From 992793c832acfd98107068d90b886643f0344d04 Mon Sep 17 00:00:00 2001 From: Martin Langhoff Date: Wed, 26 Apr 2006 12:26:16 +1200 Subject: [PATCH 1/5] git-cvsexportcommit: Add -f(orce) and -m(essage prefix) flags, small cleanups. --- Documentation/git-cvsexportcommit.txt | 9 ++++++++- git-cvsexportcommit.perl | 22 +++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt index d30435a9e4..56bd3e517d 100644 --- a/Documentation/git-cvsexportcommit.txt +++ b/Documentation/git-cvsexportcommit.txt @@ -8,7 +8,7 @@ git-cvsexportcommit - Export a commit to a CVS checkout SYNOPSIS -------- -'git-cvsexportcommmit' [-h] [-v] [-c] [-p] [PARENTCOMMIT] COMMITID +'git-cvsexportcommmit' [-h] [-v] [-c] [-p] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID DESCRIPTION @@ -39,6 +39,13 @@ OPTIONS Be pedantic (paranoid) when applying patches. Invokes patch with --fuzz=0 +-f:: + Force the merge even if the files are not up to date. + +-m:: + Prepend the commit message with the provided prefix. + Useful for patch series and the like. + -v:: Verbose. diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index 7b3a3d323b..f994443c6f 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -10,9 +10,9 @@ die "GIT_DIR is not defined or is unreadable"; } -our ($opt_h, $opt_p, $opt_v, $opt_c ); +our ($opt_h, $opt_p, $opt_v, $opt_c, $opt_f, $opt_m ); -getopts('hpvc'); +getopts('hpvcfm:'); $opt_h && usage(); @@ -77,12 +77,16 @@ $opt_v && print "Applying to CVS commit $commit from parent $parent\n"; # grab the commit message -`git-cat-file commit $commit | sed -e '1,/^\$/d' > .msg`; +open(MSG, ">.msg") or die "Cannot open .msg for writing"; +print MSG $opt_m; +close MSG; + +`git-cat-file commit $commit | sed -e '1,/^\$/d' >> .msg`; $? && die "Error extracting the commit message"; my (@afiles, @dfiles, @mfiles); my @files = safe_pipe_capture('git-diff-tree', '-r', $parent, $commit); -print @files; +#print @files; $? && die "Error in git-diff-tree"; foreach my $f (@files) { chomp $f; @@ -109,7 +113,7 @@ if (@status > 1) { warn 'Strange! cvs status returned more than one line?'}; unless ($status[0] =~ m/Status: Unknown$/) { $dirty = 1; - warn "File $f is already known in your CVS checkout!\n"; + warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n"; } } foreach my $f (@mfiles, @dfiles) { @@ -122,7 +126,11 @@ } } if ($dirty) { - die "Exiting: your CVS tree is not clean for this merge."; + if ($opt_f) { warn "The tree is not clean -- forced merge\n"; + $dirty = 0; + } else { + die "Exiting: your CVS tree is not clean for this merge."; + } } ### @@ -215,7 +223,7 @@ } sub usage { print STDERR < Date: Thu, 4 May 2006 10:51:46 +1200 Subject: [PATCH 2/5] cvsserver: use git-rev-list instead of git-log On 5/4/06, Linus Torvalds wrote: > No it wasn't. "git log --parents" was definitely supposed to still work. > > That said, I suspect a git-cvsserver kind of usage is better off using > "git-rev-list --parents HEAD" instead, which didn't break in the first > place. --- git-cvsserver.perl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 11d153c4cd..ffd9c66f94 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2076,14 +2076,15 @@ sub update # TODO: log processing is memory bound # if we can parse into a 2nd file that is in reverse order # we can probably do something really efficient - my @git_log_params = ('--parents', '--topo-order'); + my @git_log_params = ('--pretty', '--parents', '--topo-order'); if (defined $lastcommit) { push @git_log_params, "$lastcommit..$self->{module}"; } else { push @git_log_params, $self->{module}; } - open(GITLOG, '-|', 'git-log', @git_log_params) or die "Cannot call git-log: $!"; + # git-rev-list is the backend / plumbing version of git-log + open(GITLOG, '-|', 'git-rev-list', @git_log_params) or die "Cannot call git-rev-list: $!"; my @commits; From 568907f52051f340dc29a907f67e69260d7d4e7a Mon Sep 17 00:00:00 2001 From: Martyn Smith Date: Fri, 17 Mar 2006 13:33:19 +1300 Subject: [PATCH 3/5] Added logged warnings for CVS error returns --- git-cvsserver.perl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index ffd9c66f94..2e9b673372 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -950,6 +950,7 @@ sub req_ci if ( -e $state->{CVSROOT} . "/index" ) { + $log->warn("file 'index' already exists in the git repository"); print "error 1 Index already exists in git repo\n"; exit; } @@ -957,6 +958,7 @@ sub req_ci my $lockfile = "$state->{CVSROOT}/refs/heads/$state->{module}.lock"; unless ( sysopen(LOCKFILE,$lockfile,O_EXCL|O_CREAT|O_WRONLY) ) { + $log->warn("lockfile '$lockfile' already exists, please try again"); print "error 1 Lock file '$lockfile' already exists, please try again\n"; exit; } From 7d90095abe322f72820f334839afb75c23e009ff Mon Sep 17 00:00:00 2001 From: Martyn Smith Date: Mon, 27 Mar 2006 15:51:42 +1200 Subject: [PATCH 4/5] Many fixes for most operations in Eclipse. * Implemented global -n option * Implemented "Questionable" * Fixed Directory method, I _believe_ it's now correct in both cmdline and Eclipse. * Directory method Now looks for localdir of "." and compares the repo dir, uses THIS as a basis for all directory level calculations. * Added extra parameter to filenamesplit() to force stripping of "prepended" directory name. This ensures commits/updates etc work from any directory in the source tree. * Modified argsfromdir() so it is "always" called. This means that when the client specifies a directory, the method can detect this and behave accordingly (this is currently only implemented for the '.' directory) * Fixed "commit" method to correctly work from in a subdir --- git-cvsserver.perl | 211 ++++++++++++++++++++++++++++----------------- 1 file changed, 134 insertions(+), 77 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 2e9b673372..f3149bbc41 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -214,8 +214,7 @@ sub req_Globaloption { my ( $cmd, $data ) = @_; $log->debug("req_Globaloption : $data"); - - # TODO : is this data useful ??? + $state->{globaloptions}{$data} = 1; } # Valid-responses request-list \n @@ -267,11 +266,32 @@ sub req_Directory $state->{localdir} = $data; $state->{repository} = $repository; - $state->{directory} = $repository; - $state->{directory} =~ s/^$state->{CVSROOT}\///; - $state->{module} = $1 if ($state->{directory} =~ s/^(.*?)(\/|$)//); + $state->{path} = $repository; + $state->{path} =~ s/^$state->{CVSROOT}\///; + $state->{module} = $1 if ($state->{path} =~ s/^(.*?)(\/|$)//); + $state->{path} .= "/" if ( $state->{path} =~ /\S/ ); + + $state->{directory} = $state->{localdir}; + $state->{directory} = "" if ( $state->{directory} eq "." ); $state->{directory} .= "/" if ( $state->{directory} =~ /\S/ ); + if ( not defined($state->{prependdir}) and $state->{localdir} eq "." and $state->{path} =~ /\S/ ) + { + $log->info("Setting prepend to '$state->{path}'"); + $state->{prependdir} = $state->{path}; + foreach my $entry ( keys %{$state->{entries}} ) + { + $state->{entries}{$state->{prependdir} . $entry} = $state->{entries}{$entry}; + delete $state->{entries}{$entry}; + } + } + + if ( defined ( $state->{prependdir} ) ) + { + $log->debug("Prepending '$state->{prependdir}' to state|directory"); + $state->{directory} = $state->{prependdir} . $state->{directory} + } + $log->debug("req_Directory : localdir=$data repository=$repository directory=$state->{directory} module=$state->{module}"); } @@ -290,7 +310,7 @@ sub req_Entry { my ( $cmd, $data ) = @_; - $log->debug("req_Entry : $data"); + #$log->debug("req_Entry : $data"); my @data = split(/\//, $data); @@ -300,6 +320,22 @@ sub req_Entry options => $data[4], tag_or_date => $data[5], }; + + $log->info("Received entry line '$data' => '" . $state->{directory} . $data[1] . "'"); +} + +# Questionable filename \n +# Response expected: no. Additional data: no. Tell the server to check +# whether filename should be ignored, and if not, next time the server +# sends responses, send (in a M response) `?' followed by the directory and +# filename. filename must not contain `/'; it needs to be a file in the +# directory named by the most recent Directory request. +sub req_Questionable +{ + my ( $cmd, $data ) = @_; + + $log->debug("req_Questionable : $data"); + $state->{entries}{$state->{directory}.$data}{questionable} = 1; } # add \n @@ -332,8 +368,7 @@ sub req_add next; } - - my ( $filepart, $dirpart ) = filenamesplit($filename); + my ( $filepart, $dirpart ) = filenamesplit($filename, 1); print "E cvs add: scheduling file `$filename' for addition\n"; @@ -414,7 +449,7 @@ sub req_remove } - my ( $filepart, $dirpart ) = filenamesplit($filename); + my ( $filepart, $dirpart ) = filenamesplit($filename, 1); print "E cvs remove: scheduling `$filename' for removal\n"; @@ -502,22 +537,6 @@ sub req_Unchanged #$log->debug("req_Unchanged : $data"); } -# Questionable filename \n -# Response expected: no. Additional data: no. -# Tell the server to check whether filename should be ignored, -# and if not, next time the server sends responses, send (in -# a M response) `?' followed by the directory and filename. -# filename must not contain `/'; it needs to be a file in the -# directory named by the most recent Directory request. -sub req_Questionable -{ - my ( $cmd, $data ) = @_; - - $state->{entries}{$state->{directory}.$data}{questionable} = 1; - - #$log->debug("req_Questionable : $data"); -} - # Argument text \n # Response expected: no. Save argument for use in a subsequent command. # Arguments accumulate until an argument-using command is given, at which @@ -757,8 +776,7 @@ sub req_update $updater->update(); - # if no files were specified, we need to work out what files we should be providing status on ... - argsfromdir($updater) if ( scalar ( @{$state->{args}} ) == 0 ); + argsfromdir($updater); #$log->debug("update state : " . Dumper($state)); @@ -767,6 +785,8 @@ sub req_update { $filename = filecleanup($filename); + $log->debug("Processing file $filename"); + # if we have a -C we should pretend we never saw modified stuff if ( exists ( $state->{opt}{C} ) ) { @@ -821,13 +841,16 @@ sub req_update if ( $meta->{filehash} eq "deleted" ) { - my ( $filepart, $dirpart ) = filenamesplit($filename); + my ( $filepart, $dirpart ) = filenamesplit($filename,1); $log->info("Removing '$filename' from working copy (no longer in the repo)"); print "E cvs update: `$filename' is no longer in the repository\n"; - print "Removed $dirpart\n"; - print "$filepart\n"; + # Don't want to actually _DO_ the update if -n specified + unless ( $state->{globaloptions}{-n} ) { + print "Removed $dirpart\n"; + print "$filepart\n"; + } } elsif ( not defined ( $state->{entries}{$filename}{modified_hash} ) or $state->{entries}{$filename}{modified_hash} eq $oldmeta->{filehash} ) @@ -840,34 +863,42 @@ sub req_update print "MT newline\n"; print "MT -updated\n"; - my ( $filepart, $dirpart ) = filenamesplit($filename); - $dirpart =~ s/^$state->{directory}//; + my ( $filepart, $dirpart ) = filenamesplit($filename,1); - if ( defined ( $wrev ) ) - { - # instruct client we're sending a file to put in this path as a replacement - print "Update-existing $dirpart\n"; - $log->debug("Updating existing file 'Update-existing $dirpart'"); - } else { - # instruct client we're sending a file to put in this path as a new file - print "Created $dirpart\n"; - $log->debug("Creating new file 'Created $dirpart'"); - } - print $state->{CVSROOT} . "/$state->{module}/$filename\n"; + # Don't want to actually _DO_ the update if -n specified + unless ( $state->{globaloptions}{-n} ) + { + if ( defined ( $wrev ) ) + { + # instruct client we're sending a file to put in this path as a replacement + print "Update-existing $dirpart\n"; + $log->debug("Updating existing file 'Update-existing $dirpart'"); + } else { + # instruct client we're sending a file to put in this path as a new file + print "Clear-static-directory $dirpart\n"; + print $state->{CVSROOT} . "/$state->{module}/$dirpart\n"; + print "Clear-sticky $dirpart\n"; + print $state->{CVSROOT} . "/$state->{module}/$dirpart\n"; - # this is an "entries" line - $log->debug("/$filepart/1.$meta->{revision}///"); - print "/$filepart/1.$meta->{revision}///\n"; + $log->debug("Creating new file 'Created $dirpart'"); + print "Created $dirpart\n"; + } + print $state->{CVSROOT} . "/$state->{module}/$filename\n"; - # permissions - $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); - print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; + # this is an "entries" line + $log->debug("/$filepart/1.$meta->{revision}///"); + print "/$filepart/1.$meta->{revision}///\n"; - # transmit file - transmitfile($meta->{filehash}); + # permissions + $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); + print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; + + # transmit file + transmitfile($meta->{filehash}); + } } else { $log->info("Updating '$filename'"); - my ( $filepart, $dirpart ) = filenamesplit($meta->{name}); + my ( $filepart, $dirpart ) = filenamesplit($meta->{name},1); my $dir = tempdir( DIR => $TEMP_DIR, CLEANUP => 1 ) . "/"; @@ -892,19 +923,29 @@ sub req_update $log->info("Merged successfully"); print "M M $filename\n"; $log->debug("Update-existing $dirpart"); - print "Update-existing $dirpart\n"; - $log->debug($state->{CVSROOT} . "/$state->{module}/$filename"); - print $state->{CVSROOT} . "/$state->{module}/$filename\n"; - $log->debug("/$filepart/1.$meta->{revision}///"); - print "/$filepart/1.$meta->{revision}///\n"; + + # Don't want to actually _DO_ the update if -n specified + unless ( $state->{globaloptions}{-n} ) + { + print "Update-existing $dirpart\n"; + $log->debug($state->{CVSROOT} . "/$state->{module}/$filename"); + print $state->{CVSROOT} . "/$state->{module}/$filename\n"; + $log->debug("/$filepart/1.$meta->{revision}///"); + print "/$filepart/1.$meta->{revision}///\n"; + } } elsif ( $return == 1 ) { $log->info("Merged with conflicts"); print "M C $filename\n"; - print "Update-existing $dirpart\n"; - print $state->{CVSROOT} . "/$state->{module}/$filename\n"; - print "/$filepart/1.$meta->{revision}/+//\n"; + + # Don't want to actually _DO_ the update if -n specified + unless ( $state->{globaloptions}{-n} ) + { + print "Update-existing $dirpart\n"; + print $state->{CVSROOT} . "/$state->{module}/$filename\n"; + print "/$filepart/1.$meta->{revision}/+//\n"; + } } else { @@ -912,17 +953,21 @@ sub req_update next; } - # permissions - $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); - print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; + # Don't want to actually _DO_ the update if -n specified + unless ( $state->{globaloptions}{-n} ) + { + # permissions + $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); + print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; - # transmit file, format is single integer on a line by itself (file - # size) followed by the file contents - # TODO : we should copy files in blocks - my $data = `cat $file_local`; - $log->debug("File size : " . length($data)); - print length($data) . "\n"; - print $data; + # transmit file, format is single integer on a line by itself (file + # size) followed by the file contents + # TODO : we should copy files in blocks + my $data = `cat $file_local`; + $log->debug("File size : " . length($data)); + print length($data) . "\n"; + print $data; + } chdir "/"; } @@ -990,6 +1035,7 @@ sub req_ci # foreach file specified on the commandline ... foreach my $filename ( @{$state->{args}} ) { + my $committedfile = $filename; $filename = filecleanup($filename); next unless ( exists $state->{entries}{$filename}{modified_filename} or not $state->{entries}{$filename}{unchanged} ); @@ -1024,7 +1070,7 @@ sub req_ci exit; } - push @committedfiles, $filename; + push @committedfiles, $committedfile; $log->info("Committing $filename"); system("mkdir","-p",$dirpart) unless ( -d $dirpart ); @@ -1107,7 +1153,7 @@ sub req_ci my $meta = $updater->getmeta($filename); - my ( $filepart, $dirpart ) = filenamesplit($filename); + my ( $filepart, $dirpart ) = filenamesplit($filename, 1); $log->debug("Checked-in $dirpart : $filename"); @@ -1143,7 +1189,7 @@ sub req_status $updater->update(); # if no files were specified, we need to work out what files we should be providing status on ... - argsfromdir($updater) if ( scalar ( @{$state->{args}} ) == 0 ); + argsfromdir($updater); # foreach file specified on the commandline ... foreach my $filename ( @{$state->{args}} ) @@ -1244,7 +1290,7 @@ sub req_diff $updater->update(); # if no files were specified, we need to work out what files we should be providing status on ... - argsfromdir($updater) if ( scalar ( @{$state->{args}} ) == 0 ); + argsfromdir($updater); # foreach file specified on the commandline ... foreach my $filename ( @{$state->{args}} ) @@ -1386,7 +1432,7 @@ sub req_log $updater->update(); # if no files were specified, we need to work out what files we should be providing status on ... - argsfromdir($updater) if ( scalar ( @{$state->{args}} ) == 0 ); + argsfromdir($updater); # foreach file specified on the commandline ... foreach my $filename ( @{$state->{args}} ) @@ -1462,7 +1508,7 @@ sub req_annotate $updater->update(); # if no files were specified, we need to work out what files we should be providing annotate on ... - argsfromdir($updater) if ( scalar ( @{$state->{args}} ) == 0 ); + argsfromdir($updater); # we'll need a temporary checkout dir my $tmpdir = tempdir ( DIR => $TEMP_DIR ); @@ -1657,6 +1703,12 @@ sub argsfromdir { my $updater = shift; + $state->{args} = [] if ( scalar(@{$state->{args}}) == 1 and $state->{args}[0] eq "." ); + + return if ( scalar ( @{$state->{args}} ) > 0 ); + + $log->info("No args specified, populating file list automatically"); + $state->{args} = []; foreach my $file ( @{$updater->gethead} ) @@ -1738,11 +1790,17 @@ sub transmitfile sub filenamesplit { my $filename = shift; + my $fixforlocaldir = shift; my ( $filepart, $dirpart ) = ( $filename, "." ); ( $filepart, $dirpart ) = ( $2, $1 ) if ( $filename =~ /(.*)\/(.*)/ ); $dirpart .= "/"; + if ( $fixforlocaldir ) + { + $dirpart =~ s/^$state->{prependdir}//; + } + return ( $filepart, $dirpart ); } @@ -1759,7 +1817,6 @@ sub filecleanup $filename =~ s/^\.\///g; $filename = $state->{directory} . $filename; - return $filename; } From 82000d74642f1c9f55ad4b0516c59d829014839a Mon Sep 17 00:00:00 2001 From: Martyn Smith Date: Tue, 28 Mar 2006 13:24:27 +1200 Subject: [PATCH 5/5] Change to allow subdir updates from Eclipse (Now you can rightclick any directory and select team-update/team-commit) and it should work --- git-cvsserver.perl | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index f3149bbc41..5ccca4f99f 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -291,8 +291,7 @@ sub req_Directory $log->debug("Prepending '$state->{prependdir}' to state|directory"); $state->{directory} = $state->{prependdir} . $state->{directory} } - - $log->debug("req_Directory : localdir=$data repository=$repository directory=$state->{directory} module=$state->{module}"); + $log->debug("req_Directory : localdir=$data repository=$repository path=$state->{path} directory=$state->{directory} module=$state->{module}"); } # Entry entry-line \n @@ -1705,17 +1704,34 @@ sub argsfromdir $state->{args} = [] if ( scalar(@{$state->{args}}) == 1 and $state->{args}[0] eq "." ); - return if ( scalar ( @{$state->{args}} ) > 0 ); + return if ( scalar ( @{$state->{args}} ) > 1 ); - $log->info("No args specified, populating file list automatically"); - - $state->{args} = []; - - foreach my $file ( @{$updater->gethead} ) + if ( scalar(@{$state->{args}}) == 1 ) { - next if ( $file->{filehash} eq "deleted" and not defined ( $state->{entries}{$file->{name}} ) ); - next unless ( $file->{name} =~ s/^$state->{directory}// ); - push @{$state->{args}}, $file->{name}; + my $arg = $state->{args}[0]; + $arg .= $state->{prependdir} if ( defined ( $state->{prependdir} ) ); + + $log->info("Only one arg specified, checking for directory expansion on '$arg'"); + + foreach my $file ( @{$updater->gethead} ) + { + next if ( $file->{filehash} eq "deleted" and not defined ( $state->{entries}{$file->{name}} ) ); + next unless ( $file->{name} =~ /^$arg\// or $file->{name} eq $arg ); + push @{$state->{args}}, $file->{name}; + } + + shift @{$state->{args}} if ( scalar(@{$state->{args}}) > 1 ); + } else { + $log->info("Only one arg specified, populating file list automatically"); + + $state->{args} = []; + + foreach my $file ( @{$updater->gethead} ) + { + next if ( $file->{filehash} eq "deleted" and not defined ( $state->{entries}{$file->{name}} ) ); + next unless ( $file->{name} =~ s/^$state->{prependdir}// ); + push @{$state->{args}}, $file->{name}; + } } } @@ -1816,7 +1832,7 @@ sub filecleanup } $filename =~ s/^\.\///g; - $filename = $state->{directory} . $filename; + $filename = $state->{prependdir} . $filename; return $filename; }