From 8ff45f2af5b25b7581072ee7896f4285dfc034ea Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Mon, 3 Mar 2008 13:42:47 +0100 Subject: [PATCH 01/16] git-p4: Optimize the fetching of data from perforce. Use shallow copies in loop, and join content at the end. Then do the substitution, if needed. Signed-off-by: Marius Storm-Olsen Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 650ea34176..539c5cda07 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -882,21 +882,21 @@ class P4Sync(Command): while j < len(filedata): stat = filedata[j] j += 1 - text = '' + text = []; while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'): - tmp = filedata[j]['data'] - if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): - tmp = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', tmp) - elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): - tmp = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', tmp) - text += tmp + text.append(filedata[j]['data']) j += 1 - + text = ''.join(text) if not stat.has_key('depotFile'): sys.stderr.write("p4 print fails with: %s\n" % repr(stat)) continue + if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): + text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text) + elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): + text = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', text) + contents[stat['depotFile']] = text for f in filesForCommit: From 67abd417165d1e7716d947949f5e5e27318c8a29 Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Wed, 12 Mar 2008 19:03:23 -0500 Subject: [PATCH 02/16] git-p4: Unset P4DIFF environment variable when using 'p4 -du diff' A custom diffing utility can be specified for the 'p4 diff' command by setting the P4DIFF environment variable. However when using a custom diffing utility such as 'vimdiff' passing options like -du can cause unexpected behavior. Since the goal is to generate a unified diff of the changes and attach them to the bottom of the p4 submit log we should unset P4DIFF if it has been set in order to generate the diff properly. Signed-off-by: Shawn Bohrer Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 539c5cda07..28b9c3c3cb 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -627,6 +627,8 @@ class P4Submit(Command): if self.interactive: submitTemplate = self.prepareLogMessage(template, logMessage) + if os.environ.has_key("P4DIFF"): + del(os.environ["P4DIFF"]) diff = read_pipe("p4 diff -du ...") for newFile in filesToAdd: From 82cea9ffb1c4677155e3e2996d76542502611370 Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Wed, 12 Mar 2008 19:03:24 -0500 Subject: [PATCH 03/16] git-p4: Use P4EDITOR environment variable when set Perforce allows you to set the P4EDITOR environment variable to your preferred editor for use in perforce. Since we are displaying a perforce changelog to the user we should use it when it is defined. Signed-off-by: Shawn Bohrer Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 28b9c3c3cb..3cb0330ec2 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -652,7 +652,10 @@ class P4Submit(Command): defaultEditor = "vi" if platform.system() == "Windows": defaultEditor = "notepad" - editor = os.environ.get("EDITOR", defaultEditor); + if os.environ.has_key("P4EDITOR"): + editor = os.environ.get("P4EDITOR") + else: + editor = os.environ.get("EDITOR", defaultEditor); system(editor + " " + fileName) tmpFile = open(fileName, "rb") message = tmpFile.read() From b14d255ba8362a4debe51dc67d6b98d06fdc36aa Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Wed, 19 Mar 2008 16:53:20 -0500 Subject: [PATCH 04/16] builtin-gc.c: allow disabling all auto-gc'ing by assigning 0 to gc.auto The gc.auto configuration variable is somewhat ambiguous now that there is also a gc.autopacklimit setting. Some users may assume that it controls all auto-gc'ing. Also, now users must set two configuration variables to zero when they want to disable autopacking. Since it is unlikely that users will want to autopack based on some threshold of pack files when they have disabled autopacking based on the number of loose objects, be nice and allow a setting of zero for gc.auto to disable all autopacking. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- builtin-gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin-gc.c b/builtin-gc.c index 95917d74a8..509bb9c6b3 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -160,10 +160,10 @@ static int too_many_packs(void) static int need_to_gc(void) { /* - * Setting gc.auto and gc.autopacklimit to 0 or negative can - * disable the automatic gc. + * Setting gc.auto to 0 or negative can disable the + * automatic gc. */ - if (gc_auto_threshold <= 0 && gc_auto_pack_limit <= 0) + if (gc_auto_threshold <= 0) return 0; /* From 05f304526197ac6e27ce1fe2e010eb023472b30b Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 19 Mar 2008 17:06:11 -0400 Subject: [PATCH 05/16] make it easier for people who just want to get rid of 'git gc --auto' Give a direct hint to those who feel highly annoyed by the auto gc behavior. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Documentation/git-gc.txt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt index 229a7c9b30..d424a4ecbe 100644 --- a/Documentation/git-gc.txt +++ b/Documentation/git-gc.txt @@ -19,8 +19,15 @@ created from prior invocations of linkgit:git-add[1]. Users are encouraged to run this task on a regular basis within each repository to maintain good disk space utilization and good -operating performance. Some git commands may automatically run -`git-gc`; see the `--auto` flag below for details. +operating performance. + +Some git commands may automatically run `git-gc`; see the `--auto` flag +below for details. If you know what you're doing and all you want is to +disable this behavior permanently without further considerations, just do: + +---------------------- +$ git config --global gc.auto 0 +---------------------- OPTIONS ------- From 7ccd366779dd0ff042472fd76223267c19b2e498 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 19 Mar 2008 02:16:28 -0400 Subject: [PATCH 06/16] Add --reverse to the git-rev-list usage string git-rev-list accepts --reverse, as documented in the manpage, but the usage string does not list it. Signed-off-by: Kevin Ballard Signed-off-by: Junio C Hamano --- builtin-rev-list.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index d0a1416921..edc0bd35bb 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -33,6 +33,7 @@ static const char rev_list_usage[] = " ordering output:\n" " --topo-order\n" " --date-order\n" +" --reverse\n" " formatting output:\n" " --parents\n" " --objects | --objects-edge\n" From a811e4f0f023d88596adbf39674a18d34b2f152d Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 19 Mar 2008 02:16:29 -0400 Subject: [PATCH 07/16] Document the sendemail.smtpserverport config variable Add sendemail.smtpserverport to the Configuration section of the git-send-email manpage. It should probably be referenced in the --smtp-server-port option as well. Signed-off-by: Kevin Ballard Signed-off-by: Junio C Hamano --- Documentation/git-send-email.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 336d797e80..9d0a10c562 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -216,6 +216,9 @@ sendemail.chainreplyto:: sendemail.smtpserver:: Default SMTP server to use. +sendemail.smtpserverport:: + Default SMTP server port to use. + sendemail.smtpuser:: Default SMTP-AUTH username. From 740fdd27f0888d5c80ef6a550734bdc53febd2df Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Mar 2008 00:27:42 +0000 Subject: [PATCH 08/16] remote show: do not show symbolic refs For symbolic refs, a sane notion of being "stale" is that the ref they point to no longer exists. Since this is checked already, "remote show" does not need to show them at all. Incidentally, this fixes the issue that "HEAD" was shown as a stale ref by "remote show" in a freshly cloned repository. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-remote.c | 5 ++++- t/t5505-remote.sh | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index 24e692953b..9c15173032 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -207,7 +207,10 @@ static int handle_one_branch(const char *refname, if (!remote_find_tracking(states->remote, &refspec)) { struct path_list_item *item; const char *name = skip_prefix(refspec.src, "refs/heads/"); - if (unsorted_path_list_has_path(&states->tracked, name) || + /* symbolic refs pointing nowhere were handled already */ + if ((flags & REF_ISSYMREF) || + unsorted_path_list_has_path(&states->tracked, + name) || unsorted_path_list_has_path(&states->new, name)) return 0; diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index ecfc999aaa..004a8dc5ed 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -237,4 +237,14 @@ test_expect_success 'update default (overridden, with funny whitespace)' ' ' +test_expect_success '"remote show" does not show symbolic refs' ' + + git clone one three && + (cd three && + git remote show origin > output && + ! grep HEAD < output && + ! grep -i stale < output) + +' + test_done From 8114da161611d6eb7cc6163aee2f5ba51ccad9f3 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Thu, 20 Mar 2008 16:08:49 -0400 Subject: [PATCH 09/16] Don't try and percent-escape existing percent escapes in git-svn URIs git-svn project names are percent-escaped ever since f5530b8 (git-svn: support for funky branch and project names over HTTP(S), 2007-11-11). Unfortunately this breaks the scenario where the user hands git-svn an already-escaped URI. Fix the regexp to skip over what looks like existing percent escapes, and test this scenario. Signed-off-by: Kevin Ballard Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 2 +- t/t9120-git-svn-clone-with-percent-escapes.sh | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100755 t/t9120-git-svn-clone-with-percent-escapes.sh diff --git a/git-svn.perl b/git-svn.perl index bba22c1321..0c2b791eab 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3665,7 +3665,7 @@ sub escape_uri_only { my ($uri) = @_; my @tmp; foreach (split m{/}, $uri) { - s/([^\w.-])/sprintf("%%%02X",ord($1))/eg; + s/([^\w.%-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; push @tmp, $_; } join('/', @tmp); diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh new file mode 100755 index 0000000000..9a4eabe523 --- /dev/null +++ b/t/t9120-git-svn-clone-with-percent-escapes.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Copyright (c) 2008 Kevin Ballard +# + +test_description='git-svn clone with percent escapes' +. ./lib-git-svn.sh + +test_expect_success 'setup svnrepo' " + mkdir project project/trunk project/branches project/tags && + echo foo > project/trunk/foo && + svn import -m '$test_description' project '$svnrepo/pr ject' && + rm -rf project && + start_httpd +" + +if test "$SVN_HTTPD_PORT" = "" +then + test_expect_failure 'test clone with percent escapes - needs SVN_HTTPD_PORT set' 'false' +else + test_expect_success 'test clone with percent escapes' ' + git svn clone "$svnrepo/pr%20ject" clone && + cd clone && + git rev-parse refs/remotes/git-svn && + cd .. + ' +fi + +stop_httpd + +test_done From c8a086929060eef9f0ce9f149d9dc22a6df6b85a Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 20 Mar 2008 11:54:30 -0500 Subject: [PATCH 10/16] t/t7003-filter-branch.sh: use test_must_fail rather than '!' Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t7003-filter-branch.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 553131fcf4..6827249da5 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -78,7 +78,7 @@ test_expect_success 'filter subdirectory only' ' test_expect_success 'subdirectory filter result looks okay' ' test 2 = $(git rev-list sub | wc -l) && git show sub:new && - ! git show sub:subdir + test_must_fail git show sub:subdir ' test_expect_success 'setup and filter history that requires --full-history' ' @@ -100,7 +100,7 @@ test_expect_success 'subdirectory filter result looks okay' ' test 3 = $(git rev-list -1 --parents sub-master | wc -w) && git show sub-master^:new && git show sub-master^2:new && - ! git show sub:subdir + test_must_fail git show sub:subdir ' test_expect_success 'use index-filter to move into a subdirectory' ' @@ -114,7 +114,7 @@ test_expect_success 'use index-filter to move into a subdirectory' ' test_expect_success 'stops when msg filter fails' ' old=$(git rev-parse HEAD) && - ! git-filter-branch -f --msg-filter false HEAD && + test_must_fail git-filter-branch -f --msg-filter false HEAD && test $old = $(git rev-parse HEAD) && rm -rf .git-rewrite ' @@ -151,8 +151,8 @@ test_expect_success "remove a certain author's commits" ' ' test_expect_success 'barf on invalid name' ' - ! git filter-branch -f master xy-problem && - ! git filter-branch -f HEAD^ + test_must_fail git filter-branch -f master xy-problem && + test_must_fail git filter-branch -f HEAD^ ' test_expect_success '"map" works in commit filter' ' @@ -174,7 +174,7 @@ test_expect_success 'Name needing quotes' ' git add foo && git commit -m "Adding a file" && git filter-branch --tree-filter "rm -fr foo" && - ! git ls-files --error-unmatch "foo/$name" && + test_must_fail git ls-files --error-unmatch "foo/$name" && test $(git rev-parse --verify rerere) != $(git rev-parse --verify A) ' From bf7c90216df7f6ac84dee7d30e14c954d48f4718 Mon Sep 17 00:00:00 2001 From: Ralf Wildenhues Date: Thu, 20 Mar 2008 22:30:32 +0100 Subject: [PATCH 11/16] Improve description of git filter-branch. Signed-off-by: Ralf Wildenhues Signed-off-by: Junio C Hamano --- Documentation/git-filter-branch.txt | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 543a1cf105..2a78549be5 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -25,7 +25,7 @@ Otherwise, all information (including original commit times or merge information) will be preserved. The command will only rewrite the _positive_ refs mentioned in the -command line (i.e. if you pass 'a..b', only 'b' will be rewritten). +command line (e.g. if you pass 'a..b', only 'b' will be rewritten). If you specify no filters, the commits will be recommitted without any changes, which would normally have no effect. Nevertheless, this may be useful in the future for compensating for some git bugs or such, @@ -42,7 +42,7 @@ Always verify that the rewritten version is correct: The original refs, if different from the rewritten ones, will be stored in the namespace 'refs/original/'. -Note that since this operation is extensively I/O expensive, it might +Note that since this operation is very I/O expensive, it might be a good idea to redirect the temporary directory off-disk with the '-d' option, e.g. on tmpfs. Reportedly the speedup is very noticeable. @@ -51,14 +51,15 @@ Filters ~~~~~~~ The filters are applied in the order as listed below. The -argument is always evaluated in shell using the 'eval' command (with the -notable exception of the commit filter, for technical reasons). +argument is always evaluated in the shell context using the 'eval' command +(with the notable exception of the commit filter, for technical reasons). Prior to that, the $GIT_COMMIT environment variable will be set to contain the id of the commit being rewritten. Also, GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, -and GIT_COMMITTER_DATE are set according to the current commit. If any -evaluation of returns a non-zero exit status, the whole operation -will be aborted. +and GIT_COMMITTER_DATE are set according to the current commit. The values +of these variables after the filters have run, are used for the new commit. +If any evaluation of returns a non-zero exit status, the whole +operation will be aborted. A 'map' function is available that takes an "original sha1 id" argument and outputs a "rewritten sha1 id" if the commit has been already @@ -71,9 +72,9 @@ OPTIONS ------- --env-filter :: - This is the filter for modifying the environment in which - the commit will be performed. Specifically, you might want - to rewrite the author/committer name/email/time environment + This filter may be used if you only need to modify the environment + in which the commit will be performed. Specifically, you might + want to rewrite the author/committer name/email/time environment variables (see linkgit:git-commit[1] for details). Do not forget to re-export the variables. @@ -149,7 +150,7 @@ definition impossible to preserve signatures at any rate.) -d :: Use this option to set the path to the temporary directory used for rewriting. When applying a tree filter, the command needs to - temporary checkout the tree to some directory, which may consume + temporarily check out the tree to some directory, which may consume considerable space in case of large projects. By default it does this in the '.git-rewrite/' directory but you can override that choice by this parameter. From 3644da7214055d2e84223b45dfca42d437fb7ea7 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 21 Mar 2008 03:27:35 -0400 Subject: [PATCH 12/16] Make git-svn tests behave better on OS X Give lib-git-svn.sh a few alternate paths to look for apache2. Explicitly define the LockFile so httpd will actually start under OS X Signed-off-by: Kevin Ballard Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- t/lib-git-svn.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 9ee35e7901..9decd2e1e8 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -49,8 +49,28 @@ poke() { test-chmtime +1 "$1" } -SVN_HTTPD_MODULE_PATH=${SVN_HTTPD_MODULE_PATH-'/usr/lib/apache2/modules'} -SVN_HTTPD_PATH=${SVN_HTTPD_PATH-'/usr/sbin/apache2'} +for d in \ + "$SVN_HTTPD_PATH" \ + /usr/sbin/apache2 \ + /usr/sbin/httpd \ +; do + if test -f "$d" + then + SVN_HTTPD_PATH="$d" + break + fi +done +for d in \ + "$SVN_HTTPD_MODULE_PATH" \ + /usr/lib/apache2/modules \ + /usr/libexec/apache2 \ +; do + if test -d "$d" + then + SVN_HTTPD_MODULE_PATH="$d" + break + fi +done start_httpd () { if test -z "$SVN_HTTPD_PORT" @@ -66,6 +86,7 @@ ServerName "git-svn test" ServerRoot "$GIT_DIR" DocumentRoot "$GIT_DIR" PidFile "$GIT_DIR/httpd.pid" +LockFile logs/accept.lock Listen 127.0.0.1:$SVN_HTTPD_PORT LoadModule dav_module $SVN_HTTPD_MODULE_PATH/mod_dav.so LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so From 9b33fa08b2d9507f8ffefe7649a59d23b4176185 Mon Sep 17 00:00:00 2001 From: Eyvind Bernhardsen Date: Fri, 21 Mar 2008 16:25:18 +0100 Subject: [PATCH 13/16] fast-import: Document the effect of "merge" with no "from" in a commit The fast-import documentation currently does not document the behaviour of "merge" when there is no "from" in a commit. This patch adds a description of what happens: the commit is created with a parent, but no files. This behaviour is equivalent to "from" followed by "filedeleteall". Signed-off-by: Eyvind Bernhardsen Acked-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- Documentation/git-fast-import.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 96f6767075..c29a4f8126 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -385,6 +385,9 @@ new commit. Omitting the `from` command in the first commit of a new branch will cause fast-import to create that commit with no ancestor. This tends to be desired only for the initial commit of a project. +If the frontend creates all files from scratch when making a new +branch, a `merge` command may be used instead of `from` to start +the commit with an empty tree. Omitting the `from` command on existing branches is usually desired, as the current commit on that branch is automatically assumed to be the first ancestor of the new commit. @@ -427,13 +430,15 @@ existing value of the branch. `merge` ^^^^^^^ -Includes one additional ancestor commit, and makes the current -commit a merge commit. An unlimited number of `merge` commands per +Includes one additional ancestor commit. If the `from` command is +omitted when creating a new branch, the first `merge` commit will be +the first ancestor of the current commit, and the branch will start +out with no files. An unlimited number of `merge` commands per commit are permitted by fast-import, thereby establishing an n-way merge. However Git's other tools never create commits with more than 15 additional ancestors (forming a 16-way merge). For this reason it is suggested that frontends do not use more than 15 `merge` -commands per commit. +commands per commit; 16, if starting a new, empty branch. Here `` is any of the commit specification expressions also accepted by `from` (see above). From 46220ca100cfbcdd7d80a5ac3326c52a3e98dddb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 20 Mar 2008 23:34:37 -0700 Subject: [PATCH 14/16] remote.c: Fix overtight refspec validation We tightened the refspec validation code in an earlier commit ef00d15 (Tighten refspec processing, 2008-03-17) per my suggestion, but the suggestion was misguided to begin with and it broke this usage: $ git push origin HEAD~12:master The syntax of push refspecs and fetch refspecs are similar in that they are both colon separated LHS and RHS (possibly prefixed with a + to force), but the similarity ends there. For example, LHS in a push refspec can be anything that evaluates to a valid object name at runtime (except when colon and RHS is missing, or it is a glob), while it must be a valid-looking refname in a fetch refspec. To validate them correctly, the caller needs to be able to say which kind of refspecs they are. It is unreasonable to keep a single interface that cannot tell which kind it is dealing with, and ask it to behave sensibly. This commit separates the parsing of the two into different functions, and clarifies the code to implement the parsing proper (i.e. splitting into two parts, making sure both sides are wildcard or neither side is). This happens to also allow pushing a commit named with the esoteric "look for that string" syntax: $ git push ../test.git ':/remote.c: Fix overtight refspec:master' Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 +- builtin-send-pack.c | 2 +- remote.c | 159 +++++++++++++++++++++++++++++++------------- remote.h | 3 +- t/t5511-refspec.sh | 72 ++++++++++++++++++++ 5 files changed, 189 insertions(+), 50 deletions(-) create mode 100755 t/t5511-refspec.sh diff --git a/builtin-fetch.c b/builtin-fetch.c index b2b9935ed6..a11548c894 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -652,5 +652,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) signal(SIGINT, unlock_pack_on_signal); atexit(unlock_pack); - return do_fetch(transport, parse_ref_spec(ref_nr, refs), ref_nr); + return do_fetch(transport, + parse_fetch_refspec(ref_nr, refs), ref_nr); } diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 930e0fb3fd..bb9c33a650 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -537,7 +537,7 @@ static void verify_remote_names(int nr_heads, const char **heads) int i; for (i = 0; i < nr_heads; i++) { - const char *remote = strchr(heads[i], ':'); + const char *remote = strrchr(heads[i], ':'); remote = remote ? (remote + 1) : heads[i]; switch (check_ref_format(remote)) { diff --git a/remote.c b/remote.c index 9700a33c57..40ed24633f 100644 --- a/remote.c +++ b/remote.c @@ -393,58 +393,123 @@ static void read_config(void) alias_all_urls(); } -struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) +static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch) { int i; int st; struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); + for (i = 0; i < nr_refspec; i++) { - const char *sp, *ep, *gp; - sp = refspec[i]; - if (*sp == '+') { + size_t llen, rlen; + int is_glob; + const char *lhs, *rhs; + + llen = rlen = is_glob = 0; + + lhs = refspec[i]; + if (*lhs == '+') { rs[i].force = 1; - sp++; + lhs++; } - gp = strstr(sp, "/*"); - ep = strchr(sp, ':'); - if (gp && ep && gp > ep) - gp = NULL; - if (ep) { - if (ep[1]) { - const char *glob = strstr(ep + 1, "/*"); - if (glob && glob[2]) - glob = NULL; - if (!glob) - gp = NULL; - if (gp) - rs[i].dst = xstrndup(ep + 1, - glob - ep - 1); - else - rs[i].dst = xstrdup(ep + 1); + + rhs = strrchr(lhs, ':'); + if (rhs) { + rhs++; + rlen = strlen(rhs); + is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); + rs[i].dst = xstrndup(rhs, rlen - is_glob * 2); + } + + llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); + if (is_glob != (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2))) + goto invalid; + + if (is_glob) { + llen -= 2; + rlen -= 2; + } + rs[i].pattern = is_glob; + rs[i].src = xstrndup(lhs, llen); + + if (fetch) { + /* + * LHS + * - empty is allowed; it means HEAD. + * - otherwise it must be a valid looking ref. + */ + if (!*rs[i].src) + ; /* empty is ok */ + else { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } + /* + * RHS + * - missing is allowed. + * - empty is ok; it means not to store. + * - otherwise it must be a valid looking ref. + */ + if (!rs[i].dst) { + ; /* ok */ + } else if (!*rs[i].dst) { + ; /* ok */ + } else { + st = check_ref_format(rs[i].dst); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; } } else { - ep = sp + strlen(sp); - } - if (gp && gp + 2 != ep) - gp = NULL; - if (gp) { - rs[i].pattern = 1; - ep = gp; - } - rs[i].src = xstrndup(sp, ep - sp); - - if (*rs[i].src) { - st = check_ref_format(rs[i].src); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) - die("Invalid refspec '%s'", refspec[i]); - } - if (rs[i].dst && *rs[i].dst) { - st = check_ref_format(rs[i].dst); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) - die("Invalid refspec '%s'", refspec[i]); + /* + * LHS + * - empty is allowed; it means delete. + * - when wildcarded, it must be a valid looking ref. + * - otherwise, it must be an extended SHA-1, but + * there is no existing way to validate this. + */ + if (!*rs[i].src) + ; /* empty is ok */ + else if (is_glob) { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } + else + ; /* anything goes, for now */ + /* + * RHS + * - missing is allowed, but LHS then must be a + * valid looking ref. + * - empty is not allowed. + * - otherwise it must be a valid looking ref. + */ + if (!rs[i].dst) { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } else if (!*rs[i].dst) { + goto invalid; + } else { + st = check_ref_format(rs[i].dst); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } } } return rs; + + invalid: + die("Invalid refspec '%s'", refspec[i]); +} + +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) +{ + return parse_refspec_internal(nr_refspec, refspec, 1); +} + +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) +{ + return parse_refspec_internal(nr_refspec, refspec, 0); } static int valid_remote_nick(const char *name) @@ -475,8 +540,8 @@ struct remote *remote_get(const char *name) add_url_alias(ret, name); if (!ret->url) return NULL; - ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); + ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec); + ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec); return ret; } @@ -489,11 +554,11 @@ int for_each_remote(each_remote_fn fn, void *priv) if (!r) continue; if (!r->fetch) - r->fetch = parse_ref_spec(r->fetch_refspec_nr, - r->fetch_refspec); + r->fetch = parse_fetch_refspec(r->fetch_refspec_nr, + r->fetch_refspec); if (!r->push) - r->push = parse_ref_spec(r->push_refspec_nr, - r->push_refspec); + r->push = parse_push_refspec(r->push_refspec_nr, + r->push_refspec); result = fn(r, priv); } return result; @@ -824,7 +889,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int flags) { struct refspec *rs = - parse_ref_spec(nr_refspec, (const char **) refspec); + parse_push_refspec(nr_refspec, (const char **) refspec); int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; diff --git a/remote.h b/remote.h index f1dedf15f6..7e9ae792dc 100644 --- a/remote.h +++ b/remote.h @@ -67,7 +67,8 @@ void free_refs(struct ref *ref); */ void ref_remove_duplicates(struct ref *ref_map); -struct refspec *parse_ref_spec(int nr_refspec, const char **refspec); +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int all); diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh new file mode 100755 index 0000000000..670a8f1c99 --- /dev/null +++ b/t/t5511-refspec.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +test_description='refspec parsing' + +. ./test-lib.sh + +test_refspec () { + + kind=$1 refspec=$2 expect=$3 + git config remote.frotz.url "." && + git config --remove-section remote.frotz && + git config remote.frotz.url "." && + git config "remote.frotz.$kind" "$refspec" && + if test "$expect" != invalid + then + title="$kind $refspec" + test='git ls-remote frotz' + else + title="$kind $refspec (invalid)" + test='test_must_fail git ls-remote frotz' + fi + test_expect_success "$title" "$test" +} + +test_refspec push '' invalid +test_refspec push ':' invalid + +test_refspec fetch '' +test_refspec fetch ':' + +test_refspec push 'refs/heads/*:refs/remotes/frotz/*' +test_refspec push 'refs/heads/*:refs/remotes/frotz' invalid +test_refspec push 'refs/heads:refs/remotes/frotz/*' invalid +test_refspec push 'refs/heads/master:refs/remotes/frotz/xyzzy' + + +# These have invalid LHS, but we do not have a formal "valid sha-1 +# expression syntax checker" so they are not checked with the current +# code. They will be caught downstream anyway, but we may want to +# have tighter check later... + +: test_refspec push 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +: test_refspec push 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid + +test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' +test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid +test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid +test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' +test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid + +test_refspec push 'master~1:refs/remotes/frotz/backup' +test_refspec fetch 'master~1:refs/remotes/frotz/backup' invalid +test_refspec push 'HEAD~4:refs/remotes/frotz/new' +test_refspec fetch 'HEAD~4:refs/remotes/frotz/new' invalid + +test_refspec push 'HEAD' +test_refspec fetch 'HEAD' +test_refspec push 'refs/heads/ nitfol' invalid +test_refspec fetch 'refs/heads/ nitfol' invalid + +test_refspec push 'HEAD:' invalid +test_refspec fetch 'HEAD:' +test_refspec push 'refs/heads/ nitfol:' invalid +test_refspec fetch 'refs/heads/ nitfol:' invalid + +test_refspec push ':refs/remotes/frotz/deleteme' +test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' +test_refspec push ':refs/remotes/frotz/delete me' invalid +test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid + +test_done From 970639740c5f57508e42aeacd23823d7cf001659 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 23 Mar 2008 00:04:48 -0700 Subject: [PATCH 15/16] gc --auto: raise default auto pack limit from 20 to 50 Recent discussion on the list, with the improvement f7c22cc (always start looking up objects in the last used pack first, 2007-05-30) brought in, reached the concensus that the current default 20 is too low. Reference: http://thread.gmane.org/gmane.comp.version-control.git/77586 Signed-off-by: Junio C Hamano --- Documentation/config.txt | 2 +- builtin-gc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 0865f4e01a..3017d640cf 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -582,7 +582,7 @@ gc.autopacklimit:: When there are more than this many packs that are not marked with `*.keep` file in the repository, `git gc --auto` consolidates them into one larger pack. The - default value is 20. Setting this to 0 disables it. + default value is 50. Setting this to 0 disables it. gc.packrefs:: `git gc` does not run `git pack-refs` in a bare repository by diff --git a/builtin-gc.c b/builtin-gc.c index 509bb9c6b3..8cef36f6a4 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -25,7 +25,7 @@ static const char * const builtin_gc_usage[] = { static int pack_refs = 1; static int aggressive_window = -1; static int gc_auto_threshold = 6700; -static int gc_auto_pack_limit = 20; +static int gc_auto_pack_limit = 50; static char *prune_expire = "2.weeks.ago"; #define MAX_ADD 10 From bc6100087cfac0293e6ccbea95a24223b724d072 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 23 Mar 2008 00:21:48 -0700 Subject: [PATCH 16/16] GIT 1.5.5-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.5.txt | 5 ++++- GIT-VERSION-GEN | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/RelNotes-1.5.5.txt b/Documentation/RelNotes-1.5.5.txt index e31ae6a293..14beed49ba 100644 --- a/Documentation/RelNotes-1.5.5.txt +++ b/Documentation/RelNotes-1.5.5.txt @@ -124,6 +124,9 @@ Updates since v1.5.4 * "git gc" now automatically prunes unreachable objects that are two weeks old or older. + * "git gc --auto" can be disabled more easily by just setting gc.auto + to zero. It also tolerates more packfiles by default. + * "git grep" now knows "--name-only" is a synonym for the "-l" option. * "git help " now reports "'git ' is alias to ", @@ -201,6 +204,6 @@ this release, unless otherwise noted. --- exec >/var/tmp/1 -O=v1.5.4.4-620-gc817faa +O=v1.5.5-rc1 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 6ddf04d216..d0b60f40d8 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.4.GIT +DEF_VER=v1.5.5-rc1.GIT LF=' '