X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=send-pack.c;h=e9b9a39f411b6cfff1c0a4bc3f7e31274c8d2782;hb=edb6ddc53e71f4f959665cbc3180bb21b7ee7634;hp=33e69dbe1803a8667f383c1f0517867c873dafc4;hpb=eec102524fda2df7d2846e865805ca213119bf10;p=git.git diff --git a/send-pack.c b/send-pack.c index 33e69dbe1..e9b9a39f4 100644 --- a/send-pack.c +++ b/send-pack.c @@ -3,62 +3,53 @@ #include "tag.h" #include "refs.h" #include "pkt-line.h" -#include "exec_cmd.h" +#include "run-command.h" +#include "remote.h" static const char send_pack_usage[] = -"git-send-pack [--all] [--force] [--receive-pack=] [--verbose] [--thin] [:] [...]\n" +"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=] [--verbose] [--thin] [:] [...]\n" " --all and explicit specification are mutually exclusive."; static const char *receivepack = "git-receive-pack"; static int verbose; static int send_all; static int force_update; static int use_thin_pack; +static int dry_run; /* * Make a pack stream and spit it out into file descriptor fd */ static int pack_objects(int fd, struct ref *refs) { - int pipe_fd[2]; - pid_t pid; - - if (pipe(pipe_fd) < 0) - return error("send-pack: pipe failed"); - pid = fork(); - if (pid < 0) - return error("send-pack: unable to fork git-pack-objects"); - if (!pid) { - /* - * The child becomes pack-objects --revs; we feed - * the revision parameters to it via its stdin and - * let its stdout go back to the other end. - */ - static const char *args[] = { - "pack-objects", - "--all-progress", - "--revs", - "--stdout", - NULL, - NULL, - }; - if (use_thin_pack) - args[4] = "--thin"; - dup2(pipe_fd[0], 0); - dup2(fd, 1); - close(pipe_fd[0]); - close(pipe_fd[1]); - close(fd); - execv_git_cmd(args); - die("git-pack-objects exec failed (%s)", strerror(errno)); - } + /* + * The child becomes pack-objects --revs; we feed + * the revision parameters to it via its stdin and + * let its stdout go back to the other end. + */ + const char *args[] = { + "pack-objects", + "--all-progress", + "--revs", + "--stdout", + NULL, + NULL, + }; + struct child_process po; + + if (use_thin_pack) + args[4] = "--thin"; + memset(&po, 0, sizeof(po)); + po.argv = args; + po.in = -1; + po.out = fd; + po.git_cmd = 1; + if (start_command(&po)) + die("git-pack-objects failed (%s)", strerror(errno)); /* * We feed the pack-objects we just spawned with revision * parameters by writing to the pipe. */ - close(pipe_fd[0]); - close(fd); - while (refs) { char buf[42]; @@ -67,38 +58,23 @@ static int pack_objects(int fd, struct ref *refs) memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40); buf[0] = '^'; buf[41] = '\n'; - if (!write_or_whine(pipe_fd[1], buf, 42, + if (!write_or_whine(po.in, buf, 42, "send-pack: send refs")) break; } if (!is_null_sha1(refs->new_sha1)) { memcpy(buf, sha1_to_hex(refs->new_sha1), 40); buf[40] = '\n'; - if (!write_or_whine(pipe_fd[1], buf, 41, + if (!write_or_whine(po.in, buf, 41, "send-pack: send refs")) break; } refs = refs->next; } - close(pipe_fd[1]); - - for (;;) { - int status, code; - pid_t waiting = waitpid(pid, &status, 0); - if (waiting < 0) { - if (errno == EINTR) - continue; - return error("waitpid failed (%s)", strerror(errno)); - } - if ((waiting != pid) || WIFSIGNALED(status) || - !WIFEXITED(status)) - return error("pack-objects died with strange error"); - code = WEXITSTATUS(status); - if (code) - return -code; - return 0; - } + if (finish_command(&po)) + return error("pack-objects died with strange error"); + return 0; } static void unmark_and_free(struct commit_list *list, unsigned int mark) @@ -202,7 +178,7 @@ static int receive_status(int in) return ret; } -static int send_pack(int in, int out, int nr_refspec, char **refspec) +static int send_pack(int in, int out, struct remote *remote, int nr_refspec, char **refspec) { struct ref *ref; int new_refs; @@ -229,7 +205,8 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) return -1; if (!remote_refs) { - fprintf(stderr, "No refs in common and none specified; doing nothing.\n"); + fprintf(stderr, "No refs in common and none specified; doing nothing.\n" + "Perhaps you should specify a branch such as 'master'.\n"); return 0; } @@ -239,18 +216,19 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) new_refs = 0; for (ref = remote_refs; ref; ref = ref->next) { char old_hex[60], *new_hex; - int delete_ref; + int will_delete_ref; if (!ref->peer_ref) continue; - delete_ref = is_null_sha1(ref->peer_ref->new_sha1); - if (delete_ref && !allow_deleting_refs) { + + will_delete_ref = is_null_sha1(ref->peer_ref->new_sha1); + if (will_delete_ref && !allow_deleting_refs) { error("remote does not support deleting refs"); ret = -2; continue; } - if (!delete_ref && + if (!will_delete_ref && !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) { if (verbose) fprintf(stderr, "'%s': up-to-date\n", ref->name); @@ -277,7 +255,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) */ if (!force_update && - !delete_ref && + !will_delete_ref && !is_null_sha1(ref->old_sha1) && !ref->force) { if (!has_sha1_file(ref->old_sha1) || @@ -301,22 +279,24 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) } } hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); - if (!delete_ref) + if (!will_delete_ref) new_refs++; strcpy(old_hex, sha1_to_hex(ref->old_sha1)); new_hex = sha1_to_hex(ref->new_sha1); - if (ask_for_status_report) { - packet_write(out, "%s %s %s%c%s", - old_hex, new_hex, ref->name, 0, - "report-status"); - ask_for_status_report = 0; - expect_status_report = 1; + if (!dry_run) { + if (ask_for_status_report) { + packet_write(out, "%s %s %s%c%s", + old_hex, new_hex, ref->name, 0, + "report-status"); + ask_for_status_report = 0; + expect_status_report = 1; + } + else + packet_write(out, "%s %s %s", + old_hex, new_hex, ref->name); } - else - packet_write(out, "%s %s %s", - old_hex, new_hex, ref->name); - if (delete_ref) + if (will_delete_ref) fprintf(stderr, "deleting '%s'\n", ref->name); else { fprintf(stderr, "updating '%s'", ref->name); @@ -326,10 +306,26 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) fprintf(stderr, "\n from %s\n to %s\n", old_hex, new_hex); } + if (remote && !dry_run) { + struct refspec rs; + rs.src = ref->name; + rs.dst = NULL; + if (!remote_find_tracking(remote, &rs)) { + fprintf(stderr, " Also local %s\n", rs.dst); + if (will_delete_ref) { + if (delete_ref(rs.dst, NULL)) { + error("Failed to delete"); + } + } else + update_ref("update by push", rs.dst, + ref->new_sha1, NULL, 0, 0); + free(rs.dst); + } + } } packet_flush(out); - if (new_refs) + if (new_refs && !dry_run) ret = pack_objects(out, remote_refs); close(out); @@ -356,6 +352,7 @@ static void verify_remote_names(int nr_heads, char **heads) case -2: /* ok but a single level -- that is fine for * a match pattern. */ + case -3: /* ok but ends with a pattern-match character */ continue; } die("remote part of refspec is not a valid name in %s", @@ -370,6 +367,8 @@ int main(int argc, char **argv) char **heads = NULL; int fd[2], ret; pid_t pid; + char *remote_name = NULL; + struct remote *remote = NULL; setup_git_directory(); git_config(git_default_config); @@ -379,18 +378,26 @@ int main(int argc, char **argv) char *arg = *argv; if (*arg == '-') { - if (!strncmp(arg, "--receive-pack=", 15)) { + if (!prefixcmp(arg, "--receive-pack=")) { receivepack = arg + 15; continue; } - if (!strncmp(arg, "--exec=", 7)) { + if (!prefixcmp(arg, "--exec=")) { receivepack = arg + 7; continue; } + if (!prefixcmp(arg, "--remote=")) { + remote_name = arg + 9; + continue; + } if (!strcmp(arg, "--all")) { send_all = 1; continue; } + if (!strcmp(arg, "--dry-run")) { + dry_run = 1; + continue; + } if (!strcmp(arg, "--force")) { force_update = 1; continue; @@ -419,10 +426,18 @@ int main(int argc, char **argv) usage(send_pack_usage); verify_remote_names(nr_heads, heads); - pid = git_connect(fd, dest, receivepack); + if (remote_name) { + remote = remote_get(remote_name); + if (!remote_has_url(remote, dest)) { + die("Destination %s is not a uri for %s", + dest, remote_name); + } + } + + pid = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0); if (pid < 0) return 1; - ret = send_pack(fd[0], fd[1], nr_heads, heads); + ret = send_pack(fd[0], fd[1], remote, nr_heads, heads); close(fd[0]); close(fd[1]); ret |= finish_connect(pid);