From 38bcd31a5879847d259a75fbcab9a7977ff63f1e Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:17:26 +0100 Subject: [PATCH 01/27] cvsserver: Respond to the 'editors' and 'watchers' commands These commands list users editing and watching locked files. This trivial implementation always returns an empty response, since git-cvsserver does not implement file locking. Without this, TkCVS hangs at startup, waiting forever for a response. Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 7f632af20d..2fe0a8a3cb 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -73,8 +73,8 @@ my $methods = { 'status' => \&req_status, 'admin' => \&req_CATCHALL, 'history' => \&req_CATCHALL, - 'watchers' => \&req_CATCHALL, - 'editors' => \&req_CATCHALL, + 'watchers' => \&req_EMPTY, + 'editors' => \&req_EMPTY, 'annotate' => \&req_annotate, 'Global_option' => \&req_Globaloption, #'annotate' => \&req_CATCHALL, @@ -199,6 +199,11 @@ sub req_CATCHALL $log->warn("Unhandled command : req_$cmd : $data"); } +# This method invariably succeeds with an empty response. +sub req_EMPTY +{ + print "ok\n"; +} # Root pathname \n # Response expected: no. Tell the server which CVSROOT to use. Note that From 23b7180fdcd46556038241cd0388eca092fc55e1 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:17:42 +0100 Subject: [PATCH 02/27] cvsserver: Only print the file part of the filename in status header The "File:" header of CVS status output only includes the basename of the file, even when generating a recursive listing; do the same. Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 2fe0a8a3cb..444ec0db79 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -1471,8 +1471,10 @@ sub req_status $status ||= "Unknown"; + my ($filepart) = filenamesplit($filename); + print "M ===================================================================\n"; - print "M File: $filename\tStatus: $status\n"; + print "M File: $filepart\tStatus: $status\n"; if ( defined($state->{entries}{$filename}{revision}) ) { print "M Working revision:\t" . $state->{entries}{$filename}{revision} . "\n"; From 852b921c78ca33606600d7fd45e573a8435dbcb8 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:17:53 +0100 Subject: [PATCH 03/27] cvsserver: Do not include status output for subdirectories if -l is passed This effectively implements the -l switch by pruning the entries whose filenames contain a path separator. It was previously ignored. Without this, TkCVS includes strange "ghost" entries in its directory listings. Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 444ec0db79..89a4dac291 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -1428,6 +1428,8 @@ sub req_status { $filename = filecleanup($filename); + next if exists($state->{opt}{l}) && index($filename, '/', length($state->{prependdir})) >= 0; + my $meta = $updater->getmeta($filename); my $oldmeta = $meta; From dded801a7ba8bb91e73cfea2f37242a2aebbc5db Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:18:02 +0100 Subject: [PATCH 04/27] cvsserver: Add a few tests for 'status' command Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- t/t9400-git-cvsserver-server.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index b91b151417..616832407f 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -420,4 +420,36 @@ test_expect_success 'cvs update (merge no-op)' \ GIT_CONFIG="$git_config" cvs -Q update && diff -q merge ../merge' +#------------ +# CVS STATUS +#------------ + +cd "$WORKDIR" +test_expect_success 'cvs status' ' + mkdir status.dir && + echo Line > status.dir/status.file && + echo Line > status.file && + git add status.dir status.file && + git commit -q -m "Status test" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs update && + GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out && + test $(wc -l <../out) = 2 +' + +cd "$WORKDIR" +test_expect_success 'cvs status (nonrecursive)' ' + cd cvswork && + GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out && + test $(wc -l <../out) = 1 +' + +cd "$WORKDIR" +test_expect_success 'cvs status (no subdirs in header)' ' + cd cvswork && + GIT_CONFIG="$git_config" cvs status | grep ^File: >../out && + ! grep / <../out +' + test_done From e78f69a3f2e580e71a44b91fa99185bc6f92db29 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:18:12 +0100 Subject: [PATCH 05/27] cvsserver: Implement update -p (print to stdout) Cvs update -p -r is the documented way to retrieve a specific revision of a file (similar to git show :). Without this patch, the -p flag is ignored and status output is produced, causing clients to interpret it as the contents of the file. TkCVS uses update -p as a basis for implementing its various "View" and "Diff" commands. Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 47 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 89a4dac291..49c0ba2593 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -963,6 +963,17 @@ sub req_update $meta = $updater->getmeta($filename); } + # If -p was given, "print" the contents of the requested revision. + if ( exists ( $state->{opt}{p} ) ) { + if ( defined ( $meta->{revision} ) ) { + $log->info("Printing '$filename' revision " . $meta->{revision}); + + transmitfile($meta->{filehash}, { print => 1 }); + } + + next; + } + if ( ! defined $meta ) { $meta = { @@ -1096,9 +1107,9 @@ sub req_update my $file_local = $filepart . ".mine"; system("ln","-s",$state->{entries}{$filename}{modified_filename}, $file_local); my $file_old = $filepart . "." . $oldmeta->{revision}; - transmitfile($oldmeta->{filehash}, $file_old); + transmitfile($oldmeta->{filehash}, { targetfile => $file_old }); my $file_new = $filepart . "." . $meta->{revision}; - transmitfile($meta->{filehash}, $file_new); + transmitfile($meta->{filehash}, { targetfile => $file_new }); # we need to merge with the local changes ( M=successful merge, C=conflict merge ) $log->info("Merging $file_local, $file_old, $file_new"); @@ -1550,14 +1561,14 @@ sub req_diff print "E File $filename at revision 1.$revision1 doesn't exist\n"; next; } - transmitfile($meta1->{filehash}, $file1); + transmitfile($meta1->{filehash}, { targetfile => $file1 }); } # otherwise we just use the working copy revision else { ( undef, $file1 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 ); $meta1 = $updater->getmeta($filename, $wrev); - transmitfile($meta1->{filehash}, $file1); + transmitfile($meta1->{filehash}, { targetfile => $file1 }); } # if we have a second -r switch, use it too @@ -1572,7 +1583,7 @@ sub req_diff next; } - transmitfile($meta2->{filehash}, $file2); + transmitfile($meta2->{filehash}, { targetfile => $file2 }); } # otherwise we just use the working copy else @@ -1585,7 +1596,7 @@ sub req_diff { ( undef, $file2 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 ); $meta2 = $updater->getmeta($filename, $wrev); - transmitfile($meta2->{filehash}, $file2); + transmitfile($meta2->{filehash}, { targetfile => $file2 }); } # We need to have retrieved something useful @@ -2014,14 +2025,17 @@ sub revparse return undef; } -# This method takes a file hash and does a CVS "file transfer" which transmits the -# size of the file, and then the file contents. -# If a second argument $targetfile is given, the file is instead written out to -# a file by the name of $targetfile +# This method takes a file hash and does a CVS "file transfer". Its +# exact behaviour depends on a second, optional hash table argument: +# - If $options->{targetfile}, dump the contents to that file; +# - If $options->{print}, use M/MT to transmit the contents one line +# at a time; +# - Otherwise, transmit the size of the file, followed by the file +# contents. sub transmitfile { my $filehash = shift; - my $targetfile = shift; + my $options = shift; if ( defined ( $filehash ) and $filehash eq "deleted" ) { @@ -2043,11 +2057,20 @@ sub transmitfile if ( open my $fh, '-|', "git-cat-file", "blob", $filehash ) { - if ( defined ( $targetfile ) ) + if ( defined ( $options->{targetfile} ) ) { + my $targetfile = $options->{targetfile}; open NEWFILE, ">", $targetfile or die("Couldn't open '$targetfile' for writing : $!"); print NEWFILE $_ while ( <$fh> ); close NEWFILE or die("Failed to write '$targetfile': $!"); + } elsif ( defined ( $options->{print} ) && $options->{print} ) { + while ( <$fh> ) { + if( /\n\z/ ) { + print 'M ', $_; + } else { + print 'MT text ', $_, "\n"; + } + } } else { print "$size\n"; print while ( <$fh> ); From 6e8937a084927867df4d90c75b2619f2b4b0df18 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:18:23 +0100 Subject: [PATCH 06/27] cvsserver: Add test for update -p Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- t/t9400-git-cvsserver-server.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 616832407f..166b43f783 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -420,6 +420,24 @@ test_expect_success 'cvs update (merge no-op)' \ GIT_CONFIG="$git_config" cvs -Q update && diff -q merge ../merge' +cd "$WORKDIR" +test_expect_success 'cvs update (-p)' ' + touch really-empty && + echo Line 1 > no-lf && + echo -n Line 2 >> no-lf && + git add really-empty no-lf && + git commit -q -m "Update -p test" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs update && + rm -f failures && + for i in merge no-lf empty really-empty; do + GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out + diff $i.out ../$i >>failures 2>&1 + done && + test -z "$(cat failures)" +' + #------------ # CVS STATUS #------------ From c1bc30614ad0a9b63f4f798f0aa71d376a095938 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Thu, 27 Mar 2008 23:18:35 +0100 Subject: [PATCH 07/27] cvsserver: Use the user part of the email in log and annotate results Generate the CVS author names by taking the first eight characters of the user part of the email address. The resulting names are more likely to make sense (or at least reduce ambiguities) in "corporate" environments. Signed-off-by: Damien Diederen Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 49c0ba2593..dcca4e7173 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -1728,8 +1728,7 @@ sub req_log print "M revision 1.$revision->{revision}\n"; # reformat the date for log output $revision->{modified} = sprintf('%04d/%02d/%02d %s', $3, $DATE_LIST->{$2}, $1, $4 ) if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and defined($DATE_LIST->{$2}) ); - $revision->{author} =~ s/\s+.*//; - $revision->{author} =~ s/^(.{8}).*/$1/; + $revision->{author} = cvs_author($revision->{author}); print "M date: $revision->{modified}; author: $revision->{author}; state: " . ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) . "; lines: +2 -3\n"; my $commitmessage = $updater->commitmessage($revision->{commithash}); $commitmessage =~ s/^/M /mg; @@ -1844,8 +1843,7 @@ sub req_annotate unless ( defined ( $metadata->{$commithash} ) ) { $metadata->{$commithash} = $updater->getmeta($filename, $commithash); - $metadata->{$commithash}{author} =~ s/\s+.*//; - $metadata->{$commithash}{author} =~ s/^(.{8}).*/$1/; + $metadata->{$commithash}{author} = cvs_author($metadata->{$commithash}{author}); $metadata->{$commithash}{modified} = sprintf("%02d-%s-%02d", $1, $2, $3) if ( $metadata->{$commithash}{modified} =~ /^(\d+)\s(\w+)\s\d\d(\d\d)/ ); } printf("M 1.%-5d (%-8s %10s): %s\n", @@ -2139,6 +2137,16 @@ sub kopts_from_path } } +# Generate a CVS author name from Git author information, by taking +# the first eight characters of the user part of the email address. +sub cvs_author +{ + my $author_line = shift; + (my $author) = $author_line =~ /<([^>@]{1,8})/; + + $author; +} + package GITCVS::log; #### From 9027efed47ba930382baa8051f451235be12fa63 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 16 Mar 2008 20:00:21 +0100 Subject: [PATCH 08/27] git-cvsserver: handle change type T git-cvsserver does not support changes of type T (file type change, e.g. symlink->real file). This patch treats them the same as changes of type M. Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 7f632af20d..97fa39398c 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2633,7 +2633,7 @@ sub update }; $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms); } - elsif ( $change eq "M" ) + elsif ( $change eq "M" || $change eq "T" ) { #$log->debug("MODIFIED $name"); $head->{$name} = { From f3e5ae4f06ae968b710d286280a46b38ae3d36e8 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Fri, 28 Mar 2008 15:40:40 +0100 Subject: [PATCH 09/27] git-p4: Handle Windows EOLs properly after removal of p4 submit template handling. git-p4s handling of Windows style EOL was broken after the removal of the p4 submit template handling in commit f2a6059. Fix that, and make getP4OpenedType() more robust. Signed-off-by: Marius Storm-Olsen Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 3cb0330ec2..d8de9f6c25 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -90,11 +90,11 @@ def getP4OpenedType(file): # Returns the perforce file type for the given file. result = read_pipe("p4 opened %s" % file) - match = re.match(".*\((.+)\)$", result) + match = re.match(".*\((.+)\)\r?$", result) if match: return match.group(1) else: - die("Could not determine file type for %s" % file) + die("Could not determine file type for %s (result: '%s')" % (file, result)) def diffTreePattern(): # This is a simple generator for the diff tree regex pattern. This could be @@ -513,6 +513,8 @@ class P4Submit(Command): template = "" inFilesSection = False for line in read_pipe_lines("p4 change -o"): + if line.endswith("\r\n"): + line = line[:-2] + "\n" if inFilesSection: if line.startswith("\t"): # path starts and ends with a tab @@ -619,8 +621,6 @@ class P4Submit(Command): setP4ExecBit(f, mode) logMessage = extractLogMessageFromGitCommit(id) - if self.isWindows: - logMessage = logMessage.replace("\n", "\r\n") logMessage = logMessage.strip() template = self.prepareSubmitTemplate() @@ -631,23 +631,25 @@ class P4Submit(Command): del(os.environ["P4DIFF"]) diff = read_pipe("p4 diff -du ...") + newdiff = "" for newFile in filesToAdd: - diff += "==== new file ====\n" - diff += "--- /dev/null\n" - diff += "+++ %s\n" % newFile + newdiff += "==== new file ====\n" + newdiff += "--- /dev/null\n" + newdiff += "+++ %s\n" % newFile f = open(newFile, "r") for line in f.readlines(): - diff += "+" + line + newdiff += "+" + line f.close() - separatorLine = "######## everything below this line is just the diff #######" - if platform.system() == "Windows": - separatorLine += "\r" - separatorLine += "\n" + separatorLine = "######## everything below this line is just the diff #######\n" [handle, fileName] = tempfile.mkstemp() tmpFile = os.fdopen(handle, "w+") - tmpFile.write(submitTemplate + separatorLine + diff) + if self.isWindows: + submitTemplate = submitTemplate.replace("\n", "\r\n") + separatorLine = separatorLine.replace("\n", "\r\n") + newdiff = newdiff.replace("\n", "\r\n") + tmpFile.write(submitTemplate + separatorLine + diff + newdiff) tmpFile.close() defaultEditor = "vi" if platform.system() == "Windows": From 67dac28b904cf16e66c904eb61268b694809e4d5 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 29 Mar 2008 16:37:17 -0700 Subject: [PATCH 10/27] git-svn: remove redundant slashes from show-ignore Jonathan Scott Duff wrote: > Recently I tried "git svn showignore" on my parrot repository and it > failed. I tracked it down to the prop_walk() sub. When it recurses, > $path has an extra / on the beginning (i.e., when it recurses, it > tries to get the props for "//apps" instead of "/apps"). I *think* > this is because $path is used in the recursive call rather than $p > (which seems to contain a properly transformed $path). Anyway, I've > attached a patch that works for me and I think is generally the right > thing. Patch-submitted-by: Jonathan Scott Duff Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index 0c2b791eab..1b44cbe106 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1900,7 +1900,7 @@ sub prop_walk { foreach (sort keys %$dirent) { next if $dirent->{$_}->{kind} != $SVN::Node::dir; - $self->prop_walk($path . '/' . $_, $rev, $sub); + $self->prop_walk($p . $_, $rev, $sub); } } From c20711d29dff054735988c84ad5fe4f382d064cf Mon Sep 17 00:00:00 2001 From: Bryan Donlan Date: Fri, 28 Mar 2008 02:19:46 -0400 Subject: [PATCH 11/27] Silence cpio's "N blocks" output when cloning locally Pass --quiet to cpio in git-clone to hide the (confusing) "0 blocks" message. For compatibility with operating systems which might not support GNUisms, the presence of --quiet is probed for by grepping cpio's --help output. Signed-off-by: Bryan Donlan Signed-off-by: Junio C Hamano --- git-clone.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/git-clone.sh b/git-clone.sh index e981122778..2636159aaa 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -310,6 +310,9 @@ yes) mkdir -p "$GIT_DIR/objects/info" echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates" else + cpio_quiet_flag="" + cpio --help 2>&1 | grep -- --quiet >/dev/null && \ + cpio_quiet_flag=--quiet l= && if test "$use_local_hardlink" = yes then @@ -330,7 +333,8 @@ yes) fi fi && cd "$repo" && - find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 + find objects -depth -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \ + exit 1 fi git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 ;; From 6aeeffd14447348f3ab4a7d34927d6aff8c0a75c Mon Sep 17 00:00:00 2001 From: Josh Elsasser Date: Thu, 27 Mar 2008 14:02:14 -0700 Subject: [PATCH 12/27] Allow git-cvsserver database table name prefix to be specified. Adds a gitcvs.dbtablenameprefix config variable, the contents of which are prepended to any database tables names used by git-cvsserver. The same substutions as gitcvs.dbname and gitcvs.dbuser are supported, and any non-alphabetic characters are replaced with underscores. A typo found in contrib/completion/git-completion.bash is also fixed. Signed-off-by: Junio C Hamano --- Documentation/config.txt | 7 ++ Documentation/git-cvsserver.txt | 5 + contrib/completion/git-completion.bash | 3 +- git-cvsserver.perl | 123 +++++++++++++++++++------ 4 files changed, 107 insertions(+), 31 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 3017d640cf..04c01c5fdc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -661,6 +661,13 @@ gitcvs.dbuser, gitcvs.dbpass:: 'gitcvs.dbuser' supports variable substitution (see linkgit:git-cvsserver[1] for details). +gitcvs.dbTableNamePrefix:: + Database table name prefix. Prepended to the names of any + database tables used, allowing a single database to be used + for several repositories. Supports variable substitution (see + linkgit:git-cvsserver[1] for details). Any non-alphabetic + characters will be replaced with underscores. + All gitcvs variables except for 'gitcvs.allbinary' can also be specified as 'gitcvs..' (where 'access_method' is one of "ext" and "pserver") to make them apply only for the given diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index d3e99931d7..9cec8021b8 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -227,6 +227,11 @@ gitcvs.dbpass:: Database password. Only useful if setting `dbdriver`, since SQLite has no concept of database passwords. +gitcvs.dbTableNamePrefix:: + Database table name prefix. Supports variable substitution + (see below). Any non-alphabetic characters will be replaced + with underscores. + All variables can also be set per access method, see <>. Variable substitution diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 5046f69934..791e30f6d7 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -999,7 +999,8 @@ _git_config () gitcvs.enabled gitcvs.logfile gitcvs.allbinary - gitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dvpass + gitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dbpass + gitcvs.dbtablenameprefix gc.packrefs gc.reflogexpire gc.reflogexpireunreachable diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 7f632af20d..7a57177a81 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2311,6 +2311,14 @@ sub new bless $self, $class; + $self->{valid_tables} = {'revision' => 1, + 'revision_ix1' => 1, + 'revision_ix2' => 1, + 'head' => 1, + 'head_ix1' => 1, + 'properties' => 1, + 'commitmsgs' => 1}; + $self->{module} = $module; $self->{git_path} = $config . "/"; @@ -2326,6 +2334,8 @@ sub new $cfg->{gitcvs}{dbuser} || ""; $self->{dbpass} = $cfg->{gitcvs}{$state->{method}}{dbpass} || $cfg->{gitcvs}{dbpass} || ""; + $self->{dbtablenameprefix} = $cfg->{gitcvs}{$state->{method}}{dbtablenameprefix} || + $cfg->{gitcvs}{dbtablenameprefix} || ""; my %mapping = ( m => $module, a => $state->{method}, u => getlogin || getpwuid($<) || $<, @@ -2334,6 +2344,8 @@ sub new ); $self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg; $self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg; + $self->{dbtablenameprefix} =~ s/%([mauGg])/$mapping{$1}/eg; + $self->{dbtablenameprefix} = mangle_tablename($self->{dbtablenameprefix}); die "Invalid char ':' in dbdriver" if $self->{dbdriver} =~ /:/; die "Invalid char ';' in dbname" if $self->{dbname} =~ /;/; @@ -2349,10 +2361,13 @@ sub new } # Construct the revision table if required - unless ( $self->{tables}{revision} ) + unless ( $self->{tables}{$self->tablename("revision")} ) { + my $tablename = $self->tablename("revision"); + my $ix1name = $self->tablename("revision_ix1"); + my $ix2name = $self->tablename("revision_ix2"); $self->{dbh}->do(" - CREATE TABLE revision ( + CREATE TABLE $tablename ( name TEXT NOT NULL, revision INTEGER NOT NULL, filehash TEXT NOT NULL, @@ -2363,20 +2378,22 @@ sub new ) "); $self->{dbh}->do(" - CREATE INDEX revision_ix1 - ON revision (name,revision) + CREATE INDEX $ix1name + ON $tablename (name,revision) "); $self->{dbh}->do(" - CREATE INDEX revision_ix2 - ON revision (name,commithash) + CREATE INDEX $ix2name + ON $tablename (name,commithash) "); } # Construct the head table if required - unless ( $self->{tables}{head} ) + unless ( $self->{tables}{$self->tablename("head")} ) { + my $tablename = $self->tablename("head"); + my $ix1name = $self->tablename("head_ix1"); $self->{dbh}->do(" - CREATE TABLE head ( + CREATE TABLE $tablename ( name TEXT NOT NULL, revision INTEGER NOT NULL, filehash TEXT NOT NULL, @@ -2387,16 +2404,17 @@ sub new ) "); $self->{dbh}->do(" - CREATE INDEX head_ix1 - ON head (name) + CREATE INDEX $ix1name + ON $tablename (name) "); } # Construct the properties table if required - unless ( $self->{tables}{properties} ) + unless ( $self->{tables}{$self->tablename("properties")} ) { + my $tablename = $self->tablename("properties"); $self->{dbh}->do(" - CREATE TABLE properties ( + CREATE TABLE $tablename ( key TEXT NOT NULL PRIMARY KEY, value TEXT ) @@ -2404,10 +2422,11 @@ sub new } # Construct the commitmsgs table if required - unless ( $self->{tables}{commitmsgs} ) + unless ( $self->{tables}{$self->tablename("commitmsgs")} ) { + my $tablename = $self->tablename("commitmsgs"); $self->{dbh}->do(" - CREATE TABLE commitmsgs ( + CREATE TABLE $tablename ( key TEXT NOT NULL PRIMARY KEY, value TEXT ) @@ -2417,6 +2436,21 @@ sub new return $self; } +=head2 tablename + +=cut +sub tablename +{ + my $self = shift; + my $name = shift; + + if (exists $self->{valid_tables}{$name}) { + return $self->{dbtablenameprefix} . $name; + } else { + return undef; + } +} + =head2 update =cut @@ -2782,8 +2816,9 @@ sub insert_rev my $modified = shift; my $author = shift; my $mode = shift; + my $tablename = $self->tablename("revision"); - my $insert_rev = $self->{dbh}->prepare_cached("INSERT INTO revision (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1); + my $insert_rev = $self->{dbh}->prepare_cached("INSERT INTO $tablename (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1); $insert_rev->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode); } @@ -2792,16 +2827,18 @@ sub insert_mergelog my $self = shift; my $key = shift; my $value = shift; + my $tablename = $self->tablename("commitmsgs"); - my $insert_mergelog = $self->{dbh}->prepare_cached("INSERT INTO commitmsgs (key, value) VALUES (?,?)",{},1); + my $insert_mergelog = $self->{dbh}->prepare_cached("INSERT INTO $tablename (key, value) VALUES (?,?)",{},1); $insert_mergelog->execute($key, $value); } sub delete_head { my $self = shift; + my $tablename = $self->tablename("head"); - my $delete_head = $self->{dbh}->prepare_cached("DELETE FROM head",{},1); + my $delete_head = $self->{dbh}->prepare_cached("DELETE FROM $tablename",{},1); $delete_head->execute(); } @@ -2815,8 +2852,9 @@ sub insert_head my $modified = shift; my $author = shift; my $mode = shift; + my $tablename = $self->tablename("head"); - my $insert_head = $self->{dbh}->prepare_cached("INSERT INTO head (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1); + my $insert_head = $self->{dbh}->prepare_cached("INSERT INTO $tablename (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1); $insert_head->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode); } @@ -2824,8 +2862,9 @@ sub _headrev { my $self = shift; my $filename = shift; + my $tablename = $self->tablename("head"); - my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM head WHERE name=?",{},1); + my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM $tablename WHERE name=?",{},1); $db_query->execute($filename); my ( $hash, $revision, $mode ) = $db_query->fetchrow_array; @@ -2836,8 +2875,9 @@ sub _get_prop { my $self = shift; my $key = shift; + my $tablename = $self->tablename("properties"); - my $db_query = $self->{dbh}->prepare_cached("SELECT value FROM properties WHERE key=?",{},1); + my $db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1); $db_query->execute($key); my ( $value ) = $db_query->fetchrow_array; @@ -2849,13 +2889,14 @@ sub _set_prop my $self = shift; my $key = shift; my $value = shift; + my $tablename = $self->tablename("properties"); - my $db_query = $self->{dbh}->prepare_cached("UPDATE properties SET value=? WHERE key=?",{},1); + my $db_query = $self->{dbh}->prepare_cached("UPDATE $tablename SET value=? WHERE key=?",{},1); $db_query->execute($value, $key); unless ( $db_query->rows ) { - $db_query = $self->{dbh}->prepare_cached("INSERT INTO properties (key, value) VALUES (?,?)",{},1); + $db_query = $self->{dbh}->prepare_cached("INSERT INTO $tablename (key, value) VALUES (?,?)",{},1); $db_query->execute($key, $value); } @@ -2869,10 +2910,11 @@ sub _set_prop sub gethead { my $self = shift; + my $tablename = $self->tablename("head"); return $self->{gethead_cache} if ( defined ( $self->{gethead_cache} ) ); - my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, mode, revision, modified, commithash, author FROM head ORDER BY name ASC",{},1); + my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, mode, revision, modified, commithash, author FROM $tablename ORDER BY name ASC",{},1); $db_query->execute(); my $tree = []; @@ -2894,8 +2936,9 @@ sub getlog { my $self = shift; my $filename = shift; + my $tablename = $self->tablename("revision"); - my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM revision WHERE name=? ORDER BY revision DESC",{},1); + my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1); $db_query->execute($filename); my $tree = []; @@ -2919,19 +2962,21 @@ sub getmeta my $self = shift; my $filename = shift; my $revision = shift; + my $tablename_rev = $self->tablename("revision"); + my $tablename_head = $self->tablename("head"); my $db_query; if ( defined($revision) and $revision =~ /^\d+$/ ) { - $db_query = $self->{dbh}->prepare_cached("SELECT * FROM revision WHERE name=? AND revision=?",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1); $db_query->execute($filename, $revision); } elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ ) { - $db_query = $self->{dbh}->prepare_cached("SELECT * FROM revision WHERE name=? AND commithash=?",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",{},1); $db_query->execute($filename, $revision); } else { - $db_query = $self->{dbh}->prepare_cached("SELECT * FROM head WHERE name=?",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_head WHERE name=?",{},1); $db_query->execute($filename); } @@ -2947,11 +2992,12 @@ sub commitmessage { my $self = shift; my $commithash = shift; + my $tablename = $self->tablename("commitmsgs"); die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{40}$/ ); my $db_query; - $db_query = $self->{dbh}->prepare_cached("SELECT value FROM commitmsgs WHERE key=?",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1); $db_query->execute($commithash); my ( $message ) = $db_query->fetchrow_array; @@ -2979,9 +3025,10 @@ sub gethistory { my $self = shift; my $filename = shift; + my $tablename = $self->tablename("revision"); my $db_query; - $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM revision WHERE name=? ORDER BY revision DESC",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1); $db_query->execute($filename); return $db_query->fetchall_arrayref; @@ -3001,9 +3048,10 @@ sub gethistorydense { my $self = shift; my $filename = shift; + my $tablename = $self->tablename("revision"); my $db_query; - $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM revision WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1); + $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1); $db_query->execute($filename); return $db_query->fetchall_arrayref; @@ -3061,4 +3109,19 @@ sub mangle_dirname { return $dirname; } +=head2 mangle_tablename + +create a string from a that is suitable to use as part of an SQL table +name, mainly by converting all chars except \w to _ + +=cut +sub mangle_tablename { + my $tablename = shift; + return unless defined $tablename; + + $tablename =~ s/[^\w_]/_/g; + + return $tablename; +} + 1; From 6301f303d436f226b705380ab97c7c0122374241 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 30 Mar 2008 17:28:05 -0700 Subject: [PATCH 13/27] Add corner case tests for diff-index and diff-files diff-index and diff-files can get confused in corner cases when an indexed blob turns into something else in the work tree. This patch adds tests to expose such breakages. The test is classified under t2XXX series instead of t4XXX series, because the ultimate objective is to fix "add -u" (and "commit -a" that shares the same issue). Signed-off-by: Junio C Hamano --- t/t2201-add-update-typechange.sh | 140 +++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 t/t2201-add-update-typechange.sh diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh new file mode 100755 index 0000000000..75c440c74b --- /dev/null +++ b/t/t2201-add-update-typechange.sh @@ -0,0 +1,140 @@ +#!/bin/sh + +test_description='more git add -u' + +. ./test-lib.sh + +_z40=0000000000000000000000000000000000000000 + +test_expect_success setup ' + >xyzzy && + _empty=$(git hash-object --stdin yomin && + >caskly && + ln -s frotz nitfol && + mkdir rezrov && + >rezrov/bozbar && + git add caskly xyzzy yomin nitfol rezrov/bozbar && + + test_tick && + git commit -m initial + +' + +test_expect_success modify ' + rm -f xyzzy yomin nitfol caskly && + # caskly disappears (not a submodule) + mkdir caskly && + # nitfol changes from symlink to regular + >nitfol && + # rezrov/bozbar disappears + rm -fr rezrov && + ln -s xyzzy rezrov && + # xyzzy disappears (not a submodule) + mkdir xyzzy && + echo gnusto >xyzzy/bozbar && + # yomin gets replaced with a submodule + mkdir yomin && + >yomin/yomin && + ( + cd yomin && + git init && + git add yomin && + git commit -m "sub initial" + ) && + yomin=$(GIT_DIR=yomin/.git git rev-parse HEAD) && + # yonk is added and then turned into a submodule + # this should appear as T in diff-files and as A in diff-index + >yonk && + git add yonk && + rm -f yonk && + mkdir yonk && + >yonk/yonk && + ( + cd yonk && + git init && + git add yonk && + git commit -m "sub initial" + ) && + yonk=$(GIT_DIR=yonk/.git git rev-parse HEAD) && + # zifmia is added and then removed + # this should appear in diff-files but not in diff-index. + >zifmia && + git add zifmia && + rm -f zifmia && + mkdir zifmia && + { + git ls-tree -r HEAD | + sed -e "s/^/:/" -e " + / caskly/{ + s/ caskly/ $_z40 D&/ + s/blob/000000/ + } + / nitfol/{ + s/ nitfol/ $_z40 T&/ + s/blob/100644/ + } + / rezrov.bozbar/{ + s/ rezrov.bozbar/ $_z40 D&/ + s/blob/000000/ + } + / xyzzy/{ + s/ xyzzy/ $_z40 D&/ + s/blob/000000/ + } + / yomin/{ + s/ yomin/ $_z40 T&/ + s/blob/160000/ + } + " + } >expect && + { + cat expect + echo ":100644 160000 $_empty $_z40 T yonk" + echo ":100644 000000 $_empty $_z40 D zifmia" + } >expect-files && + { + cat expect + echo ":000000 160000 $_z40 $_z40 A yonk" + } >expect-index && + { + echo "100644 $_empty 0 nitfol" + echo "160000 $yomin 0 yomin" + echo "160000 $yonk 0 yonk" + } >expect-final +' + +test_expect_failure diff-files ' + git diff-files --raw >actual && + diff -u expect-files actual +' + +test_expect_failure diff-index ' + git diff-index --raw HEAD -- >actual && + diff -u expect-index actual +' + +test_expect_failure 'add -u' ' + rm -f ".git/saved-index" && + cp -p ".git/index" ".git/saved-index" && + git add -u && + git ls-files -s >actual && + diff -u expect-final actual +' + +test_expect_failure 'commit -a' ' + if test -f ".git/saved-index" + then + rm -f ".git/index" && + mv ".git/saved-index" ".git/index" + fi && + git commit -m "second" -a && + git ls-files -s >actual && + diff -u expect-final actual && + rm -f .git/index && + git read-tree HEAD && + git ls-files -s >actual && + diff -u expect-final actual +' + +test_done From 948dd346fd6748f8c2c0ae488759cbbd05a09320 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 30 Mar 2008 17:29:48 -0700 Subject: [PATCH 14/27] diff-index: careful when inspecting work tree items Earlier, if you changed a staged path into a directory in the work tree, we happily ran lstat(2) on it and found that it exists, and declared that the user changed it to a gitlink. This is wrong for two reasons: (1) It may be a directory, but it may not be a submodule, and in the latter case, the change we need to report is "the blob at the path has disappeared". We need to check with resolve_gitlink_ref() to be consistent with what "git add" and "git update-index --add" does. (2) lstat(2) may have succeeded only because a leading component of the path was turned into a symbolic link that points at something that exists in the work tree. In such a case, the path itself does not exist anymore, as far as the index is concerned. This fixes these breakages in diff-index that the previous patch has exposed. Signed-off-by: Junio C Hamano --- diff-lib.c | 69 +++++++++++++++++++++++++------- t/t2201-add-update-typechange.sh | 2 +- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/diff-lib.c b/diff-lib.c index 52dbac34a4..ad9ed13fc9 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -10,6 +10,7 @@ #include "cache-tree.h" #include "path-list.h" #include "unpack-trees.h" +#include "refs.h" /* * diff-files @@ -333,6 +334,26 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv) } return run_diff_files(revs, options); } +/* + * See if work tree has an entity that can be staged. Return 0 if so, + * return 1 if not and return -1 if error. + */ +static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache) +{ + if (lstat(ce->name, st) < 0) { + if (errno != ENOENT && errno != ENOTDIR) + return -1; + return 1; + } + if (has_symlink_leading_path(ce->name, symcache)) + return 1; + if (S_ISDIR(st->st_mode)) { + unsigned char sub[20]; + if (resolve_gitlink_ref(ce->name, "HEAD", sub)) + return 1; + } + return 0; +} int run_diff_files(struct rev_info *revs, unsigned int option) { @@ -468,6 +489,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option) * diff-index */ +struct oneway_unpack_data { + struct rev_info *revs; + char symcache[PATH_MAX]; +}; + /* A file entry went away or appeared */ static void diff_index_show_file(struct rev_info *revs, const char *prefix, @@ -481,7 +507,8 @@ static void diff_index_show_file(struct rev_info *revs, static int get_stat_data(struct cache_entry *ce, const unsigned char **sha1p, unsigned int *modep, - int cached, int match_missing) + int cached, int match_missing, + struct oneway_unpack_data *cbdata) { const unsigned char *sha1 = ce->sha1; unsigned int mode = ce->ce_mode; @@ -489,8 +516,11 @@ static int get_stat_data(struct cache_entry *ce, if (!cached) { int changed; struct stat st; - if (lstat(ce->name, &st) < 0) { - if (errno == ENOENT && match_missing) { + changed = check_work_tree_entity(ce, &st, cbdata->symcache); + if (changed < 0) + return -1; + else if (changed) { + if (match_missing) { *sha1p = sha1; *modep = mode; return 0; @@ -509,23 +539,25 @@ static int get_stat_data(struct cache_entry *ce, return 0; } -static void show_new_file(struct rev_info *revs, +static void show_new_file(struct oneway_unpack_data *cbdata, struct cache_entry *new, int cached, int match_missing) { const unsigned char *sha1; unsigned int mode; + struct rev_info *revs = cbdata->revs; - /* New file in the index: it might actually be different in + /* + * New file in the index: it might actually be different in * the working copy. */ - if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) + if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0) return; diff_index_show_file(revs, "+", new, sha1, mode); } -static int show_modified(struct rev_info *revs, +static int show_modified(struct oneway_unpack_data *cbdata, struct cache_entry *old, struct cache_entry *new, int report_missing, @@ -533,8 +565,9 @@ static int show_modified(struct rev_info *revs, { unsigned int mode, oldmode; const unsigned char *sha1; + struct rev_info *revs = cbdata->revs; - if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) { + if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0) { if (report_missing) diff_index_show_file(revs, "-", old, old->sha1, old->ce_mode); @@ -602,7 +635,8 @@ static void do_oneway_diff(struct unpack_trees_options *o, struct cache_entry *idx, struct cache_entry *tree) { - struct rev_info *revs = o->unpack_data; + struct oneway_unpack_data *cbdata = o->unpack_data; + struct rev_info *revs = cbdata->revs; int match_missing, cached; /* @@ -625,7 +659,7 @@ static void do_oneway_diff(struct unpack_trees_options *o, * Something added to the tree? */ if (!tree) { - show_new_file(revs, idx, cached, match_missing); + show_new_file(cbdata, idx, cached, match_missing); return; } @@ -638,7 +672,7 @@ static void do_oneway_diff(struct unpack_trees_options *o, } /* Show difference between old and new */ - show_modified(revs, tree, idx, 1, cached, match_missing); + show_modified(cbdata, tree, idx, 1, cached, match_missing); } static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o) @@ -675,7 +709,8 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) { struct cache_entry *idx = src[0]; struct cache_entry *tree = src[1]; - struct rev_info *revs = o->unpack_data; + struct oneway_unpack_data *cbdata = o->unpack_data; + struct rev_info *revs = cbdata->revs; if (idx && ce_stage(idx)) skip_same_name(idx, o); @@ -702,6 +737,7 @@ int run_diff_index(struct rev_info *revs, int cached) const char *tree_name; struct unpack_trees_options opts; struct tree_desc t; + struct oneway_unpack_data unpack_cb; mark_merge_entries(); @@ -711,12 +747,14 @@ int run_diff_index(struct rev_info *revs, int cached) if (!tree) return error("bad tree object %s", tree_name); + unpack_cb.revs = revs; + unpack_cb.symcache[0] = '\0'; memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; opts.index_only = cached; opts.merge = 1; opts.fn = oneway_diff; - opts.unpack_data = revs; + opts.unpack_data = &unpack_cb; opts.src_index = &the_index; opts.dst_index = NULL; @@ -738,6 +776,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) struct cache_entry *last = NULL; struct unpack_trees_options opts; struct tree_desc t; + struct oneway_unpack_data unpack_cb; /* * This is used by git-blame to run diff-cache internally; @@ -766,12 +805,14 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); + unpack_cb.revs = &revs; + unpack_cb.symcache[0] = '\0'; memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; opts.index_only = 1; opts.merge = 1; opts.fn = oneway_diff; - opts.unpack_data = &revs; + opts.unpack_data = &unpack_cb; opts.src_index = &the_index; opts.dst_index = &the_index; diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index 75c440c74b..469a8e0739 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -109,7 +109,7 @@ test_expect_failure diff-files ' diff -u expect-files actual ' -test_expect_failure diff-index ' +test_expect_success diff-index ' git diff-index --raw HEAD -- >actual && diff -u expect-index actual ' From f58dbf23c33e0e79622f4344b48ab5bc9bc360cc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 30 Mar 2008 17:30:08 -0700 Subject: [PATCH 15/27] diff-files: careful when inspecting work tree items This fixes the same breakage in diff-files. Signed-off-by: Junio C Hamano --- diff-lib.c | 17 +++++++++++------ t/t2201-add-update-typechange.sh | 6 +++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/diff-lib.c b/diff-lib.c index ad9ed13fc9..069e4507ae 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -362,10 +362,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option) int silent_on_removed = option & DIFF_SILENT_ON_REMOVED; unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) ? CE_MATCH_RACY_IS_DIRTY : 0); + char symcache[PATH_MAX]; if (diff_unmerged_stage < 0) diff_unmerged_stage = 2; entries = active_nr; + symcache[0] = '\0'; for (i = 0; i < entries; i++) { struct stat st; unsigned int oldmode, newmode; @@ -397,16 +399,17 @@ int run_diff_files(struct rev_info *revs, unsigned int option) memset(&(dpath->parent[0]), 0, sizeof(struct combine_diff_parent)*5); - if (lstat(ce->name, &st) < 0) { - if (errno != ENOENT && errno != ENOTDIR) { + changed = check_work_tree_entity(ce, &st, symcache); + if (!changed) + dpath->mode = ce_mode_from_stat(ce, st.st_mode); + else { + if (changed < 0) { perror(ce->name); continue; } if (silent_on_removed) continue; } - else - dpath->mode = ce_mode_from_stat(ce, st.st_mode); while (i < entries) { struct cache_entry *nce = active_cache[i]; @@ -459,8 +462,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (ce_uptodate(ce)) continue; - if (lstat(ce->name, &st) < 0) { - if (errno != ENOENT && errno != ENOTDIR) { + + changed = check_work_tree_entity(ce, &st, symcache); + if (changed) { + if (changed < 0) { perror(ce->name); continue; } diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index 469a8e0739..e15e3eb81b 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -104,7 +104,7 @@ test_expect_success modify ' } >expect-final ' -test_expect_failure diff-files ' +test_expect_success diff-files ' git diff-files --raw >actual && diff -u expect-files actual ' @@ -114,7 +114,7 @@ test_expect_success diff-index ' diff -u expect-index actual ' -test_expect_failure 'add -u' ' +test_expect_success 'add -u' ' rm -f ".git/saved-index" && cp -p ".git/index" ".git/saved-index" && git add -u && @@ -122,7 +122,7 @@ test_expect_failure 'add -u' ' diff -u expect-final actual ' -test_expect_failure 'commit -a' ' +test_expect_success 'commit -a' ' if test -f ".git/saved-index" then rm -f ".git/index" && From e0aaf781f656671694a0aa04d8a665bd4d7956e6 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 27 Mar 2008 11:16:04 -0500 Subject: [PATCH 16/27] mktag.c: improve verification of tagger field and tests Since nearly its birth, git's tags have included a "tagger" field which describes the name of tagger, email of tagger, and date and time of tagging. But, this field was only loosely tested by git-mktag. Provide some thorough testing for this field and also ensure that the tag header is separated from the tag body by an empty line to reduce the convenience of creating a flawed tag. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- mktag.c | 61 ++++++++++++++++++---- t/t3800-mktag.sh | 129 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 176 insertions(+), 14 deletions(-) diff --git a/mktag.c b/mktag.c index b05260c83f..8887080a66 100644 --- a/mktag.c +++ b/mktag.c @@ -8,10 +8,11 @@ * message and a signature block that git itself doesn't care about, * but that can be verified with gpg or similar. * - * The first three lines are guaranteed to be at least 63 bytes: + * The first four lines are guaranteed to be at least 83 bytes: * "object \n" is 48 bytes, "type tag\n" at 9 bytes is the - * shortest possible type-line, and "tag .\n" at 6 bytes is the - * shortest single-character-tag line. + * shortest possible type-line, "tag .\n" at 6 bytes is the shortest + * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is + * the shortest possible tagger-line. */ /* @@ -43,9 +44,9 @@ static int verify_tag(char *buffer, unsigned long size) int typelen; char type[20]; unsigned char sha1[20]; - const char *object, *type_line, *tag_line, *tagger_line; + const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb; - if (size < 64) + if (size < 84) return error("wanna fool me ? you obviously got the size wrong !"); buffer[size] = 0; @@ -97,11 +98,53 @@ static int verify_tag(char *buffer, unsigned long size) /* Verify the tagger line */ tagger_line = tag_line; - if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n')) - return error("char" PD_FMT ": could not find \"tagger\"", tagger_line - buffer); + if (memcmp(tagger_line, "tagger ", 7) || (tagger_line[7] == '\n')) + return error("char" PD_FMT ": could not find \"tagger \"", + tagger_line - buffer); - /* TODO: check for committer info + blank line? */ - /* Also, the minimum length is probably + "tagger .", or 63+8=71 */ + /* + * Check for correct form for name and email + * i.e. " <" followed by "> " on _this_ line + */ + tagger_line += 7; + if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) || + strchr(tagger_line, '\n') < rb) + return error("char" PD_FMT ": malformed tagger", + tagger_line - buffer); + + /* Check for author name, at least one character, space is acceptable */ + if (lb == tagger_line) + return error("char" PD_FMT ": missing tagger name", + tagger_line - buffer); + + /* timestamp */ + tagger_line = rb + 2; + if (*tagger_line == ' ') + return error("char" PD_FMT ": malformed tag timestamp", + tagger_line - buffer); + for (;;) { + unsigned char c = *tagger_line++; + if (c == ' ') + break; + if (isdigit(c)) + continue; + return error("char" PD_FMT ": malformed tag timestamp", + tagger_line - buffer); + } + + /* timezone, 5 digits [+-]hhmm, max. 1400 */ + if (!((tagger_line[0] == '+' || tagger_line[0] == '-') && + isdigit(tagger_line[1]) && isdigit(tagger_line[2]) && + isdigit(tagger_line[3]) && isdigit(tagger_line[4]) && + tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400)) + return error("char" PD_FMT ": malformed tag timezone", + tagger_line - buffer); + tagger_line += 6; + + /* Verify the blank line separating the header from the body */ + if (*tagger_line != '\n') + return error("char" PD_FMT ": trailing garbage in tag header", + tagger_line - buffer); /* The actual stuff afterwards we don't care about.. */ return 0; diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index bdc6e132ca..8a27400754 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -44,6 +44,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure '"object" line label check' '^error: char0: .*"object "$' @@ -55,6 +57,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure '"object" line SHA1 check' '^error: char7: .*SHA1 hash$' @@ -66,6 +70,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure '"type" line label check' '^error: char47: .*"\\ntype "$' @@ -85,6 +91,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure '"tag" line label check #1' \ @@ -121,6 +129,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure 'verify object (SHA1/type) check' \ @@ -133,6 +143,8 @@ cat >tag.sig < 0 +0000 + EOF check_verify_failure 'verify tag-name check' \ @@ -145,10 +157,12 @@ cat >tag.sig <tag.sig < 0 +0000 + +This is filler +EOF + +check_verify_failure 'detect missing tag author name' \ + '^error: char77: missing tagger name$' + +############################################################ +# 14. detect missing tag author name + +cat >tag.sig < 0 +0000 + +EOF + +check_verify_failure 'detect malformed tagger' \ + '^error: char77: malformed tagger$' + +############################################################ +# 15. allow empty tag email + +cat >tag.sig < 0 +0000 + +EOF + +test_expect_success \ + 'allow empty tag email' \ + 'git-mktag .git/refs/tags/mytag 2>message' + +############################################################ +# 16. detect missing tag timestamp + +cat >tag.sig < + +EOF + +check_verify_failure 'detect missing tag timestamp' \ + '^error: char107: malformed tag timestamp$' + +############################################################ +# 17. detect invalid tag timestamp + +cat >tag.sig < Tue Mar 25 15:47:44 2008 + +EOF + +check_verify_failure 'detect invalid tag timestamp' \ + '^error: char108: malformed tag timestamp$' + +############################################################ +# 18. detect invalid tag timezone + +cat >tag.sig < 1206478233 GMT + +EOF + +check_verify_failure 'detect invalid tag timezone' \ + '^error: char118: malformed tag timezone$' + +############################################################ +# 19. detect invalid header entry + +cat >tag.sig < 1206478233 -0500 +this line should not be here + +EOF + +check_verify_failure 'detect invalid header entry' \ + '^error: char124: trailing garbage in tag header$' + +############################################################ +# 20. create valid tag + +cat >tag.sig < 1206478233 -0500 + EOF test_expect_success \ @@ -178,7 +297,7 @@ test_expect_success \ 'git-mktag .git/refs/tags/mytag 2>message' ############################################################ -# 14. check mytag +# 21. check mytag test_expect_success \ 'check mytag' \ From 90356287e65181caeaa821d7476b8865d26bc588 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 31 Mar 2008 09:14:14 +0200 Subject: [PATCH 17/27] filter-branch: Test renaming directories in a tree-filter This test currently fails. If b is a directory then 'mv a b' is not a plain "rename", but really a "move", so we must also test that the directory does not exist with the old name in the directory with the new name. There's also some cleanup in the corresponding "rename file" test to avoid spurious shell syntax errors and "ambigous ref" error from 'git show' (but these should show up only if the test would fail anyway). Plus we also test for the non-existence of the old file. Signed-off-by: Johannes Sixt --- t/t7003-filter-branch.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 6827249da5..53b5ce605e 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -17,6 +17,8 @@ test_expect_success 'setup' ' make_commit B git checkout -b branch B make_commit D + mkdir dir + make_commit dir/D make_commit E git checkout master make_commit C @@ -41,9 +43,23 @@ test_expect_success 'rewrite, renaming a specific file' ' ' test_expect_success 'test that the file was renamed' ' - test d = $(git show HEAD:doh) && + test d = "$(git show HEAD:doh --)" && + ! test -f d && test -f doh && - test d = $(cat doh) + test d = "$(cat doh)" +' + +test_expect_success 'rewrite, renaming a specific directory' ' + git-filter-branch -f --tree-filter "mv dir diroh || :" HEAD +' + +test_expect_failure 'test that the directory was renamed' ' + test dir/d = "$(git show HEAD:diroh/d --)" && + ! test -d dir && + test -d diroh && + ! test -d diroh/dir && + test -f diroh/d && + test dir/d = "$(cat diroh/d)" ' git tag oldD HEAD~4 From 6a589fda2e4759e21d66eb2e6814e32baa14beca Mon Sep 17 00:00:00 2001 From: "veillette@yahoo.ca" Date: Mon, 31 Mar 2008 09:14:15 +0200 Subject: [PATCH 18/27] filter-branch: Fix renaming a directory in the tree-filter Commit d89c1df (filter-branch: don't use xargs -0, 2008-03-12) replaced a 'ls-files | xargs rm' pipeline by 'git clean'. 'git clean' however does not recurse and remove directories by default. Now, consider a tree-filter that renames a directory. 1. For the first commit everything works as expected 2. Then filter-branch checks out the files for the next commit. This leaves the new directory behind because there is no real "branch switching" involved that would notice that the directory can be removed. 3. Then filter-branch invokes 'git clean' to remove exactly those left-overs. But here it does not remove the directory. 4. The next tree-filter does not work as expected because there already exists a directory with the new name. Just add -d to 'git clean', so that empty directories are removed. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- git-filter-branch.sh | 2 +- t/t7003-filter-branch.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 22b6ed4a78..ea59015baa 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -281,7 +281,7 @@ while read commit parents; do die "Could not checkout the index" # files that $commit removed are now still in the working tree; # remove them, else they would be added again - git clean -q -f -x + git clean -d -q -f -x eval "$filter_tree" < /dev/null || die "tree filter failed: $filter_tree" diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 53b5ce605e..efd658adb6 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -53,7 +53,7 @@ test_expect_success 'rewrite, renaming a specific directory' ' git-filter-branch -f --tree-filter "mv dir diroh || :" HEAD ' -test_expect_failure 'test that the directory was renamed' ' +test_expect_success 'test that the directory was renamed' ' test dir/d = "$(git show HEAD:diroh/d --)" && ! test -d dir && test -d diroh && From ba26ab99d4c6c6a8f939f44cf2f2c47f6fd4f0a1 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Mon, 31 Mar 2008 18:25:23 -0500 Subject: [PATCH 19/27] mktag.c: tweak validation of tagger field and adjust test script Update the verify_tag() function to remove an unnecessary test, and add additional check for angle brackets in the name and email field, and spaces in the email field. The timestamp and timezone sections are made more straight forward by using strspn(). Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- mktag.c | 31 +++++++++-------- t/t3800-mktag.sh | 88 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 32 deletions(-) diff --git a/mktag.c b/mktag.c index 8887080a66..0b34341f71 100644 --- a/mktag.c +++ b/mktag.c @@ -45,6 +45,7 @@ static int verify_tag(char *buffer, unsigned long size) char type[20]; unsigned char sha1[20]; const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb; + size_t len; if (size < 84) return error("wanna fool me ? you obviously got the size wrong !"); @@ -98,18 +99,21 @@ static int verify_tag(char *buffer, unsigned long size) /* Verify the tagger line */ tagger_line = tag_line; - if (memcmp(tagger_line, "tagger ", 7) || (tagger_line[7] == '\n')) + if (memcmp(tagger_line, "tagger ", 7)) return error("char" PD_FMT ": could not find \"tagger \"", tagger_line - buffer); /* * Check for correct form for name and email * i.e. " <" followed by "> " on _this_ line + * No angle brackets within the name or email address fields. + * No spaces within the email address field. */ tagger_line += 7; if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) || - strchr(tagger_line, '\n') < rb) - return error("char" PD_FMT ": malformed tagger", + strpbrk(tagger_line, "<>\n") != lb+1 || + strpbrk(lb+2, "><\n ") != rb) + return error("char" PD_FMT ": malformed tagger field", tagger_line - buffer); /* Check for author name, at least one character, space is acceptable */ @@ -117,25 +121,20 @@ static int verify_tag(char *buffer, unsigned long size) return error("char" PD_FMT ": missing tagger name", tagger_line - buffer); - /* timestamp */ + /* timestamp, 1 or more digits followed by space */ tagger_line = rb + 2; - if (*tagger_line == ' ') + if (!(len = strspn(tagger_line, "0123456789"))) + return error("char" PD_FMT ": missing tag timestamp", + tagger_line - buffer); + tagger_line += len; + if (*tagger_line != ' ') return error("char" PD_FMT ": malformed tag timestamp", tagger_line - buffer); - for (;;) { - unsigned char c = *tagger_line++; - if (c == ' ') - break; - if (isdigit(c)) - continue; - return error("char" PD_FMT ": malformed tag timestamp", - tagger_line - buffer); - } + tagger_line++; /* timezone, 5 digits [+-]hhmm, max. 1400 */ if (!((tagger_line[0] == '+' || tagger_line[0] == '-') && - isdigit(tagger_line[1]) && isdigit(tagger_line[2]) && - isdigit(tagger_line[3]) && isdigit(tagger_line[4]) && + strspn(tagger_line+1, "0123456789") == 4 && tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400)) return error("char" PD_FMT ": malformed tag timezone", tagger_line - buffer); diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index 8a27400754..df1fd6f86f 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -180,7 +180,7 @@ check_verify_failure '"tagger" line label check #2' \ '^error: char70: could not find "tagger "$' ############################################################ -# 13. detect missing tag author name +# 13. disallow missing tag author name cat >tag.sig < 0 +0000 This is filler EOF -check_verify_failure 'detect missing tag author name' \ +check_verify_failure 'disallow missing tag author name' \ '^error: char77: missing tagger name$' ############################################################ -# 14. detect missing tag author name +# 14. disallow missing tag author name cat >tag.sig <.git/refs/tags/mytag 2>message' ############################################################ -# 16. detect missing tag timestamp +# 16. disallow spaces in tag email + +cat >tag.sig < 0 +0000 + +EOF + +check_verify_failure 'disallow spaces in tag email' \ + '^error: char77: malformed tagger field$' + +############################################################ +# 17. disallow missing tag timestamp cat >tag.sig < EOF -check_verify_failure 'detect missing tag timestamp' \ - '^error: char107: malformed tag timestamp$' +check_verify_failure 'disallow missing tag timestamp' \ + '^error: char107: missing tag timestamp$' ############################################################ -# 17. detect invalid tag timestamp +# 18. detect invalid tag timestamp1 cat >tag.sig < Tue Mar 25 15:47:44 2008 EOF -check_verify_failure 'detect invalid tag timestamp' \ - '^error: char108: malformed tag timestamp$' +check_verify_failure 'detect invalid tag timestamp1' \ + '^error: char107: missing tag timestamp$' ############################################################ -# 18. detect invalid tag timezone +# 19. detect invalid tag timestamp2 + +cat >tag.sig < 2008-03-31T12:20:15-0500 + +EOF + +check_verify_failure 'detect invalid tag timestamp2' \ + '^error: char111: malformed tag timestamp$' + +############################################################ +# 20. detect invalid tag timezone1 cat >tag.sig < 1206478233 GMT EOF -check_verify_failure 'detect invalid tag timezone' \ +check_verify_failure 'detect invalid tag timezone1' \ '^error: char118: malformed tag timezone$' ############################################################ -# 19. detect invalid header entry +# 21. detect invalid tag timezone2 + +cat >tag.sig < 1206478233 + 30 + +EOF + +check_verify_failure 'detect invalid tag timezone2' \ + '^error: char118: malformed tag timezone$' + +############################################################ +# 22. detect invalid tag timezone3 + +cat >tag.sig < 1206478233 -1430 + +EOF + +check_verify_failure 'detect invalid tag timezone3' \ + '^error: char118: malformed tag timezone$' + +############################################################ +# 23. detect invalid header entry cat >tag.sig <tag.sig <.git/refs/tags/mytag 2>message' ############################################################ -# 21. check mytag +# 25. check mytag test_expect_success \ 'check mytag' \ From c91ee2bd61299737c2795bd7b798e17ef0714e47 Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Tue, 1 Apr 2008 11:54:03 +0100 Subject: [PATCH 20/27] git-gui: Add shortcut keys for Show More/Less Context Bound to Ctrl/Cmd + left & right square brackets, depending on your platform. [sp: Added missing binds for . to allow shortcuts to work when not focused in the commit message area.] Signed-off-by: Jonathan del Strother Signed-off-by: Shawn O. Pearce --- git-gui.sh | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 5e97fbf03e..8225cec505 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1846,6 +1846,22 @@ proc add_range_to_selection {w x y} { $w tag add in_sel $begin.0 [expr {$end + 1}].0 } +proc show_more_context {} { + global repo_config + if {$repo_config(gui.diffcontext) < 99} { + incr repo_config(gui.diffcontext) + reshow_diff + } +} + +proc show_less_context {} { + global repo_config + if {$repo_config(gui.diffcontext) >= 1} { + incr repo_config(gui.diffcontext) -1 + reshow_diff + } +} + ###################################################################### ## ## ui construction @@ -2046,6 +2062,16 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar.commit add separator + .mbar.commit add command -label [mc "Show Less Context"] \ + -command show_less_context \ + -accelerator $M1T-\[ + + .mbar.commit add command -label [mc "Show More Context"] \ + -command show_more_context \ + -accelerator $M1T-\] + + .mbar.commit add separator + .mbar.commit add command -label [mc "Sign Off"] \ -command do_signoff \ -accelerator $M1T-S @@ -2593,17 +2619,11 @@ lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state] $ctxm add separator $ctxm add command \ -label [mc "Show Less Context"] \ - -command {if {$repo_config(gui.diffcontext) >= 1} { - incr repo_config(gui.diffcontext) -1 - reshow_diff - }} + -command show_less_context lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add command \ -label [mc "Show More Context"] \ - -command {if {$repo_config(gui.diffcontext) < 99} { - incr repo_config(gui.diffcontext) - reshow_diff - }} + -command show_more_context lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add separator $ctxm add command \ @@ -2695,6 +2715,8 @@ bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break} bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break} bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break} bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-\[> {show_less_context;break} +bind $ui_comm <$M1B-Key-\]> {show_more_context;break} bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break} bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break} @@ -2738,6 +2760,8 @@ bind . <$M1B-Key-t> do_add_selection bind . <$M1B-Key-T> do_add_selection bind . <$M1B-Key-i> do_add_all bind . <$M1B-Key-I> do_add_all +bind . <$M1B-Key-\[> {show_less_context;break} +bind . <$M1B-Key-\]> {show_more_context;break} bind . <$M1B-Key-Return> do_commit foreach i [list $ui_index $ui_workdir] { bind $i "toggle_or_diff $i %x %y; break" From 3d654be48f65545c4d3e35f5d3bbed5489820930 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 2 Apr 2008 02:17:11 -0400 Subject: [PATCH 21/27] git-gui 0.10 Signed-off-by: Shawn O. Pearce --- GIT-VERSION-GEN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index cfe46a857e..0ab478ef90 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=0.9.GITGUI +DEF_VER=0.10.GITGUI LF=' ' From e85dc0a3c7a3f4f8d5aade83fd340b8df73471cd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 31 Mar 2008 21:33:09 -0700 Subject: [PATCH 22/27] Accept git aliases outside a git repository af05d67 (Always set *nongit_ok in setup_git_directory_gently(), 2008-03-25) had a change from the patch originally submitted that resulted in disabling aliases outside a git repository. It turns out that some people used "alias.fubar = diff --color-words" in $HOME/.gitconfig to use non-index diff (or any command that do not need git repository) outside git repositories, and this change broke them, so this resurrects the support for such usage. Signed-off-by: Junio C Hamano --- git.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git.c b/git.c index b7729d72cf..c4e4644b30 100644 --- a/git.c +++ b/git.c @@ -148,8 +148,9 @@ static int handle_alias(int *argcp, const char ***argv) const char** new_argv; const char *alias_command; char *alias_string; + int unused_nongit; - subdir = setup_git_directory_gently(NULL); + subdir = setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); From 4637e47accc43479bd779a354e839f898ecd1b84 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Wed, 2 Apr 2008 05:47:41 +0200 Subject: [PATCH 23/27] help: Add a missing OPT_END(). Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- help.c | 1 + 1 file changed, 1 insertion(+) diff --git a/help.c b/help.c index ecaca770d3..10298fb0a1 100644 --- a/help.c +++ b/help.c @@ -30,6 +30,7 @@ static struct option builtin_help_options[] = { HELP_FORMAT_WEB), OPT_SET_INT('i', "info", &help_format, "show info page", HELP_FORMAT_INFO), + OPT_END(), }; static const char * const builtin_help_usage[] = { From 69fe5ef6c7211921a2a7840698bf58a80bab9412 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Apr 2008 08:49:59 +0200 Subject: [PATCH 24/27] verify-tag: Clean up the temporary file if gpg cannot be started. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- builtin-verify-tag.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index f3ef11fa2d..db81496b46 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -46,8 +46,10 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose) gpg.argv = args_gpg; gpg.in = -1; args_gpg[2] = path; - if (start_command(&gpg)) + if (start_command(&gpg)) { + unlink(path); return error("could not run gpg."); + } write_in_full(gpg.in, buf, len); close(gpg.in); From 64fb19ba636fc9e892119efc377808b86c919228 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Apr 2008 08:52:37 +0200 Subject: [PATCH 25/27] t7004-tag: Skip more tests if gpg is not available. This test was already careful enough to skip signed tag tests if gpg is not available, but it must also skip all verify tests, even those that are about non-signed tags, because they also invoke gpg. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- t/t7004-tag.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 75cd33bde8..1a7141ecd7 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -578,6 +578,14 @@ test_expect_success \ git diff expect actual ' +# subsequent tests require gpg; check if it is available +gpg --version >/dev/null +if [ $? -eq 127 ]; then + echo "gpg not found - skipping tag signing and verification tests" + test_done + exit +fi + # trying to verify annotated non-signed tags: test_expect_success \ @@ -600,13 +608,6 @@ test_expect_success \ # creating and verifying signed tags: -gpg --version >/dev/null -if [ $? -eq 127 ]; then - echo "Skipping signed tags tests, because gpg was not found" - test_done - exit -fi - # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19 # the gpg version 1.0.6 didn't parse trust packets correctly, so for # that version, creation of signed tags using the generated key fails. From cfc4ba33e3cc95a30cb808eec1b54b52450c3bdf Mon Sep 17 00:00:00 2001 From: Teemu Likonen Date: Wed, 2 Apr 2008 20:06:46 +0300 Subject: [PATCH 26/27] Describe the bug in handling filenames with funny characters in 'git add -i' The interactive mode does not work with files whose names contain characters that need C-quoting. `core.quotepath` configuration can be used to work this limitation around to some degree, but backslash, double-quote and control characters will still have problems. Signed-off-by: Junio C Hamano --- Documentation/git-add.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index c751a17d07..35e67a06e4 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -226,6 +226,12 @@ diff:: This lets you review what will be committed (i.e. between HEAD and index). +Bugs +---- +The interactive mode does not work with files whose names contain +characters that need C-quoting. `core.quotepath` configuration can be +used to work this limitation around to some degree, but backslash, +double-quote and control characters will still have problems. See Also -------- From 6c41b80153a2e4ee347d0e968ee8d0d9abfc8862 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 2 Apr 2008 10:42:14 -0700 Subject: [PATCH 27/27] GIT 1.5.5-rc3 The rate of fixes that trickle in has slowed and we are definitely getting there. Hopefully one final round and we will have the final 1.5.5 soon. Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.5.txt | 8 ++++---- GIT-VERSION-GEN | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/RelNotes-1.5.5.txt b/Documentation/RelNotes-1.5.5.txt index b299e8792c..64a52afb9d 100644 --- a/Documentation/RelNotes-1.5.5.txt +++ b/Documentation/RelNotes-1.5.5.txt @@ -6,7 +6,7 @@ Updates since v1.5.4 (subsystems) - * Comes with git-gui 0.9.3. + * Comes with git-gui 0.10.0 (portability) @@ -166,8 +166,8 @@ Updates since v1.5.4 symmetric difference between the HEAD version and the work tree version of the submodule commits. - * Various "git cvsimport", "git cvsexportcommit", "git svn" and - "git p4" improvements. + * Various "git cvsimport", "git cvsexportcommit", "git cvsserver", + "git svn" and "git p4" improvements. (internal) @@ -208,6 +208,6 @@ this release, unless otherwise noted. --- exec >/var/tmp/1 -O=v1.5.5-rc1-21-g319a36a +O=v1.5.5-rc3 echo O=`git describe refs/heads/master` git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 7529af9315..565cb41c10 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.5-rc2.GIT +DEF_VER=v1.5.5-rc3.GIT LF=' '