Merge branch 'rs/pop-commit'
authorJunio C Hamano <gitster@pobox.com>
Fri, 30 Oct 2015 20:07:03 +0000 (13:07 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 30 Oct 2015 20:07:03 +0000 (13:07 -0700)
Code simplification.

* rs/pop-commit:
use pop_commit() for consuming the first entry of a struct commit_list

1  2 
builtin/fmt-merge-msg.c
builtin/merge.c
builtin/reflog.c
builtin/show-branch.c
commit.c
remote.c
revision.c
shallow.c
diff --combined builtin/fmt-merge-msg.c
index 4ba7f282a5f6cd2e0af643f865a34c3048f2f591,46c92c174fd06ba5e0b2a06dec13733842bb48f3..846004b83358cd8adfd5f7de96b2d551700037a1
@@@ -1,6 -1,5 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
 +#include "refs.h"
  #include "commit.h"
  #include "diff.h"
  #include "revision.h"
@@@ -537,7 -536,7 +537,7 @@@ static void fmt_merge_msg_sigs(struct s
  static void find_merge_parents(struct merge_parents *result,
                               struct strbuf *in, unsigned char *head)
  {
-       struct commit_list *parents, *next;
+       struct commit_list *parents;
        struct commit *head_commit;
        int pos = 0, i, j;
  
        parents = reduce_heads(parents);
  
        while (parents) {
+               struct commit *cmit = pop_commit(&parents);
                for (i = 0; i < result->nr; i++)
-                       if (!hashcmp(result->item[i].commit,
-                                    parents->item->object.sha1))
+                       if (!hashcmp(result->item[i].commit, cmit->object.sha1))
                                result->item[i].used = 1;
-               next = parents->next;
-               free(parents);
-               parents = next;
        }
  
        for (i = j = 0; i < result->nr; i++) {
diff --combined builtin/merge.c
index 977ffff2876de4d817025bbf6d11ec251b674141,63563b9ab00025cee466939bf000eb5b3a806d85..bbf3110f88ae118065da4994de63f345cf414ba7
@@@ -231,9 -231,9 +231,9 @@@ static struct option builtin_merge_opti
  /* Cleans up metadata that is uninteresting after a succeeded merge. */
  static void drop_save(void)
  {
 -      unlink(git_path("MERGE_HEAD"));
 -      unlink(git_path("MERGE_MSG"));
 -      unlink(git_path("MERGE_MODE"));
 +      unlink(git_path_merge_head());
 +      unlink(git_path_merge_msg());
 +      unlink(git_path_merge_mode());
  }
  
  static int save_state(unsigned char *stash)
@@@ -338,7 -338,7 +338,7 @@@ static void squash_message(struct commi
        struct pretty_print_context ctx = {0};
  
        printf(_("Squash commit -- not updating HEAD\n"));
 -      filename = git_path("SQUASH_MSG");
 +      filename = git_path_squash_msg();
        fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not write to '%s'"), filename);
@@@ -754,7 -754,7 +754,7 @@@ static void add_strategies(const char *
  
  static void write_merge_msg(struct strbuf *msg)
  {
 -      const char *filename = git_path("MERGE_MSG");
 +      const char *filename = git_path_merge_msg();
        int fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"),
  
  static void read_merge_msg(struct strbuf *msg)
  {
 -      const char *filename = git_path("MERGE_MSG");
 +      const char *filename = git_path_merge_msg();
        strbuf_reset(msg);
        if (strbuf_read_file(msg, filename, 0) < 0)
                die_errno(_("Could not read from '%s'"), filename);
@@@ -799,14 -799,14 +799,14 @@@ static void prepare_to_commit(struct co
                strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
        write_merge_msg(&msg);
        if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
 -                          git_path("MERGE_MSG"), "merge", NULL))
 +                          git_path_merge_msg(), "merge", NULL))
                abort_commit(remoteheads, NULL);
        if (0 < option_edit) {
 -              if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
 +              if (launch_editor(git_path_merge_msg(), NULL, NULL))
                        abort_commit(remoteheads, NULL);
        }
        read_merge_msg(&msg);
 -      stripspace(&msg, 0 < option_edit);
 +      strbuf_stripspace(&msg, 0 < option_edit);
        if (!msg.len)
                abort_commit(remoteheads, _("Empty commit message."));
        strbuf_release(&merge_msg);
@@@ -865,7 -865,7 +865,7 @@@ static int suggest_conflicts(void
        FILE *fp;
        struct strbuf msgbuf = STRBUF_INIT;
  
 -      filename = git_path("MERGE_MSG");
 +      filename = git_path_merge_msg();
        fp = fopen(filename, "a");
        if (!fp)
                die_errno(_("Could not open '%s' for writing"), filename);
@@@ -967,7 -967,7 +967,7 @@@ static void write_merge_state(struct co
                }
                strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
        }
 -      filename = git_path("MERGE_HEAD");
 +      filename = git_path_merge_head();
        fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"), filename);
        strbuf_addch(&merge_msg, '\n');
        write_merge_msg(&merge_msg);
  
 -      filename = git_path("MERGE_MODE");
 +      filename = git_path_merge_mode();
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"), filename);
@@@ -1019,7 -1019,7 +1019,7 @@@ static struct commit_list *reduce_paren
                                          int *head_subsumed,
                                          struct commit_list *remoteheads)
  {
-       struct commit_list *parents, *next, **remotes = &remoteheads;
+       struct commit_list *parents, **remotes;
  
        /*
         * Is the current HEAD reachable from another commit being
        /* Find what parents to record by checking independent ones. */
        parents = reduce_heads(remoteheads);
  
-       for (remoteheads = NULL, remotes = &remoteheads;
-            parents;
-            parents = next) {
-               struct commit *commit = parents->item;
-               next = parents->next;
+       remoteheads = NULL;
+       remotes = &remoteheads;
+       while (parents) {
+               struct commit *commit = pop_commit(&parents);
                if (commit == head_commit)
                        *head_subsumed = 0;
                else
                        remotes = &commit_list_insert(commit, remotes)->next;
-               free(parents);
        }
        return remoteheads;
  }
@@@ -1070,7 -1068,7 +1068,7 @@@ static void handle_fetch_head(struct co
        if (!merge_names)
                merge_names = &fetch_head_file;
  
 -      filename = git_path("FETCH_HEAD");
 +      filename = git_path_fetch_head();
        fd = open(filename, O_RDONLY);
        if (fd < 0)
                die_errno(_("could not open '%s' for reading"), filename);
@@@ -1204,7 -1202,7 +1202,7 @@@ int cmd_merge(int argc, const char **ar
                int nargc = 2;
                const char *nargv[] = {"reset", "--merge", NULL};
  
 -              if (!file_exists(git_path("MERGE_HEAD")))
 +              if (!file_exists(git_path_merge_head()))
                        die(_("There is no merge to abort (MERGE_HEAD missing)."));
  
                /* Invoke 'git reset --merge' */
        if (read_cache_unmerged())
                die_resolve_conflict("merge");
  
 -      if (file_exists(git_path("MERGE_HEAD"))) {
 +      if (file_exists(git_path_merge_head())) {
                /*
                 * There is no unmerged entry, don't advise 'git
                 * add/rm <file>', just 'git commit'.
                else
                        die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
 -      if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
 +      if (file_exists(git_path_cherry_pick_head())) {
                if (advice_resolve_conflict)
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
                            "Please, commit your changes before you merge."));
        if (verify_signatures) {
                for (p = remoteheads; p; p = p->next) {
                        struct commit *commit = p->item;
 -                      char hex[41];
 +                      char hex[GIT_SHA1_HEXSZ + 1];
                        struct signature_check signature_check;
                        memset(&signature_check, 0, sizeof(signature_check));
  
                        check_commit_signature(commit, &signature_check);
  
 -                      strcpy(hex, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 +                      find_unique_abbrev_r(hex, commit->object.sha1, DEFAULT_ABBREV);
                        switch (signature_check.result) {
                        case 'G':
                                break;
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct commit *commit;
 -              char hex[41];
  
 -              strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
 -
 -              if (verbosity >= 0)
 -                      printf(_("Updating %s..%s\n"),
 -                              hex,
 -                              find_unique_abbrev(remoteheads->item->object.sha1,
 -                              DEFAULT_ABBREV));
 +              if (verbosity >= 0) {
 +                      char from[GIT_SHA1_HEXSZ + 1], to[GIT_SHA1_HEXSZ + 1];
 +                      find_unique_abbrev_r(from, head_commit->object.sha1,
 +                                            DEFAULT_ABBREV);
 +                      find_unique_abbrev_r(to, remoteheads->item->object.sha1,
 +                                            DEFAULT_ABBREV);
 +                      printf(_("Updating %s..%s\n"), from, to);
 +              }
                strbuf_addstr(&msg, "Fast-forward");
                if (have_message)
                        strbuf_addstr(&msg,
diff --combined builtin/reflog.c
index f96ca2a27dcb9ac6daa3aa110ff657981296502a,fa841b500bcb006265c72b5f6a553b3ac24fa980..cf1145e635c559206a6b0d61e41321fa914e5e42
@@@ -13,8 -13,6 +13,8 @@@ static const char reflog_expire_usage[
  "git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
  static const char reflog_delete_usage[] =
  "git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
 +static const char reflog_exists_usage[] =
 +"git reflog exists <ref>";
  
  static unsigned long default_reflog_expire;
  static unsigned long default_reflog_expire_unreachable;
@@@ -218,7 -216,6 +218,6 @@@ static int keep_entry(struct commit **i
   */
  static void mark_reachable(struct expire_reflog_policy_cb *cb)
  {
-       struct commit *commit;
        struct commit_list *pending;
        unsigned long expire_limit = cb->mark_limit;
        struct commit_list *leftover = NULL;
  
        pending = cb->mark_list;
        while (pending) {
-               struct commit_list *entry = pending;
                struct commit_list *parent;
-               pending = entry->next;
-               commit = entry->item;
-               free(entry);
+               struct commit *commit = pop_commit(&pending);
                if (commit->object.flags & REACHABLE)
                        continue;
                if (parse_commit(commit))
@@@ -429,7 -423,7 +425,7 @@@ static int parse_expire_cfg_value(cons
        if (!value)
                return config_error_nonbool(var);
        if (parse_expiry_date(value, expire))
 -              return error(_("%s' for '%s' is not a valid timestamp"),
 +              return error(_("'%s' for '%s' is not a valid timestamp"),
                             value, var);
        return 0;
  }
@@@ -701,38 -695,12 +697,38 @@@ static int cmd_reflog_delete(int argc, 
        return status;
  }
  
 +static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
 +{
 +      int i, start = 0;
 +
 +      for (i = 1; i < argc; i++) {
 +              const char *arg = argv[i];
 +              if (!strcmp(arg, "--")) {
 +                      i++;
 +                      break;
 +              }
 +              else if (arg[0] == '-')
 +                      usage(reflog_exists_usage);
 +              else
 +                      break;
 +      }
 +
 +      start = i;
 +
 +      if (argc - start != 1)
 +              usage(reflog_exists_usage);
 +
 +      if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
 +              die("invalid ref format: %s", argv[start]);
 +      return !reflog_exists(argv[start]);
 +}
 +
  /*
   * main "reflog"
   */
  
  static const char reflog_usage[] =
 -"git reflog [ show | expire | delete ]";
 +"git reflog [ show | expire | delete | exists ]";
  
  int cmd_reflog(int argc, const char **argv, const char *prefix)
  {
        if (!strcmp(argv[1], "delete"))
                return cmd_reflog_delete(argc - 1, argv + 1, prefix);
  
 +      if (!strcmp(argv[1], "exists"))
 +              return cmd_reflog_exists(argc - 1, argv + 1, prefix);
 +
        return cmd_log_reflog(argc, argv, prefix);
  }
diff --combined builtin/show-branch.c
index 092b59b0b3c0782a9802b9c3200d5523ac4e2e3e,5cc6ad19b9f72d5279d7230322e9cbe74f99da06..ac5141df80dffaf7adc42f76989698a5a90cb677
@@@ -53,17 -53,6 +53,6 @@@ static struct commit *interesting(struc
        return NULL;
  }
  
- static struct commit *pop_one_commit(struct commit_list **list_p)
- {
-       struct commit *commit;
-       struct commit_list *list;
-       list = *list_p;
-       commit = list->item;
-       *list_p = list->next;
-       free(list);
-       return commit;
- }
  struct commit_name {
        const char *head_name; /* which head's ancestor? */
        int generation; /* how many parents away from head_name */
@@@ -213,7 -202,7 +202,7 @@@ static void join_revs(struct commit_lis
        while (*list_p) {
                struct commit_list *parents;
                int still_interesting = !!interesting(*list_p);
-               struct commit *commit = pop_one_commit(list_p);
+               struct commit *commit = pop_commit(list_p);
                int flags = commit->object.flags & all_mask;
  
                if (!still_interesting && extra <= 0)
@@@ -504,7 -493,7 +493,7 @@@ static int show_merge_base(struct commi
        int exit_status = 1;
  
        while (seen) {
-               struct commit *commit = pop_one_commit(&seen);
+               struct commit *commit = pop_commit(&seen);
                int flags = commit->object.flags & all_mask;
                if (!(flags & UNINTERESTING) &&
                    ((flags & all_revs) == all_revs)) {
@@@ -743,8 -732,6 +732,8 @@@ int cmd_show_branch(int ac, const char 
                        fake_av[1] = NULL;
                        av = fake_av;
                        ac = 1;
 +                      if (!*av)
 +                              die("no branches given, and HEAD is not valid");
                }
                if (ac != 1)
                        die("--reflog option needs one branch name");
                        else
                                msg++;
                        reflog_msg[i] = xstrfmt("(%s) %s",
 -                                              show_date(timestamp, tz, 1),
 +                                              show_date(timestamp, tz,
 +                                                        DATE_MODE(RELATIVE)),
                                                msg);
                        free(logmsg);
  
        all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
  
        while (seen) {
-               struct commit *commit = pop_one_commit(&seen);
+               struct commit *commit = pop_commit(&seen);
                int this_flag = commit->object.flags;
                int is_merge_point = ((this_flag & all_revs) == all_revs);
  
diff --combined commit.c
index 494615d6ff15af5eb95e78053b2799e4c55577fc,1ab4ff220b57589a6d36f9a9b26bdd0288ac1b55..d1810c940b3cb354437e86eee38e2c2499375e80
+++ b/commit.c
@@@ -245,12 -245,7 +245,12 @@@ void set_commit_buffer(struct commit *c
  
  const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
  {
 -      struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
 +      struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
 +      if (!v) {
 +              if (sizep)
 +                      *sizep = 0;
 +              return NULL;
 +      }
        if (sizep)
                *sizep = v->size;
        return v->buffer;
@@@ -277,31 -272,24 +277,31 @@@ const void *get_commit_buffer(const str
  
  void unuse_commit_buffer(const struct commit *commit, const void *buffer)
  {
 -      struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
 -      if (v->buffer != buffer)
 +      struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
 +      if (!(v && v->buffer == buffer))
                free((void *)buffer);
  }
  
  void free_commit_buffer(struct commit *commit)
  {
 -      struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
 -      free(v->buffer);
 -      v->buffer = NULL;
 -      v->size = 0;
 +      struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
 +      if (v) {
 +              free(v->buffer);
 +              v->buffer = NULL;
 +              v->size = 0;
 +      }
  }
  
  const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
  {
 -      struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
 +      struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
        void *ret;
  
 +      if (!v) {
 +              if (sizep)
 +                      *sizep = 0;
 +              return NULL;
 +      }
        ret = v->buffer;
        if (sizep)
                *sizep = v->size;
@@@ -455,11 -443,8 +455,8 @@@ struct commit_list *copy_commit_list(st
  
  void free_commit_list(struct commit_list *list)
  {
-       while (list) {
-               struct commit_list *temp = list;
-               list = temp->next;
-               free(temp);
-       }
+       while (list)
+               pop_commit(&list);
  }
  
  struct commit_list * commit_list_insert_by_date(struct commit *item, struct commit_list **list)
@@@ -505,12 -490,8 +502,8 @@@ void commit_list_sort_by_date(struct co
  struct commit *pop_most_recent_commit(struct commit_list **list,
                                      unsigned int mark)
  {
-       struct commit *ret = (*list)->item;
+       struct commit *ret = pop_commit(list);
        struct commit_list *parents = ret->parents;
-       struct commit_list *old = *list;
-       *list = (*list)->next;
-       free(old);
  
        while (parents) {
                struct commit *commit = parents->item;
@@@ -861,11 -842,9 +854,9 @@@ static struct commit_list *merge_bases_
        list = paint_down_to_common(one, n, twos);
  
        while (list) {
-               struct commit_list *next = list->next;
-               if (!(list->item->object.flags & STALE))
-                       commit_list_insert_by_date(list->item, &result);
-               free(list);
-               list = next;
+               struct commit *commit = pop_commit(&list);
+               if (!(commit->object.flags & STALE))
+                       commit_list_insert_by_date(commit, &result);
        }
        return result;
  }
@@@ -1244,24 -1223,33 +1235,24 @@@ free_return
        free(buf);
  }
  
 -void check_commit_signature(const struct commit *commit, struct signature_check *sigc)
 +int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
  {
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
 -      struct strbuf gpg_output = STRBUF_INIT;
 -      struct strbuf gpg_status = STRBUF_INIT;
 -      int status;
 +      int ret = 1;
  
        sigc->result = 'N';
  
        if (parse_signed_commit(commit, &payload, &signature) <= 0)
                goto out;
 -      status = verify_signed_buffer(payload.buf, payload.len,
 -                                    signature.buf, signature.len,
 -                                    &gpg_output, &gpg_status);
 -      if (status && !gpg_output.len)
 -              goto out;
 -      sigc->payload = strbuf_detach(&payload, NULL);
 -      sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
 -      sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
 -      parse_gpg_output(sigc);
 +      ret = check_signature(payload.buf, payload.len, signature.buf,
 +              signature.len, sigc);
  
   out:
 -      strbuf_release(&gpg_status);
 -      strbuf_release(&gpg_output);
        strbuf_release(&payload);
        strbuf_release(&signature);
 +
 +      return ret;
  }
  
  
@@@ -1546,13 -1534,9 +1537,9 @@@ int commit_tree_extended(const char *ms
         * if everything else stays the same.
         */
        while (parents) {
-               struct commit_list *next = parents->next;
-               struct commit *parent = parents->item;
+               struct commit *parent = pop_commit(&parents);
                strbuf_addf(&buffer, "parent %s\n",
                            sha1_to_hex(parent->object.sha1));
-               free(parents);
-               parents = next;
        }
  
        /* Person/date information */
diff --combined remote.c
index fb161530cdd5e286716d45532c1d58da26250e22,ee6edfa33548ef4a1a6c5b66bac61423b1d0cef1..10f1ffce0b00a7bef0b156678ab7c04431827f0e
+++ b/remote.c
@@@ -8,7 -8,6 +8,7 @@@
  #include "tag.h"
  #include "string-list.h"
  #include "mergesort.h"
 +#include "argv-array.h"
  
  enum map_direction { FROM_SRC, FROM_DST };
  
@@@ -55,6 -54,9 +55,6 @@@ static const char *pushremote_name
  static struct rewrites rewrites;
  static struct rewrites rewrites_push;
  
 -#define BUF_SIZE (2048)
 -static char buffer[BUF_SIZE];
 -
  static int valid_remote(const struct remote *remote)
  {
        return (!!remote->url) || (!!remote->foreign_vcs);
@@@ -63,6 -65,7 +63,6 @@@
  static const char *alias_url(const char *url, struct rewrites *r)
  {
        int i, j;
 -      char *ret;
        struct counted_string *longest;
        int longest_i;
  
        if (!longest)
                return url;
  
 -      ret = xmalloc(r->rewrite[longest_i]->baselen +
 -                   (strlen(url) - longest->len) + 1);
 -      strcpy(ret, r->rewrite[longest_i]->base);
 -      strcpy(ret + r->rewrite[longest_i]->baselen, url + longest->len);
 -      return ret;
 +      return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
  }
  
  static void add_push_refspec(struct remote *remote, const char *ref)
@@@ -241,77 -248,106 +241,77 @@@ static void add_instead_of(struct rewri
        rewrite->instead_of_nr++;
  }
  
 +static const char *skip_spaces(const char *s)
 +{
 +      while (isspace(*s))
 +              s++;
 +      return s;
 +}
 +
  static void read_remotes_file(struct remote *remote)
  {
 +      struct strbuf buf = STRBUF_INIT;
        FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
  
        if (!f)
                return;
        remote->origin = REMOTE_REMOTES;
 -      while (fgets(buffer, BUF_SIZE, f)) {
 -              int value_list;
 -              char *s, *p;
 -
 -              if (starts_with(buffer, "URL:")) {
 -                      value_list = 0;
 -                      s = buffer + 4;
 -              } else if (starts_with(buffer, "Push:")) {
 -                      value_list = 1;
 -                      s = buffer + 5;
 -              } else if (starts_with(buffer, "Pull:")) {
 -                      value_list = 2;
 -                      s = buffer + 5;
 -              } else
 -                      continue;
 -
 -              while (isspace(*s))
 -                      s++;
 -              if (!*s)
 -                      continue;
 +      while (strbuf_getline(&buf, f, '\n') != EOF) {
 +              const char *v;
  
 -              p = s + strlen(s);
 -              while (isspace(p[-1]))
 -                      *--p = 0;
 +              strbuf_rtrim(&buf);
  
 -              switch (value_list) {
 -              case 0:
 -                      add_url_alias(remote, xstrdup(s));
 -                      break;
 -              case 1:
 -                      add_push_refspec(remote, xstrdup(s));
 -                      break;
 -              case 2:
 -                      add_fetch_refspec(remote, xstrdup(s));
 -                      break;
 -              }
 +              if (skip_prefix(buf.buf, "URL:", &v))
 +                      add_url_alias(remote, xstrdup(skip_spaces(v)));
 +              else if (skip_prefix(buf.buf, "Push:", &v))
 +                      add_push_refspec(remote, xstrdup(skip_spaces(v)));
 +              else if (skip_prefix(buf.buf, "Pull:", &v))
 +                      add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
        }
 +      strbuf_release(&buf);
        fclose(f);
  }
  
  static void read_branches_file(struct remote *remote)
  {
        char *frag;
 -      struct strbuf branch = STRBUF_INIT;
 -      int n = 1000;
 -      FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
 -      char *s, *p;
 -      int len;
 +      struct strbuf buf = STRBUF_INIT;
 +      FILE *f = fopen(git_path("branches/%s", remote->name), "r");
  
        if (!f)
                return;
 -      s = fgets(buffer, BUF_SIZE, f);
 +
 +      strbuf_getline(&buf, f, '\n');
        fclose(f);
 -      if (!s)
 -              return;
 -      while (isspace(*s))
 -              s++;
 -      if (!*s)
 +      strbuf_trim(&buf);
 +      if (!buf.len) {
 +              strbuf_release(&buf);
                return;
 +      }
 +
        remote->origin = REMOTE_BRANCHES;
 -      p = s + strlen(s);
 -      while (isspace(p[-1]))
 -              *--p = 0;
 -      len = p - s;
 -      p = xmalloc(len + 1);
 -      strcpy(p, s);
  
        /*
         * The branches file would have URL and optionally
         * #branch specified.  The "master" (or specified) branch is
 -       * fetched and stored in the local branch of the same name.
 +       * fetched and stored in the local branch matching the
 +       * remote name.
         */
 -      frag = strchr(p, '#');
 -      if (frag) {
 +      frag = strchr(buf.buf, '#');
 +      if (frag)
                *(frag++) = '\0';
 -              strbuf_addf(&branch, "refs/heads/%s", frag);
 -      } else
 -              strbuf_addstr(&branch, "refs/heads/master");
 +      else
 +              frag = "master";
 +
 +      add_url_alias(remote, strbuf_detach(&buf, NULL));
 +      add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s",
 +                                        frag, remote->name));
  
 -      strbuf_addf(&branch, ":refs/heads/%s", remote->name);
 -      add_url_alias(remote, p);
 -      add_fetch_refspec(remote, strbuf_detach(&branch, NULL));
        /*
         * Cogito compatible push: push current HEAD to remote #branch
         * (master if missing)
         */
 -      strbuf_init(&branch, 0);
 -      strbuf_addstr(&branch, "HEAD");
 -      if (frag)
 -              strbuf_addf(&branch, ":refs/heads/%s", frag);
 -      else
 -              strbuf_addstr(&branch, ":refs/heads/master");
 -      add_push_refspec(remote, strbuf_detach(&branch, NULL));
 +      add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag));
        remote->fetch_tags = 1; /* always auto-follow */
  }
  
@@@ -1939,10 -1975,8 +1939,8 @@@ int resolve_remote_symref(struct ref *r
  static void unmark_and_free(struct commit_list *list, unsigned int mark)
  {
        while (list) {
-               struct commit_list *temp = list;
-               temp->item->object.flags &= ~mark;
-               list = temp->next;
-               free(temp);
+               struct commit *commit = pop_commit(&list);
+               commit->object.flags &= ~mark;
        }
  }
  
@@@ -1999,9 -2033,10 +1997,9 @@@ int stat_tracking_info(struct branch *b
  {
        unsigned char sha1[20];
        struct commit *ours, *theirs;
 -      char symmetric[84];
        struct rev_info revs;
 -      const char *rev_argv[10], *base;
 -      int rev_argc;
 +      const char *base;
 +      struct argv_array argv = ARGV_ARRAY_INIT;
  
        /* Cannot stat unless we are marked to build on top of somebody else. */
        base = branch_get_upstream(branch, NULL);
        }
  
        /* Run "rev-list --left-right ours...theirs" internally... */
 -      rev_argc = 0;
 -      rev_argv[rev_argc++] = NULL;
 -      rev_argv[rev_argc++] = "--left-right";
 -      rev_argv[rev_argc++] = symmetric;
 -      rev_argv[rev_argc++] = "--";
 -      rev_argv[rev_argc] = NULL;
 -
 -      strcpy(symmetric, sha1_to_hex(ours->object.sha1));
 -      strcpy(symmetric + 40, "...");
 -      strcpy(symmetric + 43, sha1_to_hex(theirs->object.sha1));
 +      argv_array_push(&argv, ""); /* ignored */
 +      argv_array_push(&argv, "--left-right");
 +      argv_array_pushf(&argv, "%s...%s",
 +                       sha1_to_hex(ours->object.sha1),
 +                       sha1_to_hex(theirs->object.sha1));
 +      argv_array_push(&argv, "--");
  
        init_revisions(&revs, NULL);
 -      setup_revisions(rev_argc, rev_argv, &revs, NULL);
 +      setup_revisions(argv.argc, argv.argv, &revs, NULL);
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
  
        /* clear object flags smudged by the above traversal */
        clear_commit_marks(ours, ALL_REV_FLAGS);
        clear_commit_marks(theirs, ALL_REV_FLAGS);
 +
 +      argv_array_clear(&argv);
        return 0;
  }
  
diff --combined revision.c
index 22364636d1456795dd858b8039da3b90d32c6633,3f65614963e515ed9971cae10b0bc33382cf7186..0fbb6841bf14389148474bff7bd702f5ec02e558
  #include "commit-slab.h"
  #include "dir.h"
  #include "cache-tree.h"
 +#include "bisect.h"
  
  volatile show_early_output_fn_t show_early_output;
  
 +static const char *term_bad;
 +static const char *term_good;
 +
  char *path_name(const struct name_path *path, const char *name)
  {
        const struct name_path *p;
@@@ -38,7 -34,7 +38,7 @@@
        }
        n = xmalloc(len);
        m = n + len - (nlen + 1);
 -      strcpy(m, name);
 +      memcpy(m, name, nlen + 1);
        for (p = path; p; p = p->up) {
                if (p->elem_len) {
                        m -= p->elem_len + 1;
@@@ -153,10 -149,7 +153,7 @@@ void mark_parents_uninteresting(struct 
                commit_list_insert(l->item, &parents);
  
        while (parents) {
-               struct commit *commit = parents->item;
-               l = parents;
-               parents = parents->next;
-               free(l);
+               struct commit *commit = pop_commit(&parents);
  
                while (commit) {
                        /*
@@@ -1102,14 -1095,10 +1099,10 @@@ static int limit_list(struct rev_info *
        }
  
        while (list) {
-               struct commit_list *entry = list;
-               struct commit *commit = list->item;
+               struct commit *commit = pop_commit(&list);
                struct object *obj = &commit->object;
                show_early_output_fn_t show;
  
-               list = list->next;
-               free(entry);
                if (commit == interesting_cache)
                        interesting_cache = NULL;
  
@@@ -2000,10 -1989,10 +1993,10 @@@ static int handle_revision_opt(struct r
        } else if (!strcmp(arg, "--full-history")) {
                revs->simplify_history = 0;
        } else if (!strcmp(arg, "--relative-date")) {
 -              revs->date_mode = DATE_RELATIVE;
 +              revs->date_mode.type = DATE_RELATIVE;
                revs->date_mode_explicit = 1;
        } else if ((argcount = parse_long_opt("date", argv, &optarg))) {
 -              revs->date_mode = parse_date_format(optarg);
 +              parse_date_format(optarg, &revs->date_mode);
                revs->date_mode_explicit = 1;
                return argcount;
        } else if (!strcmp(arg, "--log-size")) {
@@@ -2080,23 -2069,14 +2073,23 @@@ void parse_revision_opt(struct rev_inf
        ctx->argc -= n;
  }
  
 +static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {
 +      struct strbuf bisect_refs = STRBUF_INIT;
 +      int status;
 +      strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
 +      status = for_each_ref_in_submodule(submodule, bisect_refs.buf, fn, cb_data);
 +      strbuf_release(&bisect_refs);
 +      return status;
 +}
 +
  static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
  {
 -      return for_each_ref_in_submodule(submodule, "refs/bisect/bad", fn, cb_data);
 +      return for_each_bisect_ref(submodule, fn, cb_data, term_bad);
  }
  
  static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
  {
 -      return for_each_ref_in_submodule(submodule, "refs/bisect/good", fn, cb_data);
 +      return for_each_bisect_ref(submodule, fn, cb_data, term_good);
  }
  
  static int handle_revision_pseudo_opt(const char *submodule,
                handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--bisect")) {
 +              read_bisect_terms(&term_bad, &term_good);
                handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
                handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
                revs->bisect = 1;
@@@ -2733,10 -2712,7 +2726,7 @@@ static void simplify_merges(struct rev_
                yet_to_do = NULL;
                tail = &yet_to_do;
                while (list) {
-                       commit = list->item;
-                       next = list->next;
-                       free(list);
-                       list = next;
+                       commit = pop_commit(&list);
                        tail = simplify_one(revs, commit, tail);
                }
        }
        while (list) {
                struct merge_simplify_state *st;
  
-               commit = list->item;
-               next = list->next;
-               free(list);
-               list = next;
+               commit = pop_commit(&list);
                st = locate_simplify_state(revs, commit);
                if (st->simplified == commit)
                        tail = &commit_list_insert(commit, tail)->next;
@@@ -3125,11 -3098,7 +3112,7 @@@ static struct commit *get_revision_1(st
                return NULL;
  
        do {
-               struct commit_list *entry = revs->commits;
-               struct commit *commit = entry->item;
-               revs->commits = entry->next;
-               free(entry);
+               struct commit *commit = pop_commit(&revs->commits);
  
                if (revs->reflog_info) {
                        save_parents(revs, commit);
diff --combined shallow.c
index 4f9d66723670664fd8a15e271ed0cfc309324059,889fad913185eacdc70339fcd38ee2d0ab1f7f8e..46be7897794ab8e350d64f00d3c11390fe993ad8
+++ b/shallow.c
@@@ -1,5 -1,4 +1,5 @@@
  #include "cache.h"
 +#include "tempfile.h"
  #include "lockfile.h"
  #include "commit.h"
  #include "tag.h"
@@@ -10,6 -9,7 +10,6 @@@
  #include "diff.h"
  #include "revision.h"
  #include "commit-slab.h"
 -#include "sigchain.h"
  
  static int is_shallow = -1;
  static struct stat_validity shallow_stat;
@@@ -48,7 -48,7 +48,7 @@@ int is_repository_shallow(void
                return is_shallow;
  
        if (!path)
 -              path = git_path("shallow");
 +              path = git_path_shallow();
        /*
         * fetch-pack sets '--shallow-file ""' as an indicator that no
         * shallow file should be used. We could just open it and it
@@@ -142,7 -142,7 +142,7 @@@ static void check_shallow_file_for_upda
        if (is_shallow == -1)
                die("BUG: shallow must be initialized by now");
  
 -      if (!stat_validity_check(&shallow_stat, git_path("shallow")))
 +      if (!stat_validity_check(&shallow_stat, git_path_shallow()))
                die("shallow file has changed since we read it");
  }
  
@@@ -208,28 -208,50 +208,28 @@@ int write_shallow_commits(struct strbu
        return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
  }
  
 -static struct strbuf temporary_shallow = STRBUF_INIT;
 -
 -static void remove_temporary_shallow(void)
 -{
 -      if (temporary_shallow.len) {
 -              unlink_or_warn(temporary_shallow.buf);
 -              strbuf_reset(&temporary_shallow);
 -      }
 -}
 -
 -static void remove_temporary_shallow_on_signal(int signo)
 -{
 -      remove_temporary_shallow();
 -      sigchain_pop(signo);
 -      raise(signo);
 -}
 +static struct tempfile temporary_shallow;
  
  const char *setup_temporary_shallow(const struct sha1_array *extra)
  {
        struct strbuf sb = STRBUF_INIT;
        int fd;
  
 -      if (temporary_shallow.len)
 -              die("BUG: attempt to create two temporary shallow files");
 -
        if (write_shallow_commits(&sb, 0, extra)) {
 -              strbuf_addstr(&temporary_shallow, git_path("shallow_XXXXXX"));
 -              fd = xmkstemp(temporary_shallow.buf);
 -
 -              atexit(remove_temporary_shallow);
 -              sigchain_push_common(remove_temporary_shallow_on_signal);
 +              fd = xmks_tempfile(&temporary_shallow, git_path("shallow_XXXXXX"));
  
                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
                        die_errno("failed to write to %s",
 -                                temporary_shallow.buf);
 -              close(fd);
 +                                get_tempfile_path(&temporary_shallow));
 +              close_tempfile(&temporary_shallow);
                strbuf_release(&sb);
 -              return temporary_shallow.buf;
 +              return get_tempfile_path(&temporary_shallow);
        }
        /*
         * is_repository_shallow() sees empty string as "no shallow
         * file".
         */
 -      return temporary_shallow.buf;
 +      return get_tempfile_path(&temporary_shallow);
  }
  
  void setup_alternate_shallow(struct lock_file *shallow_lock,
        struct strbuf sb = STRBUF_INIT;
        int fd;
  
 -      fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
 +      fd = hold_lock_file_for_update(shallow_lock, git_path_shallow(),
                                       LOCK_DIE_ON_ERROR);
        check_shallow_file_for_update();
        if (write_shallow_commits(&sb, 0, extra)) {
                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
                        die_errno("failed to write to %s",
 -                                shallow_lock->filename.buf);
 -              *alternate_shallow_file = shallow_lock->filename.buf;
 +                                get_lock_file_path(shallow_lock));
 +              *alternate_shallow_file = get_lock_file_path(shallow_lock);
        } else
                /*
                 * is_repository_shallow() sees empty string as "no
@@@ -286,16 -308,16 +286,16 @@@ void prune_shallow(int show_only
                strbuf_release(&sb);
                return;
        }
 -      fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
 +      fd = hold_lock_file_for_update(&shallow_lock, git_path_shallow(),
                                       LOCK_DIE_ON_ERROR);
        check_shallow_file_for_update();
        if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
                        die_errno("failed to write to %s",
 -                                shallow_lock.filename.buf);
 +                                get_lock_file_path(&shallow_lock));
                commit_lock_file(&shallow_lock);
        } else {
 -              unlink(git_path("shallow"));
 +              unlink(git_path_shallow());
                rollback_lock_file(&shallow_lock);
        }
        strbuf_release(&sb);
@@@ -400,13 -422,9 +400,9 @@@ static void paint_down(struct paint_inf
        commit_list_insert(c, &head);
        while (head) {
                struct commit_list *p;
-               struct commit *c = head->item;
+               struct commit *c = pop_commit(&head);
                uint32_t **refs = ref_bitmap_at(&info->ref_bitmap, c);
  
-               p = head;
-               head = head->next;
-               free(p);
                /* XXX check "UNINTERESTING" from pack bitmaps if available */
                if (c->object.flags & (SEEN | UNINTERESTING))
                        continue;