Merge branch 'js/find-commit-subject-ignore-leading-blanks'
authorJunio C Hamano <gitster@pobox.com>
Mon, 11 Jul 2016 17:31:07 +0000 (10:31 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 Jul 2016 17:31:08 +0000 (10:31 -0700)
A helper function that takes the contents of a commit object and
finds its subject line did not ignore leading blank lines, as is
commonly done by other codepaths. Make it ignore leading blank
lines to match.

* js/find-commit-subject-ignore-leading-blanks:
reset --hard: skip blank lines when reporting the commit subject
sequencer: use skip_blank_lines() to find the commit subject
commit -C: skip blank lines at the beginning of the message
commit.c: make find_commit_subject() more robust
pretty: make the skip_blank_lines() function public

1  2 
builtin/commit.c
builtin/reset.c
commit.c
commit.h
pretty.c
sequencer.c
diff --combined builtin/commit.c
index 3f189428b1214a363b4ba2280d45f76540341f2d,b0effbb929a654be8ed8f5120715971960e0db5b..1f6dbcd0d06a54eadc0d99a676adf3a9203aca61
@@@ -32,7 -32,6 +32,7 @@@
  #include "sequencer.h"
  #include "notes-utils.h"
  #include "mailmap.h"
 +#include "sigchain.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@@ -92,9 -91,8 +92,9 @@@ N_("If you wish to skip this commit, us
  "Then \"git cherry-pick --continue\" will resume cherry-picking\n"
  "the remaining commits.\n");
  
 +static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
 +
  static const char *use_message_buffer;
 -static const char commit_editmsg[] = "COMMIT_EDITMSG";
  static struct lock_file index_lock; /* real index */
  static struct lock_file false_lock; /* used only for partial commits */
  static enum {
@@@ -115,7 -113,6 +115,7 @@@ static char *fixup_message, *squash_mes
  static int all, also, interactive, patch_interactive, only, amend, signoff;
  static int edit_flag = -1; /* unspecified */
  static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 +static int config_commit_verbose = -1; /* unspecified */
  static int no_post_rewrite, allow_empty_message;
  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
  static char *sign_commit;
@@@ -169,11 -166,11 +169,11 @@@ static int opt_parse_m(const struct opt
  
  static void determine_whence(struct wt_status *s)
  {
 -      if (file_exists(git_path("MERGE_HEAD")))
 +      if (file_exists(git_path_merge_head()))
                whence = FROM_MERGE;
 -      else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
 +      else if (file_exists(git_path_cherry_pick_head())) {
                whence = FROM_CHERRY_PICK;
 -              if (file_exists(git_path("sequencer")))
 +              if (file_exists(git_path(SEQ_DIR)))
                        sequencer_in_use = 1;
        }
        else
@@@ -188,7 -185,6 +188,7 @@@ static void status_init_config(struct w
        gitmodules_config();
        git_config(fn, s);
        determine_whence(s);
 +      init_diff_ui_defaults();
        s->hints = advice_status_hints; /* must come after git_config() */
  }
  
@@@ -303,7 -299,7 +303,7 @@@ static void create_base_index(const str
        opts.dst_index = &the_index;
  
        opts.fn = oneway_merge;
 -      tree = parse_tree_indirect(current_head->object.sha1);
 +      tree = parse_tree_indirect(current_head->object.oid.hash);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
@@@ -328,7 -324,6 +328,7 @@@ static const char *prepare_index(int ar
        struct string_list partial;
        struct pathspec pathspec;
        int refresh_flags = REFRESH_QUIET;
 +      const char *ret;
  
        if (is_status)
                refresh_flags |= REFRESH_UNMERGED;
                        die(_("unable to create temporary index"));
  
                old_index_env = getenv(INDEX_ENVIRONMENT);
 -              setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);
 +              setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1);
  
                if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
                        die(_("interactive add failed"));
                        unsetenv(INDEX_ENVIRONMENT);
  
                discard_cache();
 -              read_cache_from(index_lock.filename.buf);
 +              read_cache_from(get_lock_file_path(&index_lock));
                if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
                        if (reopen_lock_file(&index_lock) < 0)
                                die(_("unable to write index file"));
                        warning(_("Failed to update main cache tree"));
  
                commit_style = COMMIT_NORMAL;
 -              return index_lock.filename.buf;
 +              return get_lock_file_path(&index_lock);
        }
  
        /*
         */
        if (all || (also && pathspec.nr)) {
                hold_locked_index(&index_lock, 1);
 -              add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
 +              add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
 -              return index_lock.filename.buf;
 +              return get_lock_file_path(&index_lock);
        }
  
        /*
                hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
                if (active_cache_changed
 -                  || !cache_tree_fully_valid(active_cache_tree)) {
 +                  || !cache_tree_fully_valid(active_cache_tree))
                        update_main_cache_tree(WRITE_TREE_SILENT);
 -                      active_cache_changed = 1;
 -              }
                if (active_cache_changed) {
                        if (write_locked_index(&the_index, &index_lock,
                                               COMMIT_LOCK))
                die(_("unable to write temporary index file"));
  
        discard_cache();
 -      read_cache_from(false_lock.filename.buf);
 -
 -      return false_lock.filename.buf;
 +      ret = get_lock_file_path(&false_lock);
 +      read_cache_from(ret);
 +      return ret;
  }
  
  static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
@@@ -697,7 -694,7 +697,7 @@@ static int prepare_to_commit(const cha
                }
        }
  
 -      if (message.len) {
 +      if (have_option_m) {
                strbuf_addbuf(&sb, &message);
                hook_arg1 = "message";
        } else if (logfile && !strcmp(logfile, "-")) {
                char *buffer;
                buffer = strstr(use_message_buffer, "\n\n");
                if (buffer)
-                       strbuf_addstr(&sb, buffer + 2);
+                       strbuf_addstr(&sb, skip_blank_lines(buffer + 2));
                hook_arg1 = "commit";
                hook_arg2 = use_message;
        } else if (fixup_message) {
                format_commit_message(commit, "fixup! %s\n\n",
                                      &sb, &ctx);
                hook_arg1 = "message";
 -      } else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
 -              if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
 +      } else if (!stat(git_path_merge_msg(), &statbuf)) {
 +              /*
 +               * prepend SQUASH_MSG here if it exists and a
 +               * "merge --squash" was originally performed
 +               */
 +              if (!stat(git_path_squash_msg(), &statbuf)) {
 +                      if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
 +                              die_errno(_("could not read SQUASH_MSG"));
 +                      hook_arg1 = "squash";
 +              } else
 +                      hook_arg1 = "merge";
 +              if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
                        die_errno(_("could not read MERGE_MSG"));
 -              hook_arg1 = "merge";
 -      } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
 -              if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
 +      } else if (!stat(git_path_squash_msg(), &statbuf)) {
 +              if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
                        die_errno(_("could not read SQUASH_MSG"));
                hook_arg1 = "squash";
        } else if (template_file) {
                hook_arg2 = "";
        }
  
 -      s->fp = fopen(git_path(commit_editmsg), "w");
 +      s->fp = fopen_for_writing(git_path_commit_editmsg());
        if (s->fp == NULL)
 -              die_errno(_("could not open '%s'"), git_path(commit_editmsg));
 +              die_errno(_("could not open '%s'"), git_path_commit_editmsg());
  
        /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
        old_display_comment_prefix = s->display_comment_prefix;
        s->hints = 0;
  
        if (clean_message_contents)
 -              stripspace(&sb, 0);
 +              strbuf_stripspace(&sb, 0);
  
        if (signoff)
                append_signoff(&sb, ignore_non_trailer(&sb), 0);
                                _("%s"
                                "Date:      %s"),
                                ident_shown++ ? "" : "\n",
 -                              show_ident_date(&ai, DATE_NORMAL));
 +                              show_ident_date(&ai, DATE_MODE(NORMAL)));
  
                if (!committer_ident_sufficiently_given())
                        status_printf_ln(s, GIT_COLOR_NORMAL,
        }
  
        if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
 -                          git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
 +                          git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL))
                return 0;
  
        if (use_editor) {
                const char *env[2] = { NULL };
                env[0] =  index;
                snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
 -              if (launch_editor(git_path(commit_editmsg), NULL, env)) {
 +              if (launch_editor(git_path_commit_editmsg(), NULL, env)) {
                        fprintf(stderr,
                        _("Please supply the message using either -m or -F option.\n"));
                        exit(1);
        }
  
        if (!no_verify &&
 -          run_commit_hook(use_editor, index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
 +          run_commit_hook(use_editor, index_file, "commit-msg", git_path_commit_editmsg(), NULL)) {
                return 0;
        }
  
@@@ -1027,7 -1015,7 +1027,7 @@@ static int template_untouched(struct st
        if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
                return 0;
  
 -      stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
 +      strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
        if (!skip_prefix(sb->buf, tmpl.buf, &start))
                start = sb->buf;
        strbuf_release(&tmpl);
@@@ -1058,7 -1046,7 +1058,7 @@@ static const char *find_author_by_nickn
        commit = get_revision(&revs);
        if (commit) {
                struct pretty_print_context ctx = {0};
 -              ctx.date_mode = DATE_NORMAL;
 +              ctx.date_mode.type = DATE_NORMAL;
                strbuf_release(&buf);
                format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
                clear_mailmap(&mailmap);
@@@ -1174,9 -1162,9 +1174,9 @@@ static int parse_and_validate_options(i
                f++;
        if (f > 1)
                die(_("Only one of -c/-C/-F/--fixup can be used."));
 -      if (message.len && f > 0)
 +      if (have_option_m && f > 0)
                die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
 -      if (f || message.len)
 +      if (f || have_option_m)
                template_file = NULL;
        if (edit_message)
                use_message = edit_message;
@@@ -1378,14 -1366,13 +1378,14 @@@ int cmd_status(int argc, const char **a
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
  
        fd = hold_locked_index(&index_lock, 0);
 -      if (0 <= fd)
 -              update_index_if_able(&the_index, &index_lock);
  
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
        s.ignore_submodule_arg = ignore_submodule_arg;
        wt_status_collect(&s);
  
 +      if (0 <= fd)
 +              update_index_if_able(&the_index, &index_lock);
 +
        if (s.relative_paths)
                s.prefix = prefix;
  
@@@ -1517,11 -1504,6 +1517,11 @@@ static int git_commit_config(const cha
                sign_commit = git_config_bool(k, v) ? "" : NULL;
                return 0;
        }
 +      if (!strcmp(k, "commit.verbose")) {
 +              int is_bool;
 +              config_commit_verbose = git_config_bool_or_int(k, v, &is_bool);
 +              return 0;
 +      }
  
        status = git_gpg_config(k, v, NULL);
        if (status)
@@@ -1555,10 -1537,8 +1555,10 @@@ static int run_rewrite_hook(const unsig
                return code;
        n = snprintf(buf, sizeof(buf), "%s %s\n",
                     sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
 +      sigchain_push(SIGPIPE, SIG_IGN);
        write_in_full(proc.in, buf, n);
        close(proc.in);
 +      sigchain_pop(SIGPIPE);
        return finish_command(&proc);
  }
  
@@@ -1668,13 -1648,9 +1668,13 @@@ int cmd_commit(int argc, const char **a
                if (parse_commit(current_head))
                        die(_("could not parse HEAD commit"));
        }
 +      verbose = -1; /* unspecified */
        argc = parse_and_validate_options(argc, argv, builtin_commit_options,
                                          builtin_commit_usage,
                                          prefix, current_head, &s);
 +      if (verbose == -1)
 +              verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
 +
        if (dry_run)
                return dry_run_commit(argc, argv, prefix, current_head, &s);
        index_file = prepare_index(argc, argv, prefix, current_head, 0);
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
                pptr = &commit_list_insert(current_head, pptr)->next;
 -              fp = fopen(git_path("MERGE_HEAD"), "r");
 +              fp = fopen(git_path_merge_head(), "r");
                if (fp == NULL)
                        die_errno(_("could not open '%s' for reading"),
 -                                git_path("MERGE_HEAD"));
 -              while (strbuf_getline(&m, fp, '\n') != EOF) {
 +                                git_path_merge_head());
 +              while (strbuf_getline_lf(&m, fp) != EOF) {
                        struct commit *parent;
  
                        parent = get_merge_parent(m.buf);
                }
                fclose(fp);
                strbuf_release(&m);
 -              if (!stat(git_path("MERGE_MODE"), &statbuf)) {
 -                      if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0)
 +              if (!stat(git_path_merge_mode(), &statbuf)) {
 +                      if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
                                die_errno(_("could not read MERGE_MODE"));
                        if (!strcmp(sb.buf, "no-ff"))
                                allow_fast_forward = 0;
  
        /* Finally, get the commit message */
        strbuf_reset(&sb);
 -      if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
 +      if (strbuf_read_file(&sb, git_path_commit_editmsg(), 0) < 0) {
                int saved_errno = errno;
                rollback_index_files();
                die(_("could not read commit message: %s"), strerror(saved_errno));
                wt_status_truncate_message_at_cut_line(&sb);
  
        if (cleanup_mode != CLEANUP_NONE)
 -              stripspace(&sb, cleanup_mode == CLEANUP_ALL);
 +              strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
        if (template_untouched(&sb) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD", sha1,
                                   current_head
 -                                 ? current_head->object.sha1 : null_sha1,
 +                                 ? current_head->object.oid.hash : null_sha1,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
        }
        ref_transaction_free(transaction);
  
 -      unlink(git_path("CHERRY_PICK_HEAD"));
 -      unlink(git_path("REVERT_HEAD"));
 -      unlink(git_path("MERGE_HEAD"));
 -      unlink(git_path("MERGE_MSG"));
 -      unlink(git_path("MERGE_MODE"));
 -      unlink(git_path("SQUASH_MSG"));
 +      unlink(git_path_cherry_pick_head());
 +      unlink(git_path_revert_head());
 +      unlink(git_path_merge_head());
 +      unlink(git_path_merge_msg());
 +      unlink(git_path_merge_mode());
 +      unlink(git_path_squash_msg());
  
        if (commit_index_files())
                die (_("Repository has been updated, but unable to write\n"
                cfg = init_copy_notes_for_rewrite("amend");
                if (cfg) {
                        /* we are amending, so current_head is not NULL */
 -                      copy_note_for_rewrite(cfg, current_head->object.sha1, sha1);
 +                      copy_note_for_rewrite(cfg, current_head->object.oid.hash, sha1);
                        finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
                }
 -              run_rewrite_hook(current_head->object.sha1, sha1);
 +              run_rewrite_hook(current_head->object.oid.hash, sha1);
        }
        if (!quiet)
                print_summary(prefix, sha1, !current_head);
diff --combined builtin/reset.c
index acd6278868b65981fd838b4ade327cdcaab51ccd,34d8b236f1568f72e3995221f4524ec708f9d829..5c6206bc1c40dd1ac7081896232910be95d13977
@@@ -36,7 -36,7 +36,7 @@@ static const char *reset_type_names[] 
  
  static inline int is_merge(void)
  {
 -      return !access(git_path("MERGE_HEAD"), F_OK);
 +      return !access(git_path_merge_head(), F_OK);
  }
  
  static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
@@@ -96,14 -96,14 +96,14 @@@ static void print_new_head_line(struct 
        const char *hex, *body;
        const char *msg;
  
 -      hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
 +      hex = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
        printf(_("HEAD is now at %s"), hex);
        msg = logmsg_reencode(commit, NULL, get_log_output_encoding());
        body = strstr(msg, "\n\n");
        if (body) {
                const char *eol;
                size_t len;
-               body += 2;
+               body = skip_blank_lines(body + 2);
                eol = strchr(body, '\n');
                len = eol ? eol - body : strlen(body);
                printf(" %.*s\n", (int) len, body);
@@@ -158,7 -158,7 +158,7 @@@ static int read_from_tree(const struct 
                return 1;
        diffcore_std(&opt);
        diff_flush(&opt);
 -      free_pathspec(&opt.pathspec);
 +      clear_pathspec(&opt.pathspec);
  
        return 0;
  }
@@@ -269,7 -269,7 +269,7 @@@ int cmd_reset(int argc, const char **ar
        int reset_type = NONE, update_ref_status = 0, quiet = 0;
        int patch_mode = 0, unborn;
        const char *rev;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct pathspec pathspec;
        int intent_to_add = 0;
        const struct option options[] = {
                                                PARSE_OPT_KEEP_DASHDASH);
        parse_args(&pathspec, argv, prefix, patch_mode, &rev);
  
 -      unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
 +      unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
 -              hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
 +              hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
        } else if (!pathspec.nr) {
                struct commit *commit;
 -              if (get_sha1_committish(rev, sha1))
 +              if (get_sha1_committish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
 -              commit = lookup_commit_reference(sha1);
 +              commit = lookup_commit_reference(oid.hash);
                if (!commit)
                        die(_("Could not parse object '%s'."), rev);
 -              hashcpy(sha1, commit->object.sha1);
 +              oidcpy(&oid, &commit->object.oid);
        } else {
                struct tree *tree;
 -              if (get_sha1_treeish(rev, sha1))
 +              if (get_sha1_treeish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
 -              tree = parse_tree_indirect(sha1);
 +              tree = parse_tree_indirect(oid.hash);
                if (!tree)
                        die(_("Could not parse object '%s'."), rev);
 -              hashcpy(sha1, tree->object.sha1);
 +              oidcpy(&oid, &tree->object.oid);
        }
  
        if (patch_mode) {
                hold_locked_index(lock, 1);
                if (reset_type == MIXED) {
                        int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
 -                      if (read_from_tree(&pathspec, sha1, intent_to_add))
 +                      if (read_from_tree(&pathspec, oid.hash, intent_to_add))
                                return 1;
                        if (get_git_work_tree())
                                refresh_index(&the_index, flags, NULL, NULL,
                                              _("Unstaged changes after reset:"));
                } else {
 -                      int err = reset_index(sha1, reset_type, quiet);
 +                      int err = reset_index(oid.hash, reset_type, quiet);
                        if (reset_type == KEEP && !err)
 -                              err = reset_index(sha1, MIXED, quiet);
 +                              err = reset_index(oid.hash, MIXED, quiet);
                        if (err)
                                die(_("Could not reset index file to revision '%s'."), rev);
                }
        if (!pathspec.nr && !unborn) {
                /* Any resets without paths update HEAD to the head being
                 * switched to, saving the previous head in ORIG_HEAD before. */
 -              update_ref_status = reset_refs(rev, sha1);
 +              update_ref_status = reset_refs(rev, oid.hash);
  
                if (reset_type == HARD && !update_ref_status && !quiet)
 -                      print_new_head_line(lookup_commit_reference(sha1));
 +                      print_new_head_line(lookup_commit_reference(oid.hash));
        }
        if (!pathspec.nr)
                remove_branch_state();
diff --combined commit.c
index 3f4f371e5eec41fa67345c0b9d373b541e52172a,116774c2105a8165295287e22b5579eb79e68be4..24d4715f24f06c4747eb728ffbdab2aadf715e6a
+++ b/commit.c
@@@ -38,7 -38,7 +38,7 @@@ struct commit *lookup_commit_or_die(con
        struct commit *c = lookup_commit_reference(sha1);
        if (!c)
                die(_("could not parse %s"), ref_name);
 -      if (hashcmp(sha1, c->object.sha1)) {
 +      if (hashcmp(sha1, c->object.oid.hash)) {
                warning(_("%s %s is not a commit!"),
                        ref_name, sha1_to_hex(sha1));
        }
@@@ -55,12 -55,12 +55,12 @@@ struct commit *lookup_commit(const unsi
  
  struct commit *lookup_commit_reference_by_name(const char *name)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct commit *commit;
  
 -      if (get_sha1_committish(name, sha1))
 +      if (get_sha1_committish(name, oid.hash))
                return NULL;
 -      commit = lookup_commit_reference(sha1);
 +      commit = lookup_commit_reference(oid.hash);
        if (parse_commit(commit))
                return NULL;
        return commit;
@@@ -99,7 -99,7 +99,7 @@@ static int commit_graft_alloc, commit_g
  static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
  {
        struct commit_graft **commit_graft_table = table;
 -      return commit_graft_table[index]->sha1;
 +      return commit_graft_table[index]->oid.hash;
  }
  
  static int commit_graft_pos(const unsigned char *sha1)
  
  int register_commit_graft(struct commit_graft *graft, int ignore_dups)
  {
 -      int pos = commit_graft_pos(graft->sha1);
 +      int pos = commit_graft_pos(graft->oid.hash);
  
        if (0 <= pos) {
                if (ignore_dups)
@@@ -138,23 -138,22 +138,23 @@@ struct commit_graft *read_graft_line(ch
        /* The format is just "Commit Parent1 Parent2 ...\n" */
        int i;
        struct commit_graft *graft = NULL;
 +      const int entry_size = GIT_SHA1_HEXSZ + 1;
  
        while (len && isspace(buf[len-1]))
                buf[--len] = '\0';
        if (buf[0] == '#' || buf[0] == '\0')
                return NULL;
 -      if ((len + 1) % 41)
 +      if ((len + 1) % entry_size)
                goto bad_graft_data;
 -      i = (len + 1) / 41 - 1;
 -      graft = xmalloc(sizeof(*graft) + 20 * i);
 +      i = (len + 1) / entry_size - 1;
 +      graft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i)));
        graft->nr_parent = i;
 -      if (get_sha1_hex(buf, graft->sha1))
 +      if (get_oid_hex(buf, &graft->oid))
                goto bad_graft_data;
 -      for (i = 40; i < len; i += 41) {
 +      for (i = GIT_SHA1_HEXSZ; i < len; i += entry_size) {
                if (buf[i] != ' ')
                        goto bad_graft_data;
 -              if (get_sha1_hex(buf + i + 1, graft->parent[i/41]))
 +              if (get_sha1_hex(buf + i + 1, graft->parent[i/entry_size].hash))
                        goto bad_graft_data;
        }
        return graft;
@@@ -245,12 -244,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;
@@@ -262,13 -256,13 +262,13 @@@ const void *get_commit_buffer(const str
        if (!ret) {
                enum object_type type;
                unsigned long size;
 -              ret = read_sha1_file(commit->object.sha1, &type, &size);
 +              ret = read_sha1_file(commit->object.oid.hash, &type, &size);
                if (!ret)
                        die("cannot read commit object %s",
 -                          sha1_to_hex(commit->object.sha1));
 +                          oid_to_hex(&commit->object.oid));
                if (type != OBJ_COMMIT)
                        die("expected commit for %s, got %s",
 -                          sha1_to_hex(commit->object.sha1), typename(type));
 +                          oid_to_hex(&commit->object.oid), typename(type));
                if (sizep)
                        *sizep = size;
        }
  
  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;
@@@ -315,42 -302,39 +315,42 @@@ int parse_commit_buffer(struct commit *
  {
        const char *tail = buffer;
        const char *bufptr = buffer;
 -      unsigned char parent[20];
 +      struct object_id parent;
        struct commit_list **pptr;
        struct commit_graft *graft;
 +      const int tree_entry_len = GIT_SHA1_HEXSZ + 5;
 +      const int parent_entry_len = GIT_SHA1_HEXSZ + 7;
  
        if (item->object.parsed)
                return 0;
        item->object.parsed = 1;
        tail += size;
 -      if (tail <= bufptr + 46 || memcmp(bufptr, "tree ", 5) || bufptr[45] != '\n')
 -              return error("bogus commit object %s", sha1_to_hex(item->object.sha1));
 -      if (get_sha1_hex(bufptr + 5, parent) < 0)
 +      if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
 +                      bufptr[tree_entry_len] != '\n')
 +              return error("bogus commit object %s", oid_to_hex(&item->object.oid));
 +      if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
                return error("bad tree pointer in commit %s",
 -                           sha1_to_hex(item->object.sha1));
 -      item->tree = lookup_tree(parent);
 -      bufptr += 46; /* "tree " + "hex sha1" + "\n" */
 +                           oid_to_hex(&item->object.oid));
 +      item->tree = lookup_tree(parent.hash);
 +      bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
  
 -      graft = lookup_commit_graft(item->object.sha1);
 -      while (bufptr + 48 < tail && !memcmp(bufptr, "parent ", 7)) {
 +      graft = lookup_commit_graft(item->object.oid.hash);
 +      while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
                struct commit *new_parent;
  
 -              if (tail <= bufptr + 48 ||
 -                  get_sha1_hex(bufptr + 7, parent) ||
 -                  bufptr[47] != '\n')
 -                      return error("bad parents in commit %s", sha1_to_hex(item->object.sha1));
 -              bufptr += 48;
 +              if (tail <= bufptr + parent_entry_len + 1 ||
 +                  get_sha1_hex(bufptr + 7, parent.hash) ||
 +                  bufptr[parent_entry_len] != '\n')
 +                      return error("bad parents in commit %s", oid_to_hex(&item->object.oid));
 +              bufptr += parent_entry_len + 1;
                /*
                 * The clone is shallow if nr_parent < 0, and we must
                 * not traverse its real parents even when we unhide them.
                 */
                if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
                        continue;
 -              new_parent = lookup_commit(parent);
 +              new_parent = lookup_commit(parent.hash);
                if (new_parent)
                        pptr = &commit_list_insert(new_parent, pptr)->next;
        }
                int i;
                struct commit *new_parent;
                for (i = 0; i < graft->nr_parent; i++) {
 -                      new_parent = lookup_commit(graft->parent[i]);
 +                      new_parent = lookup_commit(graft->parent[i].hash);
                        if (!new_parent)
                                continue;
                        pptr = &commit_list_insert(new_parent, pptr)->next;
@@@ -380,15 -364,15 +380,15 @@@ int parse_commit_gently(struct commit *
                return -1;
        if (item->object.parsed)
                return 0;
 -      buffer = read_sha1_file(item->object.sha1, &type, &size);
 +      buffer = read_sha1_file(item->object.oid.hash, &type, &size);
        if (!buffer)
                return quiet_on_missing ? -1 :
                        error("Could not read %s",
 -                           sha1_to_hex(item->object.sha1));
 +                           oid_to_hex(&item->object.oid));
        if (type != OBJ_COMMIT) {
                free(buffer);
                return error("Object %s not a commit",
 -                           sha1_to_hex(item->object.sha1));
 +                           oid_to_hex(&item->object.oid));
        }
        ret = parse_commit_buffer(item, buffer, size);
        if (save_commit_buffer && !ret) {
@@@ -403,7 -387,7 +403,7 @@@ void parse_commit_or_die(struct commit 
  {
        if (parse_commit(item))
                die("unable to parse commit %s",
 -                  item ? sha1_to_hex(item->object.sha1) : "(null)");
 +                  item ? oid_to_hex(&item->object.oid) : "(null)");
  }
  
  int find_commit_subject(const char *commit_buffer, const char **subject)
        while (*p && (*p != '\n' || p[1] != '\n'))
                p++;
        if (*p) {
-               p += 2;
+               p = skip_blank_lines(p + 2);
                for (eol = p; *eol && *eol != '\n'; eol++)
                        ; /* do nothing */
        } else
@@@ -455,8 -439,11 +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)
@@@ -502,8 -489,12 +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;
@@@ -563,7 -554,7 +563,7 @@@ void clear_commit_marks_for_object_arra
  
        for (i = 0; i < a->nr; i++) {
                object = a->objects[i].item;
 -              commit = lookup_commit_reference_gently(object->sha1, 1);
 +              commit = lookup_commit_reference_gently(object->oid.hash, 1);
                if (commit)
                        clear_commit_marks(commit, mark);
        }
@@@ -854,9 -845,11 +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;
  }
@@@ -903,7 -896,7 +903,7 @@@ static int remove_redundant(struct comm
  
        work = xcalloc(cnt, sizeof(*work));
        redundant = xcalloc(cnt, 1);
 -      filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
 +      ALLOC_ARRAY(filled_index, cnt - 1);
  
        for (i = 0; i < cnt; i++)
                parse_commit(array[i]);
@@@ -1206,7 -1199,7 +1206,7 @@@ static void handle_signed_tag(struct co
        desc = merge_remote_util(parent);
        if (!desc || !desc->obj)
                return;
 -      buf = read_sha1_file(desc->obj->sha1, &type, &size);
 +      buf = read_sha1_file(desc->obj->oid.hash, &type, &size);
        if (!buf || type != OBJ_TAG)
                goto free_return;
        len = parse_signature(buf, size);
@@@ -1235,24 -1228,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;
  }
  
  
@@@ -1537,9 -1539,13 +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;
 +                          oid_to_hex(&parent->object.oid));
        }
  
        /* Person/date information */
@@@ -1575,10 -1581,10 +1575,10 @@@ struct commit *get_merge_parent(const c
  {
        struct object *obj;
        struct commit *commit;
 -      unsigned char sha1[20];
 -      if (get_sha1(name, sha1))
 +      struct object_id oid;
 +      if (get_sha1(name, oid.hash))
                return NULL;
 -      obj = parse_object(sha1);
 +      obj = parse_object(oid.hash);
        commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
        if (commit && !commit->util) {
                struct merge_remote_desc *desc;
@@@ -1623,7 -1629,7 +1623,7 @@@ void print_commit_list(struct commit_li
  {
        for ( ; list; list = list->next) {
                const char *format = list->next ? format_cur : format_last;
 -              printf(format, sha1_to_hex(list->item->object.sha1));
 +              printf(format, oid_to_hex(&list->item->object.oid));
        }
  }
  
diff --combined commit.h
index 78ed513c75401b0d1fa821dc18baad833201b4e6,7efa2d2e12258f6426d733e0e264ad18b4c10a3d..3b88c8889db0f1b0e1f6ba2b6d504bb18fed13a2
+++ b/commit.h
@@@ -131,17 -131,11 +131,17 @@@ enum cmit_fmt 
        CMIT_FMT_FULLER,
        CMIT_FMT_ONELINE,
        CMIT_FMT_EMAIL,
 +      CMIT_FMT_MBOXRD,
        CMIT_FMT_USERFORMAT,
  
        CMIT_FMT_UNSPECIFIED
  };
  
 +static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)
 +{
 +      return (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_MBOXRD);
 +}
 +
  struct pretty_print_context {
        /*
         * Callers should tweak these to change the behavior of pp_* functions.
        const char *subject;
        const char *after_subject;
        int preserve_subject;
 -      enum date_mode date_mode;
 +      struct date_mode date_mode;
        unsigned date_mode_explicit:1;
 +      int expand_tabs_in_log;
        int need_8bit_cte;
        char *notes_message;
        struct reflog_walk_info *reflog_info;
         * should not be counted on by callers.
         */
        struct string_list in_body_headers;
 +      int graph_width;
  };
  
  struct userformat_want {
@@@ -184,6 -176,7 +184,7 @@@ extern const char *format_subject(struc
                                  const char *line_separator);
  extern void userformat_find_requirements(const char *fmt, struct userformat_want *w);
  extern int commit_format_is_empty(enum cmit_fmt);
+ extern const char *skip_blank_lines(const char *msg);
  extern void format_commit_message(const struct commit *commit,
                                  const char *format, struct strbuf *sb,
                                  const struct pretty_print_context *context);
@@@ -238,9 -231,9 +239,9 @@@ enum rev_sort_order 
  void sort_in_topological_order(struct commit_list **, enum rev_sort_order);
  
  struct commit_graft {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        int nr_parent; /* < 0 if shallow commit */
 -      unsigned char parent[FLEX_ARRAY][20]; /* more */
 +      struct object_id parent[FLEX_ARRAY]; /* more */
  };
  typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
  
@@@ -387,7 -380,7 +388,7 @@@ extern void print_commit_list(struct co
   * at all.  This may allocate memory for sig->gpg_output, sig->gpg_status,
   * sig->signer and sig->key.
   */
 -extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc);
 +extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc);
  
  int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
  
diff --combined pretty.c
index 330a5e0015bb925b0c76c903aa666712e85ed102,0d40b1b0b1e86c672c122a97d065881b499ac3b8..9fa42c2b4e3cd55fe8ec03248bc19780574bf961
+++ b/pretty.c
@@@ -16,7 -16,6 +16,7 @@@ static struct cmt_fmt_map 
        const char *name;
        enum cmit_fmt format;
        int is_tformat;
 +      int expand_tabs_in_log;
        int is_alias;
        const char *user_format;
  } *commit_formats;
@@@ -88,14 -87,13 +88,14 @@@ static int git_pretty_formats_config(co
  static void setup_commit_formats(void)
  {
        struct cmt_fmt_map builtin_formats[] = {
 -              { "raw",        CMIT_FMT_RAW,           0 },
 -              { "medium",     CMIT_FMT_MEDIUM,        0 },
 -              { "short",      CMIT_FMT_SHORT,         0 },
 -              { "email",      CMIT_FMT_EMAIL,         0 },
 -              { "fuller",     CMIT_FMT_FULLER,        0 },
 -              { "full",       CMIT_FMT_FULL,          0 },
 -              { "oneline",    CMIT_FMT_ONELINE,       1 }
 +              { "raw",        CMIT_FMT_RAW,           0,      0 },
 +              { "medium",     CMIT_FMT_MEDIUM,        0,      8 },
 +              { "short",      CMIT_FMT_SHORT,         0,      0 },
 +              { "email",      CMIT_FMT_EMAIL,         0,      0 },
 +              { "mboxrd",     CMIT_FMT_MBOXRD,        0,      0 },
 +              { "fuller",     CMIT_FMT_FULLER,        0,      8 },
 +              { "full",       CMIT_FMT_FULL,          0,      8 },
 +              { "oneline",    CMIT_FMT_ONELINE,       1,      0 }
        };
        commit_formats_len = ARRAY_SIZE(builtin_formats);
        builtin_formats_len = commit_formats_len;
@@@ -174,7 -172,6 +174,7 @@@ void get_commit_format(const char *arg
  
        rev->commit_format = commit_format->format;
        rev->use_terminator = commit_format->is_tformat;
 +      rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log;
        if (commit_format->format == CMIT_FMT_USERFORMAT) {
                save_user_format(rev, commit_format->user_format,
                                 commit_format->is_tformat);
@@@ -402,7 -399,7 +402,7 @@@ static void add_rfc2047(struct strbuf *
  }
  
  const char *show_ident_date(const struct ident_split *ident,
 -                          enum date_mode mode)
 +                          const struct date_mode *mode)
  {
        unsigned long date = 0;
        long tz = 0;
@@@ -445,7 -442,7 +445,7 @@@ void pp_user_info(struct pretty_print_c
        if (pp->mailmap)
                map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
  
 -      if (pp->fmt == CMIT_FMT_EMAIL) {
 +      if (cmit_fmt_is_mail(pp->fmt)) {
                if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
                        struct strbuf buf = STRBUF_INIT;
  
        switch (pp->fmt) {
        case CMIT_FMT_MEDIUM:
                strbuf_addf(sb, "Date:   %s\n",
 -                          show_ident_date(&ident, pp->date_mode));
 +                          show_ident_date(&ident, &pp->date_mode));
                break;
        case CMIT_FMT_EMAIL:
 +      case CMIT_FMT_MBOXRD:
                strbuf_addf(sb, "Date: %s\n",
 -                          show_ident_date(&ident, DATE_RFC2822));
 +                          show_ident_date(&ident, DATE_MODE(RFC2822)));
                break;
        case CMIT_FMT_FULLER:
                strbuf_addf(sb, "%sDate: %s\n", what,
 -                          show_ident_date(&ident, pp->date_mode));
 +                          show_ident_date(&ident, &pp->date_mode));
                break;
        default:
                /* notin' */
        }
  }
  
- static int is_empty_line(const char *line, int *len_p)
+ static int is_blank_line(const char *line, int *len_p)
  {
        int len = *len_p;
        while (len && isspace(line[len - 1]))
        return !len;
  }
  
static const char *skip_empty_lines(const char *msg)
const char *skip_blank_lines(const char *msg)
  {
        for (;;) {
                int linelen = get_one_line(msg);
                int ll = linelen;
                if (!linelen)
                        break;
-               if (!is_empty_line(msg, &ll))
+               if (!is_blank_line(msg, &ll))
                        break;
                msg += linelen;
        }
@@@ -537,7 -533,7 +537,7 @@@ static void add_merge_info(const struc
  {
        struct commit_list *parent = commit->parents;
  
 -      if ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) ||
 +      if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) ||
            !parent || !parent->next)
                return;
  
                struct commit *p = parent->item;
                const char *hex = NULL;
                if (pp->abbrev)
 -                      hex = find_unique_abbrev(p->object.sha1, pp->abbrev);
 +                      hex = find_unique_abbrev(p->object.oid.hash, pp->abbrev);
                if (!hex)
 -                      hex = sha1_to_hex(p->object.sha1);
 +                      hex = oid_to_hex(&p->object.oid);
                parent = parent->next;
  
                strbuf_addf(sb, " %s", hex);
@@@ -675,8 -671,7 +675,8 @@@ static int mailmap_name(const char **em
  }
  
  static size_t format_person_part(struct strbuf *sb, char part,
 -                               const char *msg, int len, enum date_mode dmode)
 +                               const char *msg, int len,
 +                               const struct date_mode *dmode)
  {
        /* currently all placeholders have same length */
        const int placeholder_len = 2;
                strbuf_addstr(sb, show_ident_date(&s, dmode));
                return placeholder_len;
        case 'D':       /* date, RFC2822 style */
 -              strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822));
 +              strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RFC2822)));
                return placeholder_len;
        case 'r':       /* date, relative */
 -              strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
 +              strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RELATIVE)));
                return placeholder_len;
        case 'i':       /* date, ISO 8601-like */
 -              strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
 +              strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601)));
                return placeholder_len;
        case 'I':       /* date, ISO 8601 strict */
 -              strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT));
 +              strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT)));
                return placeholder_len;
        }
  
@@@ -877,7 -872,7 +877,7 @@@ const char *format_subject(struct strbu
                int linelen = get_one_line(line);
  
                msg += linelen;
-               if (!linelen || is_empty_line(line, &linelen))
+               if (!linelen || is_blank_line(line, &linelen))
                        break;
  
                if (!sb)
@@@ -896,11 -891,11 +896,11 @@@ static void parse_commit_message(struc
        const char *msg = c->message + c->message_off;
        const char *start = c->message;
  
-       msg = skip_empty_lines(msg);
+       msg = skip_blank_lines(msg);
        c->subject_off = msg - start;
  
        msg = format_subject(NULL, msg, NULL);
-       msg = skip_empty_lines(msg);
+       msg = skip_blank_lines(msg);
        c->body_off = msg - start;
  
        c->commit_message_parsed = 1;
@@@ -938,7 -933,7 +938,7 @@@ static void rewrap_message_tail(struct 
  static int format_reflog_person(struct strbuf *sb,
                                char part,
                                struct reflog_walk_info *log,
 -                              enum date_mode dmode)
 +                              const struct date_mode *dmode)
  {
        const char *ident;
  
@@@ -1024,15 -1019,9 +1024,15 @@@ static size_t parse_padding_placeholder
                int width;
                if (!end || end == start)
                        return 0;
 -              width = strtoul(start, &next, 10);
 +              width = strtol(start, &next, 10);
                if (next == start || width == 0)
                        return 0;
 +              if (width < 0) {
 +                      if (to_column)
 +                              width += term_columns();
 +                      if (width < 0)
 +                              return 0;
 +              }
                c->padding = to_column ? -width : width;
                c->flush_type = flush_type;
  
@@@ -1071,7 -1060,7 +1071,7 @@@ static size_t format_commit_one(struct 
        switch (placeholder[0]) {
        case 'C':
                if (starts_with(placeholder + 1, "(auto)")) {
 -                      c->auto_color = 1;
 +                      c->auto_color = want_color(c->pretty_ctx->color);
                        return 7; /* consumed 7 bytes, "C(auto)" */
                } else {
                        int ret = parse_color(sb, placeholder, c);
  
        /* these depend on the commit */
        if (!commit->object.parsed)
 -              parse_object(commit->object.sha1);
 +              parse_object(commit->object.oid.hash);
  
        switch (placeholder[0]) {
        case 'H':               /* commit hash */
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
 -              strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
 +              strbuf_addstr(sb, oid_to_hex(&commit->object.oid));
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                return 1;
        case 'h':               /* abbreviated commit hash */
                        strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                        return 1;
                }
 -              strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
 +              strbuf_addstr(sb, find_unique_abbrev(commit->object.oid.hash,
                                                     c->pretty_ctx->abbrev));
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
 -              strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
 +              strbuf_addstr(sb, oid_to_hex(&commit->tree->object.oid));
                return 1;
        case 't':               /* abbreviated tree hash */
                if (add_again(sb, &c->abbrev_tree_hash))
                        return 1;
 -              strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
 +              strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.oid.hash,
                                                     c->pretty_ctx->abbrev));
                c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
                return 1;
                for (p = commit->parents; p; p = p->next) {
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
 -                      strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
 +                      strbuf_addstr(sb, oid_to_hex(&p->item->object.oid));
                }
                return 1;
        case 'p':               /* abbreviated parent hashes */
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
                        strbuf_addstr(sb, find_unique_abbrev(
 -                                      p->item->object.sha1,
 +                                      p->item->object.oid.hash,
                                        c->pretty_ctx->abbrev));
                }
                c->abbrev_parent_hashes.len = sb->len -
                        if (c->pretty_ctx->reflog_info)
                                get_reflog_selector(sb,
                                                    c->pretty_ctx->reflog_info,
 -                                                  c->pretty_ctx->date_mode,
 +                                                  &c->pretty_ctx->date_mode,
                                                    c->pretty_ctx->date_mode_explicit,
                                                    (placeholder[1] == 'd'));
                        return 2;
                        return format_reflog_person(sb,
                                                    placeholder[1],
                                                    c->pretty_ctx->reflog_info,
 -                                                  c->pretty_ctx->date_mode);
 +                                                  &c->pretty_ctx->date_mode);
                }
                return 0;       /* unknown %g placeholder */
        case 'N':
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
 -                                 c->pretty_ctx->date_mode);
 +                                 &c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
 -                                 c->pretty_ctx->date_mode);
 +                                 &c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                if (c->commit_encoding)
                        strbuf_addstr(sb, c->commit_encoding);
@@@ -1307,7 -1296,6 +1307,7 @@@ static size_t format_and_pad_commit(str
                if (!start)
                        start = sb->buf;
                occupied = utf8_strnwidth(start, -1, 1);
 +              occupied += c->pretty_ctx->graph_width;
                padding = (-padding) - occupied;
        }
        while (1) {
@@@ -1623,7 -1611,7 +1623,7 @@@ void pp_title_line(struct pretty_print_
        if (pp->after_subject) {
                strbuf_addstr(sb, pp->after_subject);
        }
 -      if (pp->fmt == CMIT_FMT_EMAIL) {
 +      if (cmit_fmt_is_mail(pp->fmt)) {
                strbuf_addch(sb, '\n');
        }
  
        strbuf_release(&title);
  }
  
 +static int pp_utf8_width(const char *start, const char *end)
 +{
 +      int width = 0;
 +      size_t remain = end - start;
 +
 +      while (remain) {
 +              int n = utf8_width(&start, &remain);
 +              if (n < 0 || !start)
 +                      return -1;
 +              width += n;
 +      }
 +      return width;
 +}
 +
 +static void strbuf_add_tabexpand(struct strbuf *sb, int tabwidth,
 +                               const char *line, int linelen)
 +{
 +      const char *tab;
 +
 +      while ((tab = memchr(line, '\t', linelen)) != NULL) {
 +              int width = pp_utf8_width(line, tab);
 +
 +              /*
 +               * If it wasn't well-formed utf8, or it
 +               * had characters with badly defined
 +               * width (control characters etc), just
 +               * give up on trying to align things.
 +               */
 +              if (width < 0)
 +                      break;
 +
 +              /* Output the data .. */
 +              strbuf_add(sb, line, tab - line);
 +
 +              /* .. and the de-tabified tab */
 +              strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth));
 +
 +              /* Skip over the printed part .. */
 +              linelen -= tab + 1 - line;
 +              line = tab + 1;
 +      }
 +
 +      /*
 +       * Print out everything after the last tab without
 +       * worrying about width - there's nothing more to
 +       * align.
 +       */
 +      strbuf_add(sb, line, linelen);
 +}
 +
 +/*
 + * pp_handle_indent() prints out the intendation, and
 + * the whole line (without the final newline), after
 + * de-tabifying.
 + */
 +static void pp_handle_indent(struct pretty_print_context *pp,
 +                           struct strbuf *sb, int indent,
 +                           const char *line, int linelen)
 +{
 +      strbuf_addchars(sb, ' ', indent);
 +      if (pp->expand_tabs_in_log)
 +              strbuf_add_tabexpand(sb, pp->expand_tabs_in_log, line, linelen);
 +      else
 +              strbuf_add(sb, line, linelen);
 +}
 +
 +static int is_mboxrd_from(const char *line, int len)
 +{
 +      /*
 +       * a line matching /^From $/ here would only have len == 4
 +       * at this point because is_empty_line would've trimmed all
 +       * trailing space
 +       */
 +      return len > 4 && starts_with(line + strspn(line, ">"), "From ");
 +}
 +
  void pp_remainder(struct pretty_print_context *pp,
                  const char **msg_p,
                  struct strbuf *sb,
                if (!linelen)
                        break;
  
-               if (is_empty_line(line, &linelen)) {
+               if (is_blank_line(line, &linelen)) {
                        if (first)
                                continue;
                        if (pp->fmt == CMIT_FMT_SHORT)
  
                strbuf_grow(sb, linelen + indent + 20);
                if (indent)
 -                      strbuf_addchars(sb, ' ', indent);
 -              strbuf_add(sb, line, linelen);
 +                      pp_handle_indent(pp, sb, indent, line, linelen);
 +              else if (pp->expand_tabs_in_log)
 +                      strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
 +                                           line, linelen);
 +              else {
 +                      if (pp->fmt == CMIT_FMT_MBOXRD &&
 +                                      is_mboxrd_from(line, linelen))
 +                              strbuf_addch(sb, '>');
 +
 +                      strbuf_add(sb, line, linelen);
 +              }
                strbuf_addch(sb, '\n');
        }
  }
@@@ -1774,14 -1677,14 +1774,14 @@@ void pretty_print_commit(struct pretty_
        encoding = get_log_output_encoding();
        msg = reencoded = logmsg_reencode(commit, NULL, encoding);
  
 -      if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 +      if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
                indent = 0;
  
        /*
         * We need to check and emit Content-type: to mark it
         * as 8-bit if we haven't done so.
         */
 -      if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
 +      if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {
                int i, ch, in_body;
  
                for (in_body = i = 0; (ch = msg[i]); i++) {
        }
  
        /* Skip excess blank lines at the beginning of body, if any... */
-       msg = skip_empty_lines(msg);
+       msg = skip_blank_lines(msg);
  
        /* These formats treat the title line specially. */
 -      if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 +      if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
                pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
  
        beginning_of_body = sb->len;
         * format.  Make sure we did not strip the blank line
         * between the header and the body.
         */
 -      if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
 +      if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
  
        unuse_commit_buffer(commit, reencoded);
diff --combined sequencer.c
index c6362d63f35fe37d67fa235784ab8ce75a60db44,e286a6ec13bf7758e3979a9fe8c210573f2f3132..a33c39b64fbd9cf42e5bd531488f7d2366bd167b
  const char sign_off_header[] = "Signed-off-by: ";
  static const char cherry_picked_prefix[] = "(cherry picked from commit ";
  
 +static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)
 +static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)
 +static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)
 +static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)
 +
  static int is_rfc2822_line(const char *buf, int len)
  {
        int i;
@@@ -124,36 -119,62 +124,36 @@@ static const char *action_name(const st
  
  struct commit_message {
        char *parent_label;
 -      const char *label;
 -      const char *subject;
 +      char *label;
 +      char *subject;
        const char *message;
  };
  
  static int get_message(struct commit *commit, struct commit_message *out)
  {
        const char *abbrev, *subject;
 -      int abbrev_len, subject_len;
 -      char *q;
 -
 -      if (!git_commit_encoding)
 -              git_commit_encoding = "UTF-8";
 +      int subject_len;
  
 -      out->message = logmsg_reencode(commit, NULL, git_commit_encoding);
 -      abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
 -      abbrev_len = strlen(abbrev);
 +      out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());
 +      abbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
  
        subject_len = find_commit_subject(out->message, &subject);
  
 -      out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
 -                            strlen("... ") + subject_len + 1);
 -      q = out->parent_label;
 -      q = mempcpy(q, "parent of ", strlen("parent of "));
 -      out->label = q;
 -      q = mempcpy(q, abbrev, abbrev_len);
 -      q = mempcpy(q, "... ", strlen("... "));
 -      out->subject = q;
 -      q = mempcpy(q, subject, subject_len);
 -      *q = '\0';
 +      out->subject = xmemdupz(subject, subject_len);
 +      out->label = xstrfmt("%s... %s", abbrev, out->subject);
 +      out->parent_label = xstrfmt("parent of %s", out->label);
 +
        return 0;
  }
  
  static void free_message(struct commit *commit, struct commit_message *msg)
  {
        free(msg->parent_label);
 +      free(msg->label);
 +      free(msg->subject);
        unuse_commit_buffer(commit, msg->message);
  }
  
 -static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
 -{
 -      const char *filename;
 -      int fd;
 -      struct strbuf buf = STRBUF_INIT;
 -
 -      strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
 -
 -      filename = git_path("%s", pseudoref);
 -      fd = open(filename, O_WRONLY | O_CREAT, 0666);
 -      if (fd < 0)
 -              die_errno(_("Could not open '%s' for writing"), filename);
 -      if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
 -              die_errno(_("Could not write to '%s'"), filename);
 -      strbuf_release(&buf);
 -}
 -
  static void print_advice(int show_hint, struct replay_opts *opts)
  {
        char *msg = getenv("GIT_CHERRY_PICK_HELP");
                 * (typically rebase --interactive) wants to take care
                 * of the commit itself so remove CHERRY_PICK_HEAD
                 */
 -              unlink(git_path("CHERRY_PICK_HEAD"));
 +              unlink(git_path_cherry_pick_head());
                return;
        }
  
@@@ -337,7 -358,7 +337,7 @@@ static int is_index_unchanged(void
                if (cache_tree_update(&the_index, 0))
                        return error(_("Unable to update cache tree\n"));
  
 -      return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
 +      return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
  }
  
  /*
@@@ -388,18 -409,18 +388,18 @@@ static int is_original_commit_empty(str
  
        if (parse_commit(commit))
                return error(_("Could not parse commit %s\n"),
 -                           sha1_to_hex(commit->object.sha1));
 +                           oid_to_hex(&commit->object.oid));
        if (commit->parents) {
                struct commit *parent = commit->parents->item;
                if (parse_commit(parent))
                        return error(_("Could not parse parent commit %s\n"),
 -                              sha1_to_hex(parent->object.sha1));
 -              ptree_sha1 = parent->tree->object.sha1;
 +                              oid_to_hex(&parent->object.oid));
 +              ptree_sha1 = parent->tree->object.oid.hash;
        } else {
                ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
        }
  
 -      return !hashcmp(ptree_sha1, commit->tree->object.sha1);
 +      return !hashcmp(ptree_sha1, commit->tree->object.oid.hash);
  }
  
  /*
@@@ -446,6 -467,7 +446,6 @@@ static int do_pick_commit(struct commi
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
 -      char *defmsg = NULL;
        struct strbuf msgbuf = STRBUF_INIT;
        int res, unborn = 0, allow;
  
  
                if (!opts->mainline)
                        return error(_("Commit %s is a merge but no -m option was given."),
 -                              sha1_to_hex(commit->object.sha1));
 +                              oid_to_hex(&commit->object.oid));
  
                for (cnt = 1, p = commit->parents;
                     cnt != opts->mainline && p;
                        p = p->next;
                if (cnt != opts->mainline || !p)
                        return error(_("Commit %s does not have parent %d"),
 -                              sha1_to_hex(commit->object.sha1), opts->mainline);
 +                              oid_to_hex(&commit->object.oid), opts->mainline);
                parent = p->item;
        } else if (0 < opts->mainline)
                return error(_("Mainline was specified but commit %s is not a merge."),
 -                      sha1_to_hex(commit->object.sha1));
 +                      oid_to_hex(&commit->object.oid));
        else
                parent = commit->parents->item;
  
        if (opts->allow_ff &&
 -          ((parent && !hashcmp(parent->object.sha1, head)) ||
 +          ((parent && !hashcmp(parent->object.oid.hash, head)) ||
             (!parent && unborn)))
 -              return fast_forward_to(commit->object.sha1, head, unborn, opts);
 +              return fast_forward_to(commit->object.oid.hash, head, unborn, opts);
  
        if (parent && parse_commit(parent) < 0)
                /* TRANSLATORS: The first %s will be "revert" or
                   "cherry-pick", the second %s a SHA1 */
                return error(_("%s: cannot parse parent commit %s"),
 -                      action_name(opts), sha1_to_hex(parent->object.sha1));
 +                      action_name(opts), oid_to_hex(&parent->object.oid));
  
        if (get_message(commit, &msg) != 0)
                return error(_("Cannot get commit message for %s"),
 -                      sha1_to_hex(commit->object.sha1));
 +                      oid_to_hex(&commit->object.oid));
  
        /*
         * "commit" is an existing commit.  We would want to apply
         * reverse of it if we are revert.
         */
  
 -      defmsg = git_pathdup("MERGE_MSG");
 -
        if (opts->action == REPLAY_REVERT) {
                base = commit;
                base_label = msg.label;
                strbuf_addstr(&msgbuf, "Revert \"");
                strbuf_addstr(&msgbuf, msg.subject);
                strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
 -              strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
 +              strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
  
                if (commit->parents && commit->parents->next) {
                        strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
 -                      strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
 +                      strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid));
                }
                strbuf_addstr(&msgbuf, ".\n");
        } else {
                 * information followed by "\n\n".
                 */
                p = strstr(msg.message, "\n\n");
-               if (p) {
-                       p += 2;
-                       strbuf_addstr(&msgbuf, p);
-               }
+               if (p)
+                       strbuf_addstr(&msgbuf, skip_blank_lines(p + 2));
  
                if (opts->record_origin) {
                        if (!has_conforming_footer(&msgbuf, NULL, 0))
                                strbuf_addch(&msgbuf, '\n');
                        strbuf_addstr(&msgbuf, cherry_picked_prefix);
 -                      strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
 +                      strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
                        strbuf_addstr(&msgbuf, ")\n");
                }
        }
        if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
                res = do_recursive_merge(base, next, base_label, next_label,
                                         head, &msgbuf, opts);
 -              write_message(&msgbuf, defmsg);
 +              write_message(&msgbuf, git_path_merge_msg());
        } else {
                struct commit_list *common = NULL;
                struct commit_list *remotes = NULL;
  
 -              write_message(&msgbuf, defmsg);
 +              write_message(&msgbuf, git_path_merge_msg());
  
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
         * write it at all.
         */
        if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
 -              write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
 +              update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.oid.hash, NULL,
 +                         REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
        if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
 -              write_cherry_pick_head(commit, "REVERT_HEAD");
 +              update_ref(NULL, "REVERT_HEAD", commit->object.oid.hash, NULL,
 +                         REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
  
        if (res) {
                error(opts->action == REPLAY_REVERT
                      ? _("could not revert %s... %s")
                      : _("could not apply %s... %s"),
 -                    find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
 +                    find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),
                      msg.subject);
                print_advice(res == 1, opts);
                rerere(opts->allow_rerere_auto);
                goto leave;
        }
        if (!opts->no_commit)
 -              res = run_git_commit(defmsg, opts, allow);
 +              res = run_git_commit(git_path_merge_msg(), opts, allow);
  
  leave:
        free_message(commit, &msg);
 -      free(defmsg);
  
        return res;
  }
@@@ -655,7 -676,7 +653,7 @@@ static int format_todo(struct strbuf *b
  
        for (cur = todo_list; cur; cur = cur->next) {
                const char *commit_buffer = get_commit_buffer(cur->item, NULL);
 -              sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
 +              sha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);
                subject_len = find_commit_subject(commit_buffer, &subject);
                strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
                        subject_len, subject);
@@@ -733,23 -754,24 +731,23 @@@ static int parse_insn_buffer(char *buf
  static void read_populate_todo(struct commit_list **todo_list,
                        struct replay_opts *opts)
  {
 -      const char *todo_file = git_path(SEQ_TODO_FILE);
        struct strbuf buf = STRBUF_INIT;
        int fd, res;
  
 -      fd = open(todo_file, O_RDONLY);
 +      fd = open(git_path_todo_file(), O_RDONLY);
        if (fd < 0)
 -              die_errno(_("Could not open %s"), todo_file);
 +              die_errno(_("Could not open %s"), git_path_todo_file());
        if (strbuf_read(&buf, fd, 0) < 0) {
                close(fd);
                strbuf_release(&buf);
 -              die(_("Could not read %s."), todo_file);
 +              die(_("Could not read %s."), git_path_todo_file());
        }
        close(fd);
  
        res = parse_insn_buffer(buf.buf, todo_list, opts);
        strbuf_release(&buf);
        if (res)
 -              die(_("Unusable instruction sheet: %s"), todo_file);
 +              die(_("Unusable instruction sheet: %s"), git_path_todo_file());
  }
  
  static int populate_opts_cb(const char *key, const char *value, void *data)
  
  static void read_populate_opts(struct replay_opts **opts_ptr)
  {
 -      const char *opts_file = git_path(SEQ_OPTS_FILE);
 -
 -      if (!file_exists(opts_file))
 +      if (!file_exists(git_path_opts_file()))
                return;
 -      if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
 -              die(_("Malformed options sheet: %s"), opts_file);
 +      if (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts_ptr) < 0)
 +              die(_("Malformed options sheet: %s"), git_path_opts_file());
  }
  
  static void walk_revs_populate_todo(struct commit_list **todo_list,
  
  static int create_seq_dir(void)
  {
 -      const char *seq_dir = git_path(SEQ_DIR);
 -
 -      if (file_exists(seq_dir)) {
 +      if (file_exists(git_path_seq_dir())) {
                error(_("a cherry-pick or revert is already in progress"));
                advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
                return -1;
        }
 -      else if (mkdir(seq_dir, 0777) < 0)
 -              die_errno(_("Could not create sequencer directory %s"), seq_dir);
 +      else if (mkdir(git_path_seq_dir(), 0777) < 0)
 +              die_errno(_("Could not create sequencer directory %s"),
 +                        git_path_seq_dir());
        return 0;
  }
  
  static void save_head(const char *head)
  {
 -      const char *head_file = git_path(SEQ_HEAD_FILE);
        static struct lock_file head_lock;
        struct strbuf buf = STRBUF_INIT;
        int fd;
  
 -      fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
 +      fd = hold_lock_file_for_update(&head_lock, git_path_head_file(), LOCK_DIE_ON_ERROR);
        strbuf_addf(&buf, "%s\n", head);
        if (write_in_full(fd, buf.buf, buf.len) < 0)
 -              die_errno(_("Could not write to %s"), head_file);
 +              die_errno(_("Could not write to %s"), git_path_head_file());
        if (commit_lock_file(&head_lock) < 0)
 -              die(_("Error wrapping up %s."), head_file);
 +              die(_("Error wrapping up %s."), git_path_head_file());
  }
  
  static int reset_for_rollback(const unsigned char *sha1)
@@@ -849,8 -875,8 +847,8 @@@ static int rollback_single_pick(void
  {
        unsigned char head_sha1[20];
  
 -      if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
 -          !file_exists(git_path("REVERT_HEAD")))
 +      if (!file_exists(git_path_cherry_pick_head()) &&
 +          !file_exists(git_path_revert_head()))
                return error(_("no cherry-pick or revert in progress"));
        if (read_ref_full("HEAD", 0, head_sha1, NULL))
                return error(_("cannot resolve HEAD"));
  
  static int sequencer_rollback(struct replay_opts *opts)
  {
 -      const char *filename;
        FILE *f;
        unsigned char sha1[20];
        struct strbuf buf = STRBUF_INIT;
  
 -      filename = git_path(SEQ_HEAD_FILE);
 -      f = fopen(filename, "r");
 +      f = fopen(git_path_head_file(), "r");
        if (!f && errno == ENOENT) {
                /*
                 * There is no multiple-cherry-pick in progress.
                return rollback_single_pick();
        }
        if (!f)
 -              return error(_("cannot open %s: %s"), filename,
 -                                              strerror(errno));
 -      if (strbuf_getline(&buf, f, '\n')) {
 -              error(_("cannot read %s: %s"), filename, ferror(f) ?
 -                      strerror(errno) : _("unexpected end of file"));
 +              return error_errno(_("cannot open %s"), git_path_head_file());
 +      if (strbuf_getline_lf(&buf, f)) {
 +              error(_("cannot read %s: %s"), git_path_head_file(),
 +                    ferror(f) ?  strerror(errno) : _("unexpected end of file"));
                fclose(f);
                goto fail;
        }
        fclose(f);
        if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
                error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
 -                      filename);
 +                      git_path_head_file());
 +              goto fail;
 +      }
 +      if (is_null_sha1(sha1)) {
 +              error(_("cannot abort from a branch yet to be born"));
                goto fail;
        }
        if (reset_for_rollback(sha1))
@@@ -904,27 -929,28 +902,27 @@@ fail
  
  static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
  {
 -      const char *todo_file = git_path(SEQ_TODO_FILE);
        static struct lock_file todo_lock;
        struct strbuf buf = STRBUF_INIT;
        int fd;
  
 -      fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
 +      fd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), LOCK_DIE_ON_ERROR);
        if (format_todo(&buf, todo_list, opts) < 0)
 -              die(_("Could not format %s."), todo_file);
 +              die(_("Could not format %s."), git_path_todo_file());
        if (write_in_full(fd, buf.buf, buf.len) < 0) {
                strbuf_release(&buf);
 -              die_errno(_("Could not write to %s"), todo_file);
 +              die_errno(_("Could not write to %s"), git_path_todo_file());
        }
        if (commit_lock_file(&todo_lock) < 0) {
                strbuf_release(&buf);
 -              die(_("Error wrapping up %s."), todo_file);
 +              die(_("Error wrapping up %s."), git_path_todo_file());
        }
        strbuf_release(&buf);
  }
  
  static void save_opts(struct replay_opts *opts)
  {
 -      const char *opts_file = git_path(SEQ_OPTS_FILE);
 +      const char *opts_file = git_path_opts_file();
  
        if (opts->no_commit)
                git_config_set_in_file(opts_file, "options.no-commit", "true");
@@@ -985,8 -1011,8 +983,8 @@@ static int continue_single_pick(void
  {
        const char *argv[] = { "commit", NULL };
  
 -      if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
 -          !file_exists(git_path("REVERT_HEAD")))
 +      if (!file_exists(git_path_cherry_pick_head()) &&
 +          !file_exists(git_path_revert_head()))
                return error(_("no cherry-pick or revert in progress"));
        return run_command_v_opt(argv, RUN_GIT_CMD);
  }
@@@ -995,14 -1021,14 +993,14 @@@ static int sequencer_continue(struct re
  {
        struct commit_list *todo_list = NULL;
  
 -      if (!file_exists(git_path(SEQ_TODO_FILE)))
 +      if (!file_exists(git_path_todo_file()))
                return continue_single_pick();
        read_populate_opts(&opts);
        read_populate_todo(&todo_list, opts);
  
        /* Verify that the conflict has been resolved */
 -      if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
 -          file_exists(git_path("REVERT_HEAD"))) {
 +      if (file_exists(git_path_cherry_pick_head()) ||
 +          file_exists(git_path_revert_head())) {
                int ret = continue_single_pick();
                if (ret)
                        return ret;
@@@ -1090,8 -1116,11 +1088,8 @@@ int sequencer_pick_revisions(struct rep
        walk_revs_populate_todo(&todo_list, opts);
        if (create_seq_dir() < 0)
                return -1;
 -      if (get_sha1("HEAD", sha1)) {
 -              if (opts->action == REPLAY_REVERT)
 -                      return error(_("Can't revert as initial commit"));
 -              return error(_("Can't cherry-pick into empty head"));
 -      }
 +      if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
 +              return error(_("Can't revert as initial commit"));
        save_head(sha1_to_hex(sha1));
        save_opts(opts);
        return pick_commits(todo_list, opts);