mirror of
https://github.com/git/git.git
synced 2026-03-14 10:53:25 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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>::
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
------------
|
||||
|
||||
10
commit.c
10
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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
152
send-pack.c
152
send-pack.c
@@ -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
81
t/t5401-update-hooks.sh
Executable 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
|
||||
Reference in New Issue
Block a user