Merge branch 'ph/push-to-delete-nothing'
authorJunio C Hamano <gitster@pobox.com>
Tue, 18 Oct 2011 04:37:10 +0000 (21:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Oct 2011 04:37:10 +0000 (21:37 -0700)
* ph/push-to-delete-nothing:
receive-pack: don't pass non-existent refs to post-{receive,update} hooks

Conflicts:
builtin/receive-pack.c

1  2 
builtin/receive-pack.c
diff --combined builtin/receive-pack.c
index e2d3f94661ffd89e08a1bf0e52ff07b366612b65,b73f18a57bf44eaab0465f5236009d4f004df595..261b610d24017557c137d83a9c005b662e795b6a
@@@ -11,7 -11,6 +11,7 @@@
  #include "transport.h"
  #include "string-list.h"
  #include "sha1-array.h"
 +#include "connected.h"
  
  static const char receive_pack_usage[] = "git receive-pack <git-dir>";
  
@@@ -26,8 -25,7 +26,8 @@@ static int deny_deletes
  static int deny_non_fast_forwards;
  static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
  static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
 -static int receive_fsck_objects;
 +static int receive_fsck_objects = -1;
 +static int transfer_fsck_objects = -1;
  static int receive_unpack_limit = -1;
  static int transfer_unpack_limit = -1;
  static int unpack_limit = 100;
@@@ -81,11 -79,6 +81,11 @@@ static int receive_pack_config(const ch
                return 0;
        }
  
 +      if (strcmp(var, "transfer.fsckobjects") == 0) {
 +              transfer_fsck_objects = git_config_bool(var, value);
 +              return 0;
 +      }
 +
        if (!strcmp(var, "receive.denycurrentbranch")) {
                deny_current_branch = parse_deny_action(var, value);
                return 0;
@@@ -154,7 -147,8 +154,8 @@@ static void write_head_info(void
  struct command {
        struct command *next;
        const char *error_string;
-       unsigned int skip_update;
+       unsigned int skip_update:1,
+                    did_not_exist:1;
        unsigned char old_sha1[20];
        unsigned char new_sha1[20];
        char ref_name[FLEX_ARRAY]; /* more */
@@@ -212,15 -206,21 +213,15 @@@ static int copy_to_sideband(int in, in
        return 0;
  }
  
 -static int run_receive_hook(struct command *commands, const char *hook_name)
 +typedef int (*feed_fn)(void *, const char **, size_t *);
 +static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
  {
 -      static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
 -      struct command *cmd;
        struct child_process proc;
        struct async muxer;
        const char *argv[2];
 -      int have_input = 0, code;
 -
 -      for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
 -              if (!cmd->error_string && !cmd->did_not_exist)
 -                      have_input = 1;
 -      }
 +      int code;
  
 -      if (!have_input || access(hook_name, X_OK) < 0)
 +      if (access(hook_name, X_OK) < 0)
                return 0;
  
        argv[0] = hook_name;
                return code;
        }
  
 -      for (cmd = commands; cmd; cmd = cmd->next) {
 -              if (!cmd->error_string && !cmd->did_not_exist) {
 -                      size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
 -                              sha1_to_hex(cmd->old_sha1),
 -                              sha1_to_hex(cmd->new_sha1),
 -                              cmd->ref_name);
 -                      if (write_in_full(proc.in, buf, n) != n)
 -                              break;
 -              }
 +      while (1) {
 +              const char *buf;
 +              size_t n;
 +              if (feed(feed_state, &buf, &n))
 +                      break;
 +              if (write_in_full(proc.in, buf, n) != n)
 +                      break;
        }
        close(proc.in);
        if (use_sideband)
        return finish_command(&proc);
  }
  
-       while (cmd && cmd->error_string)
 +struct receive_hook_feed_state {
 +      struct command *cmd;
++      int skip_broken;
 +      struct strbuf buf;
 +};
 +
 +static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
 +{
 +      struct receive_hook_feed_state *state = state_;
 +      struct command *cmd = state->cmd;
 +
- static int run_receive_hook(struct command *commands, const char *hook_name)
++      while (cmd &&
++             state->skip_broken && (cmd->error_string || cmd->did_not_exist))
 +              cmd = cmd->next;
 +      if (!cmd)
 +              return -1; /* EOF */
 +      strbuf_reset(&state->buf);
 +      strbuf_addf(&state->buf, "%s %s %s\n",
 +                  sha1_to_hex(cmd->old_sha1), sha1_to_hex(cmd->new_sha1),
 +                  cmd->ref_name);
 +      state->cmd = cmd->next;
 +      if (bufp) {
 +              *bufp = state->buf.buf;
 +              *sizep = state->buf.len;
 +      }
 +      return 0;
 +}
 +
++static int run_receive_hook(struct command *commands, const char *hook_name,
++                          int skip_broken)
 +{
 +      struct receive_hook_feed_state state;
 +      int status;
 +
 +      strbuf_init(&state.buf, 0);
 +      state.cmd = commands;
++      state.skip_broken = skip_broken;
 +      if (feed_receive_hook(&state, NULL, NULL))
 +              return 0;
 +      state.cmd = commands;
 +      status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
 +      strbuf_release(&state.buf);
 +      return status;
 +}
 +
  static int run_update_hook(struct command *cmd)
  {
        static const char update_hook[] = "hooks/update";
@@@ -396,7 -357,7 +401,7 @@@ static const char *update(struct comman
        struct ref_lock *lock;
  
        /* only refs/... are allowed */
 -      if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
 +      if (prefixcmp(name, "refs/") || check_refname_format(name + 5, 0)) {
                rp_error("refusing to create funny ref '%s' remotely", name);
                return "funny refname";
        }
  
        if (is_null_sha1(new_sha1)) {
                if (!parse_object(old_sha1)) {
-                       rp_warning("Allowing deletion of corrupt ref.");
                        old_sha1 = NULL;
+                       if (ref_exists(name)) {
+                               rp_warning("Allowing deletion of corrupt ref.");
+                       } else {
+                               rp_warning("Deleting a non-existent ref.");
+                               cmd->did_not_exist = 1;
+                       }
                }
                if (delete_ref(namespaced_name, old_sha1, 0)) {
                        rp_error("failed to delete %s", name);
@@@ -517,7 -483,7 +527,7 @@@ static void run_update_post_hook(struc
        struct child_process proc;
  
        for (argc = 0, cmd = commands; cmd; cmd = cmd->next) {
-               if (cmd->error_string)
+               if (cmd->error_string || cmd->did_not_exist)
                        continue;
                argc++;
        }
  
        for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
                char *p;
-               if (cmd->error_string)
+               if (cmd->error_string || cmd->did_not_exist)
                        continue;
                p = xmalloc(strlen(cmd->ref_name) + 1);
                strcpy(p, cmd->ref_name);
@@@ -619,43 -585,6 +629,43 @@@ static void check_aliased_updates(struc
        string_list_clear(&ref_list, 0);
  }
  
 +static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
 +{
 +      struct command **cmd_list = cb_data;
 +      struct command *cmd = *cmd_list;
 +
 +      if (!cmd)
 +              return -1; /* end of list */
 +      *cmd_list = NULL; /* this returns only one */
 +      hashcpy(sha1, cmd->new_sha1);
 +      return 0;
 +}
 +
 +static void set_connectivity_errors(struct command *commands)
 +{
 +      struct command *cmd;
 +
 +      for (cmd = commands; cmd; cmd = cmd->next) {
 +              struct command *singleton = cmd;
 +              if (!check_everything_connected(command_singleton_iterator,
 +                                              0, &singleton))
 +                      continue;
 +              cmd->error_string = "missing necessary objects";
 +      }
 +}
 +
 +static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
 +{
 +      struct command **cmd_list = cb_data;
 +      struct command *cmd = *cmd_list;
 +
 +      if (!cmd)
 +              return -1; /* end of list */
 +      *cmd_list = cmd->next;
 +      hashcpy(sha1, cmd->new_sha1);
 +      return 0;
 +}
 +
  static void execute_commands(struct command *commands, const char *unpacker_error)
  {
        struct command *cmd;
                return;
        }
  
 -      if (run_receive_hook(commands, pre_receive_hook)) {
 +      cmd = commands;
 +      if (check_everything_connected(iterate_receive_command_list,
 +                                     0, &cmd))
 +              set_connectivity_errors(commands);
 +
-       if (run_receive_hook(commands, pre_receive_hook)) {
++      if (run_receive_hook(commands, pre_receive_hook, 0)) {
                for (cmd = commands; cmd; cmd = cmd->next)
                        cmd->error_string = "pre-receive hook declined";
                return;
@@@ -756,11 -680,6 +766,11 @@@ static const char *unpack(void
        struct pack_header hdr;
        const char *hdr_err;
        char hdr_arg[38];
 +      int fsck_objects = (receive_fsck_objects >= 0
 +                          ? receive_fsck_objects
 +                          : transfer_fsck_objects >= 0
 +                          ? transfer_fsck_objects
 +                          : 0);
  
        hdr_err = parse_pack_header(&hdr);
        if (hdr_err)
                int code, i = 0;
                const char *unpacker[4];
                unpacker[i++] = "unpack-objects";
 -              if (receive_fsck_objects)
 +              if (fsck_objects)
                        unpacker[i++] = "--strict";
                unpacker[i++] = hdr_arg;
                unpacker[i++] = NULL;
  
                keeper[i++] = "index-pack";
                keeper[i++] = "--stdin";
 -              if (receive_fsck_objects)
 +              if (fsck_objects)
                        keeper[i++] = "--strict";
                keeper[i++] = "--fix-thin";
                keeper[i++] = hdr_arg;
@@@ -940,7 -859,7 +950,7 @@@ int cmd_receive_pack(int argc, const ch
                        unlink_or_warn(pack_lockfile);
                if (report_status)
                        report(commands, unpack_status);
--              run_receive_hook(commands, post_receive_hook);
++              run_receive_hook(commands, post_receive_hook, 1);
                run_update_post_hook(commands);
                if (auto_gc) {
                        const char *argv_gc_auto[] = {