fetch-pack: start multi-head pulling.

This is a beginning of resurrecting the multi-head pulling support
for git-fetch-pack command.  The git-fetch-script wrapper still
only knows about fetching a single head, without renaming, so it is
not very useful unless you directly call git-fetch-pack itself yet.

It also fixes a longstanding obsolete description of how the command
discovers the list of local commits.
This commit is contained in:
Junio C Hamano 2005-08-12 02:08:29 -07:00
parent 87b7b84159
commit 33b8303466
3 changed files with 51 additions and 27 deletions

View file

@ -9,19 +9,19 @@ git-fetch-pack - Receive missing objects from another repository.
SYNOPSIS
--------
git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<head>...] < <commit-list>
git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
DESCRIPTION
-----------
Invokes 'git-upload-pack' on a potentially remote repository,
and asks it to send objects missing from this repository, to
update the named heads. The list of commits available locally
is fed from the standard input, to be sent to 'git-upload-pack'
running on the other end.
is found out by scanning local $GIT_DIR/refs/ and sent to
'git-upload-pack' running on the other end.
This command can be used only when the local side has a common
(ancestor) commit with the remote head that is being pulled
from. Use 'git-clone-pack' for that.
This command degenerates to download everything to complete the
asked refs from the remote side when the local side does not
have a common ancestor commit.
OPTIONS
@ -50,15 +50,11 @@ OPTIONS
<directory>::
The repository to sync from.
<head>...::
<refs>...::
The remote heads to update from. This is relative to
$GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
unspecified, update from all heads the remote side has.
However the program refuses to work if more than one
remote head matches the specified heads. I am not sure
what this means... Help!!!!!
Author
------

View file

@ -4,10 +4,13 @@
#include <sys/wait.h>
static int quiet;
static const char fetch_pack_usage[] = "git-fetch-pack [-q] [--exec=upload-pack] [host:]directory [heads]* < mycommitlist";
static int verbose;
static const char fetch_pack_usage[] =
"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
static const char *exec = "git-upload-pack";
static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *remote)
static int find_common(int fd[2], unsigned char *result_sha1,
struct ref *refs)
{
static char line[1000];
int count = 0, flushes = 0, retval;
@ -16,7 +19,16 @@ static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *rem
revs = popen("git-rev-list $(git-rev-parse --all)", "r");
if (!revs)
die("unable to run 'git-rev-list'");
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
while (refs) {
unsigned char *remote = refs->old_sha1;
if (verbose)
fprintf(stderr,
"want %s (%s)\n", sha1_to_hex(remote),
refs->name);
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
refs = refs->next;
}
packet_flush(fd[1]);
flushes = 1;
retval = -1;
@ -25,6 +37,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *rem
if (get_sha1_hex(line, sha1))
die("git-fetch-pack: expected object name, got crud");
packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
if (verbose)
fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
if (!(31 & ++count)) {
packet_flush(fd[1]);
flushes++;
@ -38,6 +52,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *rem
if (get_ack(fd[0], result_sha1)) {
flushes = 0;
retval = 0;
if (verbose)
fprintf(stderr, "got ack\n");
break;
}
flushes--;
@ -45,19 +61,19 @@ static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *rem
}
pclose(revs);
packet_write(fd[1], "done\n");
if (verbose)
fprintf(stderr, "done\n");
while (flushes) {
flushes--;
if (get_ack(fd[0], result_sha1))
if (get_ack(fd[0], result_sha1)) {
if (verbose)
fprintf(stderr, "got ack\n");
return 0;
}
}
return retval;
}
/*
* Eventually we'll want to be able to fetch multiple heads.
*
* Right now we'll just require a single match.
*/
static int fetch_pack(int fd[2], int nr_match, char **match)
{
struct ref *ref;
@ -70,12 +86,8 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
packet_flush(fd[1]);
die("no matching remote head");
}
if (ref->next) {
packet_flush(fd[1]);
die("multiple remote heads");
}
if (find_common(fd, sha1, ref->old_sha1) < 0)
die("git-fetch-pack: no common commits");
if (find_common(fd, sha1, ref) < 0)
fprintf(stderr, "warning: no common commits\n");
pid = fork();
if (pid < 0)
die("git-fetch-pack: unable to fork off git-unpack-objects");
@ -97,7 +109,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
int code = WEXITSTATUS(status);
if (code)
die("git-unpack-objects died with error code %d", code);
puts(sha1_to_hex(ref->old_sha1));
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);
ref = ref->next;
}
return 0;
}
if (WIFSIGNALED(status)) {
@ -124,6 +140,14 @@ int main(int argc, char **argv)
exec = arg + 7;
continue;
}
if (!strcmp("-q", arg)) {
quiet = 1;
continue;
}
if (!strcmp("-v", arg)) {
verbose = 1;
continue;
}
usage(fetch_pack_usage);
}
dest = arg;

View file

@ -31,6 +31,10 @@ rsync://*)
;;
*)
head=$(git-fetch-pack "$merge_repo" "$merge_head")
if h=`expr "$head" : '\([^ ][^ ]*\) '`
then
head=$h
fi
;;
esac || exit 1