From 27086d0f8418b1961a5fc2bea978f0a5ff37c50d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 31 Dec 2006 02:20:23 -0500 Subject: [PATCH 01/11] Add test case for update hooks in receive-pack. Verify that the update hooks work as documented/advertised. This is a simple set of tests to check that the update hooks run with the parameters expected, have their STDOUT and STDERR redirected to the client side of the connection, and that their STDIN does not contain any data (as its actually /dev/null). Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- t/t5401-update-hooks.sh | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 t/t5401-update-hooks.sh diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh new file mode 100755 index 0000000000..cd8cee6ae8 --- /dev/null +++ b/t/t5401-update-hooks.sh @@ -0,0 +1,81 @@ +#!/bin/sh +# +# Copyright (c) 2006 Shawn O. Pearce +# + +test_description='Test the update hook infrastructure.' +. ./test-lib.sh + +test_expect_success setup ' + echo This is a test. >a && + git-update-index --add a && + tree0=$(git-write-tree) && + commit0=$(echo setup | git-commit-tree $tree0) && + git-update-ref HEAD $commit0 && + git-clone ./. victim && + echo We hope it works. >a && + git-update-index a && + tree1=$(git-write-tree) && + commit1=$(echo modify | git-commit-tree $tree1 -p $commit0) && + git-update-ref HEAD $commit1 +' + +cat >victim/.git/hooks/update <<'EOF' +#!/bin/sh +echo "$@" >$GIT_DIR/update.args +read x; echo -n "$x" >$GIT_DIR/update.stdin +echo STDOUT update +echo STDERR update >&2 +EOF +chmod u+x victim/.git/hooks/update + +cat >victim/.git/hooks/post-update <<'EOF' +#!/bin/sh +echo "$@" >$GIT_DIR/post-update.args +read x; echo -n "$x" >$GIT_DIR/post-update.stdin +echo STDOUT post-update +echo STDERR post-update >&2 +EOF +chmod u+x victim/.git/hooks/post-update + +test_expect_success push ' + git-send-pack ./victim/.git/ master >send.out 2>send.err +' + +test_expect_success 'hooks ran' ' + test -f victim/.git/update.args && + test -f victim/.git/update.stdin && + test -f victim/.git/post-update.args && + test -f victim/.git/post-update.stdin +' + +test_expect_success 'update hook arguments' ' + echo refs/heads/master $commit0 $commit1 | + diff -u - victim/.git/update.args +' + +test_expect_success 'post-update hook arguments' ' + echo refs/heads/master | + diff -u - victim/.git/post-update.args +' + +test_expect_failure 'update hook stdin is /dev/null' ' + test -s victim/.git/update.stdin +' + +test_expect_failure 'post-update hook stdin is /dev/null' ' + test -s victim/.git/post-update.stdin +' + +test_expect_failure 'send-pack produced no output' ' + test -s send.out +' + +test_expect_success 'send-pack stderr contains hook messages' ' + grep "STDOUT update" send.err && + grep "STDERR update" send.err && + grep "STDOUT post-update" send.err && + grep "STDERR post-update" send.err +' + +test_done From 87a3d29f460701bf6fc1f34419290cad658c11a2 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 31 Dec 2006 00:52:25 -0800 Subject: [PATCH 02/11] Update documentation for update hook. Signed-off-by: Junio C Hamano --- Documentation/hooks.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt index 517f49b5cc..161123f142 100644 --- a/Documentation/hooks.txt +++ b/Documentation/hooks.txt @@ -126,9 +126,9 @@ Another use suggested on the mailing list is to use this hook to implement access control which is finer grained than the one based on filesystem group. -The standard output of this hook is sent to `/dev/null`; if you +The standard output of this hook is sent to `stderr`, so if you want to report something to the `git-send-pack` on the other end, -you can redirect your output to your `stderr`. +you can simply `echo` your messages. post-update From 4b4ee90e587779233488325d2832a946eebe03e0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 31 Dec 2006 00:59:53 -0800 Subject: [PATCH 03/11] send-pack.c: use is_null_sha1() Everybody else uses is_null_sha1() -- there is no point to have its own is_zero_sha1() anymore. Signed-off-by: Junio C Hamano --- send-pack.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/send-pack.c b/send-pack.c index 54de96e40c..29cf73681f 100644 --- a/send-pack.c +++ b/send-pack.c @@ -14,17 +14,6 @@ static int send_all; static int force_update; static int use_thin_pack; -static int is_zero_sha1(const unsigned char *sha1) -{ - int i; - - for (i = 0; i < 20; i++) { - if (*sha1++) - return 0; - } - return 1; -} - static void exec_pack_objects(void) { static const char *args[] = { @@ -338,7 +327,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) if (!force_update && !delete_ref && - !is_zero_sha1(ref->old_sha1) && + !is_null_sha1(ref->old_sha1) && !ref->force) { if (!has_sha1_file(ref->old_sha1) || !ref_newer(ref->peer_ref->new_sha1, From 0ae5f98c7ba29fa4c698989cd6b38deba06d5bf3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 31 Dec 2006 01:26:53 -0800 Subject: [PATCH 04/11] send-pack: tell pack-objects to use its internal rev-list. This means one less process in the pipeline to worry about, and removes about 1/8 of the code. Signed-off-by: Junio C Hamano --- send-pack.c | 139 ++++++++++++++++------------------------------------ 1 file changed, 42 insertions(+), 97 deletions(-) diff --git a/send-pack.c b/send-pack.c index 29cf73681f..eaa6efbc0c 100644 --- a/send-pack.c +++ b/send-pack.c @@ -14,100 +14,49 @@ static int send_all; static int force_update; static int use_thin_pack; -static void exec_pack_objects(void) -{ - static const char *args[] = { - "pack-objects", - "--all-progress", - "--stdout", - NULL - }; - execv_git_cmd(args); - die("git-pack-objects exec failed (%s)", strerror(errno)); -} - -static void exec_rev_list(struct ref *refs) -{ - static const char *args[4]; - int i = 0; - - args[i++] = "rev-list"; /* 0 */ - if (use_thin_pack) /* 1 */ - args[i++] = "--objects-edge"; - else - args[i++] = "--objects"; - - args[i++] = "--stdin"; - - args[i] = NULL; - execv_git_cmd(args); - die("git-rev-list exec failed (%s)", strerror(errno)); -} - /* - * Run "rev-list --stdin | pack-objects" pipe. + * Make a pack stream and spit it out into file descriptor fd */ -static void rev_list(struct ref *refs) +static int pack_objects(int fd, struct ref *refs) { int pipe_fd[2]; - pid_t pack_objects_pid; + pid_t pid; if (pipe(pipe_fd) < 0) - die("rev-list setup: pipe failed"); - pack_objects_pid = fork(); - if (!pack_objects_pid) { - /* The child becomes pack-objects; reads from pipe - * and writes to the original fd - */ - dup2(pipe_fd[0], 0); - close(pipe_fd[0]); - close(pipe_fd[1]); - exec_pack_objects(); - die("pack-objects setup failed"); - } - if (pack_objects_pid < 0) - die("pack-objects fork failed"); - - /* We become rev-list --stdin; output goes to pipe. */ - dup2(pipe_fd[1], 1); - close(pipe_fd[0]); - close(pipe_fd[1]); - exec_rev_list(refs); -} - -/* - * Create "rev-list --stdin | pack-objects" pipe and feed - * the refs into the pipeline. - */ -static void rev_list_generate(int fd, struct ref *refs) -{ - int pipe_fd[2]; - pid_t rev_list_generate_pid; - - if (pipe(pipe_fd) < 0) - die("rev-list-generate setup: pipe failed"); - rev_list_generate_pid = fork(); - if (!rev_list_generate_pid) { - /* The child becomes the "rev-list | pack-objects" - * pipeline. It takes input from us, and its output - * goes to fd. + return error("send-pack: pipe failed"); + pid = fork(); + if (!pid) { + /* + * The child becomes pack-objects --revs; we feed + * the revision parameters to it via its stdin and + * let its stdout go back to the other end. */ + static const char *args[] = { + "pack-objects", + "--all-progress", + "--revs", + "--stdout", + NULL, + NULL, + }; + if (use_thin_pack) + args[4] = "--thin"; dup2(pipe_fd[0], 0); dup2(fd, 1); close(pipe_fd[0]); close(pipe_fd[1]); close(fd); - rev_list(refs); - die("rev-list setup failed"); + execv_git_cmd(args); + die("git-pack-objects exec failed (%s)", strerror(errno)); } - if (rev_list_generate_pid < 0) - die("rev-list-generate fork failed"); - /* We feed the rev parameters to them. We do not write into - * fd nor read from the pipe. + /* + * We feed the pack-objects we just spawned with revision + * parameters by writing to the pipe. */ close(pipe_fd[0]); close(fd); + while (refs) { char buf[42]; @@ -126,28 +75,24 @@ static void rev_list_generate(int fd, struct ref *refs) refs = refs->next; } close(pipe_fd[1]); - // waitpid(rev_list_generate_pid); - exit(0); -} -/* - * Make a pack stream and spit it out into file descriptor fd - */ -static void pack_objects(int fd, struct ref *refs) -{ - pid_t rev_list_pid; + for (;;) { + int status, code; + pid_t waiting = waitpid(pid, &status, 0); - rev_list_pid = fork(); - if (!rev_list_pid) { - rev_list_generate(fd, refs); - die("rev-list setup failed"); + if (waiting < 0) { + if (errno == EINTR) + continue; + return error("waitpid failed (%s)", strerror(errno)); + } + if ((waiting != pid) || WIFSIGNALED(status) || + !WIFEXITED(status)) + return error("pack-objects died with strange error"); + code = WEXITSTATUS(status); + if (code) + return -code; + return 0; } - if (rev_list_pid < 0) - die("rev-list fork failed"); - /* - * We don't wait for the rev-list pipeline in the parent: - * we end up waiting for the other end instead - */ } static void unmark_and_free(struct commit_list *list, unsigned int mark) @@ -379,7 +324,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) packet_flush(out); if (new_refs) - pack_objects(out, remote_refs); + ret = pack_objects(out, remote_refs); close(out); if (expect_status_report) { From c04197ee1e575cf78662b2c8c055089a5c669214 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 31 Dec 2006 18:47:33 -0500 Subject: [PATCH 05/11] Docs: update cvs-migration.txt to reflect clone's new default behavior I couldn't think of a really quick way to give all the details, so just refer readers to the git-repo-config man page instead. I haven't tested recent cvs import behavior--some time presumably it should be updated to do something more similar to clone. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/cvs-migration.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index b657f4589f..8e09beaa79 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -34,13 +34,10 @@ them first before running git pull. [NOTE] ================================ -The first `git clone` places the following in the -`my-project/.git/remotes/origin` file, and that's why the previous step -and the next step both work. ------------- -URL: foo.com:/pub/project.git/ -Pull: refs/heads/master:refs/remotes/origin/master ------------- +The `pull` command knows where to get updates from because of certain +configuration variables that were set by the first `git clone` +command; see `git repo-config -l` and the gitlink:git-repo-config[1] man +page for details. ================================ You can update the shared repository with your changes by first committing From 36566cc0bc2e5e930e4ed885e1a15fcfd10b0b53 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 31 Dec 2006 18:47:34 -0500 Subject: [PATCH 06/11] Documentation: update git-clone.txt for clone's new default behavior Fix a couple remaining references to the origin branch. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/git-clone.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 874934a332..96523204dd 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -75,16 +75,13 @@ OPTIONS Also the branch heads at the remote are copied directly to corresponding local branch heads, without mapping them to `refs/remotes/origin/`. When this option is - used, neither the `origin` branch nor the default - `remotes/origin` file is created. + used, neither remote-tracking branches nor the related + configuration variables are created. --origin :: -o :: - Instead of using the branch name 'origin' to keep track - of the upstream repository, use instead. Note - that the shorthand name stored in `remotes/origin` is - not affected, but the local branch name to pull the - remote `master` branch into is. + Instead of using the remote name 'origin' to keep track + of the upstream repository, use instead. --upload-pack :: -u :: From f65bb2c66fbebc10810857c64466679c81bf8154 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 31 Dec 2006 18:47:36 -0500 Subject: [PATCH 07/11] Documentation: update glossary entry for "origin" Update glossary entry for "origin" to reflect fact that it normally now refers to a remote repository, not a branch. Also, warning not to work on remote-tracking branches is no longer necessary since git doesn't allow that. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/glossary.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt index 894883d7b6..7c1a6592c1 100644 --- a/Documentation/glossary.txt +++ b/Documentation/glossary.txt @@ -188,11 +188,12 @@ octopus:: predator. origin:: - The default upstream tracking branch. Most projects have at + The default upstream repository. Most projects have at least one upstream project which they track. By default 'origin' is used for that purpose. New upstream updates - will be fetched into this branch; you should never commit - to it yourself. + will be fetched into remote tracking branches named + origin/name-of-upstream-branch, which you can see using + "git branch -r". pack:: A set of objects which have been compressed into one file (to save From d66409f068df3a8590524c3224e300194c7c8b6b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 31 Dec 2006 18:47:38 -0500 Subject: [PATCH 08/11] Documentation: update tutorial's discussion of origin Update tutorial's discussion of origin branch to reflect new defaults, and include a brief mention of git-repo-config. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/tutorial.txt | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index cb808d924b..d043e844d2 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -323,20 +323,25 @@ $ git pull Note that he doesn't need to give the path to Alice's repository; when Bob cloned Alice's repository, git stored the location of her -repository in the file .git/remotes/origin, and that location is used -as the default for pulls. - -Bob may also notice a branch in his repository that he didn't create: +repository in the repository configuration, and that location is +used for pulls: ------------------------------------- -$ git branch -* master - origin +$ git repo-config --get remote.origin.url +/home/bob/myrepo ------------------------------------- -The "origin" branch, which was created automatically by "git clone", -is a pristine copy of Alice's master branch; Bob should never commit -to it. +(The complete configuration created by git-clone is visible using +"git repo-config -l", and the gitlink:git-repo-config[1] man page +explains the meaning of each option.) + +Git also keeps a pristine copy of Alice's master branch under the +name "origin/master": + +------------------------------------- +$ git branch -r + origin/master +------------------------------------- If Bob later decides to work from a different host, he can still perform clones and pulls using the ssh protocol: From 63c97ce228f2d2697a8ed954a9592dfb5f286338 Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Sat, 30 Dec 2006 23:11:52 -0500 Subject: [PATCH 09/11] Fix formatting for urls section of fetch, pull, and push manpages Updated to make the nroff'ed man pages look nicer. Signed-off-by: "Theodore Ts'o" Signed-off-by: Junio C Hamano --- Documentation/urls.txt | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 870c95073b..745f9677d0 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -41,9 +41,10 @@ file in `$GIT_DIR/remotes` directory can be given; the named file should be in the following format: ------------ -URL: one of the above URL format -Push: -Pull: + URL: one of the above URL format + Push: + Pull: + ------------ Then such a short-hand is specified in place of @@ -57,10 +58,11 @@ Or, equivalently, in the `$GIT_DIR/config` (note the use of `fetch` instead of `Pull:`): ------------ -[remote ""] - url = - push = - fetch = + [remote ""] + url = + push = + fetch = + ------------ The name of a file in `$GIT_DIR/branches` directory can be @@ -73,14 +75,14 @@ without the fragment is equivalent to have this in the corresponding file in the `$GIT_DIR/remotes/` directory. ------------ -URL: -Pull: refs/heads/master: ------------- + URL: + Pull: refs/heads/master: +------------ while having `#` is equivalent to ------------ -URL: -Pull: refs/heads/: + URL: + Pull: refs/heads/: ------------ From fbc9012307d3b2e1bcee84e4455b11e97f580e07 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 31 Dec 2006 17:44:37 -0800 Subject: [PATCH 10/11] Do not merge random set of refs out of wildcarded refs When your fetch configuration has only the wildcards, we would pick the lexicographically first ref from the remote side for merging, which was complete nonsense. Make sure nothing except the one that is specified with branch.*.merge is merged in this case. Signed-off-by: Junio C Hamano --- git-parse-remote.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 144f170155..d2e4c2b9ae 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -76,16 +76,32 @@ get_remote_default_refs_for_push () { # from get_remote_refs_for_fetch when it deals with refspecs # supplied on the command line. $ls_remote_result has the list # of refs available at remote. +# +# The first token returned is either "explicit" or "glob"; this +# is to help prevent randomly "globbed" ref from being chosen as +# a merge candidate expand_refs_wildcard () { + first_one=yes for ref do lref=${ref#'+'} # a non glob pattern is given back as-is. expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || { + if test -n "$first_one" + then + echo "explicit" + first_one= + fi echo "$ref" continue } + # glob + if test -n "$first_one" + then + echo "glob" + first_one= + fi from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'` to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'` local_force= @@ -116,7 +132,8 @@ canon_refs_list_for_fetch () { if test "$1" = "-d" then shift ; remote="$1" ; shift - set x $(expand_refs_wildcard "$@") + set $(expand_refs_wildcard "$@") + is_explicit="$1" shift if test "$remote" = "$(get_default_remote)" then @@ -125,6 +142,10 @@ canon_refs_list_for_fetch () { merge_branches=$(git-repo-config \ --get-all "branch.${curr_branch}.merge") fi + if test -z "$merge_branches" && test $is_explicit != explicit + then + merge_branches=..this.will.never.match.any.ref.. + fi fi for ref do From e90068a9046ccaf0bed82fd180b4748edbd5659a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 31 Dec 2006 18:18:23 -0800 Subject: [PATCH 11/11] i18n: do not leak 'encoding' header even when we cheat the conversion. We special case the case where encoding recorded in the commit and the output encoding are the same and do not call iconv(). But we should drop 'encoding' header for this case as well for consistency. Signed-off-by: Junio C Hamano --- commit.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/commit.c b/commit.c index afdf27eece..544e42629e 100644 --- a/commit.c +++ b/commit.c @@ -679,11 +679,13 @@ static char *logmsg_reencode(const struct commit *commit) else if (!*output_encoding) return NULL; encoding = get_header(commit, "encoding"); - if (!encoding || !strcmp(encoding, output_encoding)) { - free(encoding); + if (!encoding) return NULL; - } - out = reencode_string(commit->buffer, output_encoding, encoding); + if (!strcmp(encoding, output_encoding)) + out = strdup(commit->buffer); + else + out = reencode_string(commit->buffer, + output_encoding, encoding); if (out) out = replace_encoding_header(out, output_encoding);