On Sat, May 20, 2006 at 11:17:42PM -0700, Junio C Hamano wrote: > base delta for that object to skip computation". What you want > here is "if the object we are going to send is not a delta in > the source, and there are sufficient number of other objects the > object could have been deltified against, then it is very likely > that it was not worth deltifying when it was packed; so it is > probably not worth deltifying it now". I think we can make a stronger statement in many cases: "if the object we are going to send is not a delta in the source, and there are no other objects it could be deltified against, then it is not worth deltifying." That is, in the case that we just packed we KNOW that it's not worth it, since we're not sending anything that isn't already packed. Following this logic, I believe we could always turn off deltification if there are no loose objects. It seems a bit special case, but it optimizes the "repack -d then push" workflow which I suspect may be relatively common. The patch below runs git-rev-list with --unpacked; if there are no objects returned, it tells pack-objects to set depth=0 (is that really what we want? It's OK to use existing deltas; we just don't want to compute any new ones. I'm not sure how --depth behaves in that respect). -Peff --- f3e7fb4a5025cc8157557f3da6f9dc7d0a89395f send-pack.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 58 insertions(+), 14 deletions(-) f3e7fb4a5025cc8157557f3da6f9dc7d0a89395f diff --git a/send-pack.c b/send-pack.c index 409f188..0bddc0a 100644 --- a/send-pack.c +++ b/send-pack.c @@ -25,18 +25,7 @@ static int is_zero_sha1(const unsigned c return 1; } -static void exec_pack_objects(void) -{ - static const char *args[] = { - "pack-objects", - "--stdout", - NULL - }; - execv_git_cmd(args); - die("git-pack-objects exec failed (%s)", strerror(errno)); -} - -static void exec_rev_list(struct ref *refs) +static void exec_rev_list(struct ref *refs, int unpacked) { struct ref *ref; static const char *args[1000]; @@ -47,6 +36,8 @@ static void exec_rev_list(struct ref *re args[i++] = "--objects-edge"; else args[i++] = "--objects"; + if(unpacked) + args[i++] = "--unpacked"; /* First send the ones we care about most */ for (ref = refs; ref; ref = ref->next) { @@ -85,6 +76,59 @@ static void exec_rev_list(struct ref *re die("git-rev-list exec failed (%s)", strerror(errno)); } +static int rev_list_loose_objects(struct ref *refs) +{ + int fd[2]; + pid_t pid; + + if(pipe(fd) < 0) + die("rev-list setup: pipe failed"); + pid = fork(); + if(pid < 0) + die("rev-list setup: fork failed"); + if(!pid) { + dup2(fd[1], 1); + close(fd[0]); + close(fd[1]); + exec_rev_list(refs, 1); + die("rev-list failed"); + } + close(fd[1]); + return fd[0]; +} + +static int count_loose_objects(struct ref *refs) +{ + int fd = rev_list_loose_objects(refs); + unsigned count = 0; + char buf[4096]; + int len; + + while((len = read(fd, buf, sizeof buf)) > 0) { + int i; + for(i = 0; i < len; i++) + if(buf[i] == '\n') + count++; + } + if(len < 0) + die("rev-list read failed"); + return count; +} + +static void exec_pack_objects(struct ref *refs) +{ + static const char *args[] = { + "pack-objects", + "--stdout", + NULL, + NULL + }; + if(count_loose_objects(refs) == 0) + args[2] = "--depth=0"; + execv_git_cmd(args); + die("git-pack-objects exec failed (%s)", strerror(errno)); +} + static void rev_list(int fd, struct ref *refs) { int pipe_fd[2]; @@ -99,7 +143,7 @@ static void rev_list(int fd, struct ref close(pipe_fd[0]); close(pipe_fd[1]); close(fd); - exec_pack_objects(); + exec_pack_objects(refs); die("pack-objects setup failed"); } if (pack_objects_pid < 0) @@ -108,7 +152,7 @@ static void rev_list(int fd, struct ref close(pipe_fd[0]); close(pipe_fd[1]); close(fd); - exec_rev_list(refs); + exec_rev_list(refs, 0); } static int pack_objects(int fd, struct ref *refs) -- 1.3.3.gf1cf-dirty - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html