Merge branch 'master' into next

* master:
  i18n: do not leak 'encoding' header even when we cheat the conversion.
  Do not merge random set of refs out of wildcarded refs
  Fix formatting for urls section of fetch, pull, and push manpages
  Documentation: update tutorial's discussion of origin
  Documentation: update glossary entry for "origin"
  Documentation: update git-clone.txt for clone's new default behavior
  Docs: update cvs-migration.txt to reflect clone's new default behavior
  send-pack: tell pack-objects to use its internal rev-list.
  send-pack.c: use is_null_sha1()
  Update documentation for update hook.
  Add test case for update hooks in receive-pack.
This commit is contained in:
Junio C Hamano
2006-12-31 18:58:54 -08:00
10 changed files with 195 additions and 155 deletions

View File

@@ -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

View File

@@ -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 <name>::
-o <name>::
Instead of using the branch name 'origin' to keep track
of the upstream repository, use <name> 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 <name> instead.
--upload-pack <upload-pack>::
-u <upload-pack>::

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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: <refspec>
Pull: <refspec>
URL: one of the above URL format
Push: <refspec>
Pull: <refspec>
------------
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 "<remote>"]
url = <url>
push = <refspec>
fetch = <refspec>
[remote "<remote>"]
url = <url>
push = <refspec>
fetch = <refspec>
------------
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: <url>
Pull: refs/heads/master:<remote>
------------
URL: <url>
Pull: refs/heads/master:<remote>
------------
while having `<url>#<head>` is equivalent to
------------
URL: <url>
Pull: refs/heads/<head>:<remote>
URL: <url>
Pull: refs/heads/<head>:<remote>
------------

View File

@@ -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);

View File

@@ -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

View File

@@ -14,111 +14,49 @@ 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[] = {
"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];
@@ -137,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)
@@ -338,7 +272,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,
@@ -390,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) {

81
t/t5401-update-hooks.sh Executable file
View File

@@ -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