Skip to content

Commit

Permalink
Make git-fetch-pack actually do all the unpacking etc.
Browse files Browse the repository at this point in the history
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
Linus Torvalds committed Jul 4, 2005
1 parent fb9040c commit 75bfc6c
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 25 deletions.
62 changes: 48 additions & 14 deletions fetch-pack.c
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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");
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
63 changes: 52 additions & 11 deletions upload-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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));
Expand All @@ -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;
Expand Down

0 comments on commit 75bfc6c

Please sign in to comment.