Re: [PATCH] fetch-pack should not ask for a ref which is already there
- From
Johannes Schindelin <johannes.schindelin@gmx.de>
- Date
- Sep 29, 2005, 19:08 UTC
- Message-ID
- <Pine.LNX.4.63.0509292058020.8413@wgmdd8.biozentrum.uni-wuerzburg.de>
- In-Reply-To
- <Pine.LNX.4.58.0509291120170.3308@g5.osdl.org>
Hi,
On Thu, 29 Sep 2005, Linus Torvalds wrote:
Show 6 quoted lines
> On Thu, 29 Sep 2005, Johannes Schindelin wrote: > > > > With this patch, instead of blindly asking for every remote ref, fetch-pack > > first looks in the local repository if that ref is already there. > > No. This is WRONG.
Actually, this is not wrong. The patch is wrong. Here's why:
> The "fetch" semantics are simple: we only write out new refs _after_ we've > fetched all the objects that point to them. That means that while we > cannot trust a "oh, I already have this commit, let's skip it", we _can_ > trust "oh, I already have these refs, let's skip them".
What the commit message should suggest was: if a local ref is identical to the remote ref, do not "want" it. But of course, I got it all wrong. BTW this patch is not to annoy you, but to ease the burden on the server for git-daemon. (Many a developer begins the day by fetching the latest and greatest).
The correct way to go about it would be to check that
$(git-rev-list <remote_ref> $(git-rev-parse --all | sed "s/^/^/"))
is empty. However, I am lazy, and in most cases, it is sufficient to check if the remote ref is identical to a local ref. So here goes another try:
[PATCH] fetch-pack should not ask for a ref which is already there
With this patch, instead of blindly asking for every remote ref, fetch-pack first looks in the local repository if that ref is already a local ref.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
fetch-pack.c | 72 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 52 insertions(+), 20 deletions(-)
edfbae3927434270c35dfcad417e7d202e509e90
diff --git a/fetch-pack.c b/fetch-pack.c --- a/fetch-pack.c +++ b/fetch-pack.c @@ -9,6 +9,22 @@ 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 has_ref_flag; +static const unsigned char *has_ref_sha1; + +static int has_ref_helper(const char *path, const unsigned char *sha1) { + if(!memcmp(sha1, has_ref_sha1, 20)) + has_ref_flag = 1; + return has_ref_flag; +} + +static int has_ref(const unsigned char *sha1) { + has_ref_sha1 = sha1; + has_ref_flag = 0; + for_each_ref(has_ref_helper); + return has_ref_flag; +} + static int find_common(int fd[2], unsigned char *result_sha1, struct ref *refs) { @@ -16,20 +32,27 @@ static int find_common(int fd[2], unsign int count = 0, flushes = 0, retval; FILE *revs; - revs = popen("git-rev-list $(git-rev-parse --all)", "r"); - if (!revs) - die("unable to run 'git-rev-list'"); - 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)); + if(!has_ref(remote)) { + 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)); + count++; + } refs = refs->next; } packet_flush(fd[1]); + + if(count==0) + return 1; + + revs = popen("git-rev-list $(git-rev-parse --all)", "r"); + if (!revs) + die("unable to run 'git-rev-list'"); + flushes = 1; retval = -1; while (fgets(line, sizeof(line), revs) != NULL) { @@ -74,7 +97,7 @@ static int find_common(int fd[2], unsign return retval; } -static int fetch_pack(int fd[2], int nr_match, char **match) +static struct ref *fetch_pack(int fd[2], int nr_match, char **match) { struct ref *ref; unsigned char sha1[20]; @@ -86,7 +109,10 @@ static int fetch_pack(int fd[2], int nr_ packet_flush(fd[1]); die("no matching remote head"); } - if (find_common(fd, sha1, ref) < 0) + status = find_common(fd, sha1, ref); + if(status > 0) + return ref; + if(status < 0) fprintf(stderr, "warning: no common commits\n"); pid = fork(); if (pid < 0) @@ -109,12 +135,7 @@ static int fetch_pack(int fd[2], int nr_ int code = WEXITSTATUS(status); if (code) die("git-unpack-objects died with error code %d", code); - while (ref) { - printf("%s %s\n", - sha1_to_hex(ref->old_sha1), ref->name); - ref = ref->next; - } - return 0; + return ref; } if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); @@ -125,10 +146,11 @@ static int fetch_pack(int fd[2], int nr_ int main(int argc, char **argv) { - int i, ret, nr_heads; + int i, nr_heads; char *dest = NULL, **heads; int fd[2]; pid_t pid; + struct ref *ref; nr_heads = 0; heads = NULL; @@ -160,9 +182,19 @@ int main(int argc, char **argv) pid = git_connect(fd, dest, exec); if (pid < 0) return 1; - ret = fetch_pack(fd, nr_heads, heads); + ref = fetch_pack(fd, nr_heads, heads); + if(!ref) + return 1; + + while (ref) { + printf("%s %s\n", + sha1_to_hex(ref->old_sha1), ref->name); + ref = ref->next; + } + close(fd[0]); close(fd[1]); finish_connect(pid); - return ret; + + return 0; }