git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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;
 }
Previous: Linus TorvaldsNext: Johannes Schindelin
Message 7 of 10 in “fetch-pack should not ask for a ref which is already there”
  1. fetch-pack should not ask for a ref which is already thereJohannes Schindelin, Sep 28, 2005
  2. Junio C HamanoSep 29, 2005
  3. Johannes SchindelinSep 29, 2005
  4. Junio C HamanoSep 29, 2005
  5. Johannes SchindelinSep 29, 2005
  6. Linus TorvaldsSep 29, 2005
  7. Johannes SchindelinSep 29, 2005
  8. Johannes SchindelinSep 29, 2005
  9. Linus TorvaldsSep 29, 2005
  10. Johannes SchindelinSep 30, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.