Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Make git-fetch-pack actually do all the unpacking etc.

It returns the result SHA1 on stdout, so you can do

	remote=$(git-fetch-pack host:dir branchname)

and it will unpack the objects and "remote" will be the SHA1 name of the
branch on the other side.  You can then save that off, or merge it, or
whatever.
  • Loading branch information...
commit 75bfc6c232689ae06aba6a7d4aa15ac2791d9a11 1 parent fb9040c
Linus Torvalds authored
Showing with 100 additions and 25 deletions.
  1. +48 −14 fetch-pack.c
  2. +52 −11 upload-pack.c
View
62 fetch-pack.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
+#include <sys/wait.h>
static const char fetch_pack_usage[] = "git-fetch-pack [host:]directory [heads]* < mycommitlist";
static const char *exec = "git-upload-pack";
@@ -26,11 +27,17 @@ static int get_ack(int fd, unsigned char *result_sha1)
static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *remote)
{
static char line[1000];
- int count = 0, flushes = 0;
+ 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'");
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
packet_flush(fd[1]);
- while (fgets(line, sizeof(line), stdin) != NULL) {
+ flushes = 1;
+ retval = -1;
+ while (fgets(line, sizeof(line), revs) != NULL) {
unsigned char sha1[20];
if (get_sha1_hex(line, sha1))
die("git-fetch-pack: expected object name, got crud");
@@ -45,19 +52,22 @@ static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *rem
*/
if (count == 32)
continue;
- if (get_ack(fd[0], result_sha1))
- return 0;
+ if (get_ack(fd[0], result_sha1)) {
+ flushes = 0;
+ retval = 0;
+ break;
+ }
flushes--;
}
}
- flushes++;
- packet_flush(fd[1]);
+ pclose(revs);
+ packet_write(fd[1], "done\n");
while (flushes) {
flushes--;
if (get_ack(fd[0], result_sha1))
return 0;
}
- return -1;
+ return retval;
}
static int get_old_sha1(const char *refname, unsigned char *sha1)
@@ -88,12 +98,12 @@ static int check_ref(const char *refname, const unsigned char *sha1)
memset(mysha1, 0, 20);
if (!memcmp(sha1, mysha1, 20)) {
- printf("%s: unchanged\n", refname);
+ fprintf(stderr, "%s: unchanged\n", refname);
return 0;
}
memcpy(oldhex, sha1_to_hex(mysha1), 41);
- printf("%s: %s (%s)\n", refname, sha1_to_hex(sha1), oldhex);
+ fprintf(stderr, "%s: %s (%s)\n", refname, sha1_to_hex(sha1), oldhex);
return 1;
}
@@ -128,7 +138,8 @@ static int get_remote_heads(int fd, int nr_match, char **match, unsigned char *r
static int fetch_pack(int fd[2], int nr_match, char **match)
{
unsigned char sha1[20], remote[20];
- int heads;
+ int heads, status;
+ pid_t pid;
heads = get_remote_heads(fd[0], nr_match, match, remote);
if (heads != 1) {
@@ -137,11 +148,34 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
}
if (find_common(fd, sha1, remote) < 0)
die("git-fetch-pack: no common commits");
- close(fd[1]);
- dup2(fd[0], 0);
+ pid = fork();
+ if (pid < 0)
+ die("git-fetch-pack: unable to fork off git-unpack-objects");
+ if (!pid) {
+ close(fd[1]);
+ dup2(fd[0], 0);
+ close(fd[0]);
+ execlp("git-unpack-objects", "git-unpack-objects", NULL);
+ die("git-unpack-objects exec failed");
+ }
close(fd[0]);
- execlp("git-unpack-objects", "git-unpack-objects", NULL);
- die("git-unpack-objects exec failed");
+ close(fd[1]);
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR)
+ die("waiting for git-unpack-objects: %s", strerror(errno));
+ }
+ if (WIFEXITED(status)) {
+ int code = WEXITSTATUS(status);
+ if (code)
+ die("git-unpack-objects died with error code %d", code);
+ puts(sha1_to_hex(remote));
+ return 0;
+ }
+ if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+ die("git-unpack-objects died of signal %d", sig);
+ }
+ die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
}
int main(int argc, char **argv)
View
63 upload-pack.c
@@ -10,16 +10,57 @@ static int nr_has = 0, nr_needs = 0;
static unsigned char has_sha1[MAX_HAS][20];
static unsigned char needs_sha1[MAX_NEEDS][20];
+static int strip(char *line, int len)
+{
+ if (len && line[len-1] == '\n')
+ line[--len] = 0;
+ return len;
+}
+
static void create_pack_file(void)
{
- /*
- * Here, we should do
- *
- * git-rev-list --objects needs_sha1 --not has_sha1 |
- * git-pack-objects --stdout
- *
- * but we don't.
- */
+ int fd[2];
+ pid_t pid;
+
+ if (pipe(fd) < 0)
+ die("git-upload-pack: unable to create pipe");
+ pid = fork();
+ if (pid < 0)
+ die("git-upload-pack: unable to fork git-rev-list");
+
+ if (!pid) {
+ int i;
+ int args = nr_has + nr_needs + 5;
+ char **argv = xmalloc(args * sizeof(char *));
+ char *buf = xmalloc(args * 45);
+ char **p = argv;
+
+ dup2(fd[1], 1);
+ close(0);
+ close(fd[0]);
+ close(fd[1]);
+ *p++ = "git-rev-list";
+ *p++ = "--objects";
+ for (i = 0; i < nr_needs; i++) {
+ *p++ = buf;
+ memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
+ buf += 41;
+ }
+ for (i = 0; i < nr_has; i++) {
+ *p++ = buf;
+ *buf++ = '^';
+ memcpy(buf, sha1_to_hex(has_sha1[i]), 41);
+ buf += 41;
+ }
+ *p++ = NULL;
+ execvp("git-rev-list", argv);
+ die("git-upload-pack: unable to exec git-rev-list");
+ }
+ dup2(fd[0], 0);
+ close(fd[0]);
+ close(fd[1]);
+ execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL);
+ die("git-upload-pack: unable to exec git-pack-objects");
}
static int got_sha1(char *hex, unsigned char *sha1)
@@ -50,8 +91,7 @@ static int get_common_commits(void)
packet_write(1, "NAK\n");
continue;
}
- if (line[len-1] == '\n')
- line[--len] = 0;
+ len = strip(line, len);
if (!strncmp(line, "have ", 5)) {
if (got_sha1(line+5, sha1)) {
packet_write(1, "ACK %s\n", sha1_to_hex(sha1));
@@ -69,7 +109,8 @@ static int get_common_commits(void)
for (;;) {
len = packet_read_line(0, line, sizeof(line));
if (!len)
- break;
+ continue;
+ len = strip(line, len);
if (!strncmp(line, "have ", 5)) {
got_sha1(line+5, sha1);
continue;
Please sign in to comment.
Something went wrong with that request. Please try again.