Merge branch 'mm/commit-template-squelch-advice-messages'
authorJunio C Hamano <gitster@pobox.com>
Fri, 20 Sep 2013 19:36:31 +0000 (12:36 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Sep 2013 19:36:32 +0000 (12:36 -0700)
From the commit log template, remove irrelevant "advice" messages
that are shared with "git status" output.

* mm/commit-template-squelch-advice-messages:
commit: disable status hints when writing to COMMIT_EDITMSG
wt-status: turn advice_status_hints into a field of wt_status
commit: factor status configuration is a helper function

1  2 
builtin/commit.c
wt-status.c
wt-status.h
diff --combined builtin/commit.c
index 29d4225ff214d629eab622242ae8e0aac780ead1,321462a435d2fa2b22d4fb59decbe7e39d1f7084..6ab4605cf5c2e6ef5efb37518c9c215bf8895f97
@@@ -30,7 -30,6 +30,7 @@@
  #include "column.h"
  #include "sequencer.h"
  #include "notes-utils.h"
 +#include "mailmap.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [options] [--] <pathspec>..."),
@@@ -164,6 -163,15 +164,15 @@@ static void determine_whence(struct wt_
                s->whence = whence;
  }
  
+ static void status_init_config(struct wt_status *s, config_fn_t fn)
+ {
+       wt_status_prepare(s);
+       gitmodules_config();
+       git_config(fn, s);
+       determine_whence(s);
+       s->hints = advice_status_hints; /* must come after git_config() */
+ }
  static void rollback_index_files(void)
  {
        switch (commit_style) {
@@@ -203,15 -211,17 +212,15 @@@ static int commit_index_files(void
   * and return the paths that match the given pattern in list.
   */
  static int list_paths(struct string_list *list, const char *with_tree,
 -                    const char *prefix, const char **pattern)
 +                    const char *prefix, const struct pathspec *pattern)
  {
        int i;
        char *m;
  
 -      if (!pattern)
 +      if (!pattern->nr)
                return 0;
  
 -      for (i = 0; pattern[i]; i++)
 -              ;
 -      m = xcalloc(1, i);
 +      m = xcalloc(1, pattern->nr);
  
        if (with_tree) {
                char *max_prefix = common_prefix(pattern);
  
                if (ce->ce_flags & CE_UPDATE)
                        continue;
 -              if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
 +              if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
                        continue;
                item = string_list_insert(list, ce->name);
                if (ce_skip_worktree(ce))
@@@ -297,17 -307,17 +306,17 @@@ static char *prepare_index(int argc, co
  {
        int fd;
        struct string_list partial;
 -      const char **pathspec = NULL;
 +      struct pathspec pathspec;
        char *old_index_env = NULL;
        int refresh_flags = REFRESH_QUIET;
  
        if (is_status)
                refresh_flags |= REFRESH_UNMERGED;
 +      parse_pathspec(&pathspec, 0,
 +                     PATHSPEC_PREFER_FULL,
 +                     prefix, argv);
  
 -      if (*argv)
 -              pathspec = get_pathspec(prefix, argv);
 -
 -      if (read_cache_preload(pathspec) < 0)
 +      if (read_cache_preload(&pathspec) < 0)
                die(_("index file corrupt"));
  
        if (interactive) {
         * (A) if all goes well, commit the real index;
         * (B) on failure, rollback the real index.
         */
 -      if (all || (also && pathspec && *pathspec)) {
 +      if (all || (also && pathspec.nr)) {
                fd = hold_locked_index(&index_lock, 1);
 -              add_files_to_cache(also ? prefix : NULL, pathspec, 0);
 +              add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
                if (write_cache(fd, active_cache, active_nr) ||
         * and create commit from the_index.
         * We still need to refresh the index here.
         */
 -      if (!only && (!pathspec || !*pathspec)) {
 +      if (!only && !pathspec.nr) {
                fd = hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
                if (active_cache_changed) {
  
        memset(&partial, 0, sizeof(partial));
        partial.strdup_strings = 1;
 -      if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec))
 +      if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
                exit(1);
  
        discard_cache();
@@@ -598,7 -608,6 +607,7 @@@ static int prepare_to_commit(const cha
        const char *hook_arg2 = NULL;
        int ident_shown = 0;
        int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
 +      int old_display_comment_prefix;
  
        /* This checks and barfs if author is badly specified */
        determine_author_info(author_ident);
        if (s->fp == NULL)
                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->display_comment_prefix = 1;
 +
+       /*
+        * Most hints are counter-productive when the commit has
+        * already started.
+        */
+       s->hints = 0;
        if (clean_message_contents)
                stripspace(&sb, 0);
  
         */
        if (!commitable && whence != FROM_MERGE && !allow_empty &&
            !(amend && is_a_merge(current_head))) {
 +              s->display_comment_prefix = old_display_comment_prefix;
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
                        fputs(_(empty_amend_advice), stderr);
@@@ -940,7 -950,6 +955,7 @@@ static const char *find_author_by_nickn
        struct rev_info revs;
        struct commit *commit;
        struct strbuf buf = STRBUF_INIT;
 +      struct string_list mailmap = STRING_LIST_INIT_NODUP;
        const char *av[20];
        int ac = 0;
  
        av[++ac] = buf.buf;
        av[++ac] = NULL;
        setup_revisions(ac, av, &revs, NULL);
 +      revs.mailmap = &mailmap;
 +      read_mailmap(revs.mailmap, NULL);
 +
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
                struct pretty_print_context ctx = {0};
                ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
 -              format_commit_message(commit, "%an <%ae>", &buf, &ctx);
 +              format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
 +              clear_mailmap(&mailmap);
                return strbuf_detach(&buf, NULL);
        }
        die(_("No existing author found with '%s'"), name);
@@@ -1101,7 -1106,7 +1116,7 @@@ static int parse_and_validate_options(i
        if (patch_interactive)
                interactive = 1;
  
 -      if (!!also + !!only + !!all + !!interactive > 1)
 +      if (also + only + all + interactive > 1)
                die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
        if (argc == 0 && (also || (only && !amend)))
                die(_("No paths with --include/--only does not make sense."));
@@@ -1192,10 -1197,6 +1207,10 @@@ static int git_status_config(const cha
                s->use_color = git_config_colorbool(k, v);
                return 0;
        }
 +      if (!strcmp(k, "status.displaycommentprefix")) {
 +              s->display_comment_prefix = git_config_bool(k, v);
 +              return 0;
 +      }
        if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
                int slot = parse_status_slot(k, 13);
                if (slot < 0)
@@@ -1242,14 -1243,14 +1257,14 @@@ int cmd_status(int argc, const char **a
                OPT_SET_INT(0, "long", &status_format,
                            N_("show status in long format (default)"),
                            STATUS_FORMAT_LONG),
 -              OPT_BOOLEAN('z', "null", &s.null_termination,
 -                          N_("terminate entries with NUL")),
 +              OPT_BOOL('z', "null", &s.null_termination,
 +                       N_("terminate entries with NUL")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
                  N_("mode"),
                  N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
 -              OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
 -                          N_("show ignored files")),
 +              OPT_BOOL(0, "ignored", &show_ignored_in_status,
 +                       N_("show ignored files")),
                { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
                  N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_status_usage, builtin_status_options);
  
-       wt_status_prepare(&s);
-       gitmodules_config();
-       git_config(git_status_config, &s);
-       determine_whence(&s);
+       status_init_config(&s, git_status_config);
        argc = parse_options(argc, argv, prefix,
                             builtin_status_options,
                             builtin_status_usage, 0);
        handle_untracked_files_arg(&s);
        if (show_ignored_in_status)
                s.show_ignored_files = 1;
 -      if (*argv)
 -              s.pathspec = get_pathspec(prefix, argv);
 +      parse_pathspec(&s.pathspec, 0,
 +                     PATHSPEC_PREFER_FULL,
 +                     prefix, argv);
  
 -      read_cache_preload(s.pathspec);
 -      refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
 +      read_cache_preload(&s.pathspec);
 +      refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
  
        fd = hold_locked_index(&index_lock, 0);
        if (0 <= fd)
@@@ -1449,24 -1446,24 +1461,24 @@@ int cmd_commit(int argc, const char **a
                OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
                OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
                OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
 -              OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
 -              OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")),
 +              OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
 +              OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
                OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
                OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
                OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
 -              OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")),
 +              OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
                { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
                  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
                /* end commit message options */
  
                OPT_GROUP(N_("Commit contents options")),
 -              OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")),
 -              OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")),
 -              OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")),
 -              OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")),
 -              OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")),
 -              OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
 -              OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")),
 +              OPT_BOOL('a', "all", &all, N_("commit all changed files")),
 +              OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
 +              OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
 +              OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
 +              OPT_BOOL('o', "only", &only, N_("commit only specified files")),
 +              OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
 +              OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
                OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
                            STATUS_FORMAT_SHORT),
                OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
                OPT_SET_INT(0, "long", &status_format,
                            N_("show status in long format (default)"),
                            STATUS_FORMAT_LONG),
 -              OPT_BOOLEAN('z', "null", &s.null_termination,
 -                          N_("terminate entries with NUL")),
 -              OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
 -              OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
 +              OPT_BOOL('z', "null", &s.null_termination,
 +                       N_("terminate entries with NUL")),
 +              OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
 +              OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
                /* end commit contents options */
  
 -              { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
 -                N_("ok to record an empty change"),
 -                PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
 -              { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
 -                N_("ok to record a change with an empty message"),
 -                PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
 +              OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
 +                              N_("ok to record an empty change")),
 +              OPT_HIDDEN_BOOL(0, "allow-empty-message", &allow_empty_message,
 +                              N_("ok to record a change with an empty message")),
  
                OPT_END()
        };
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_commit_usage, builtin_commit_options);
  
-       wt_status_prepare(&s);
-       gitmodules_config();
-       git_config(git_commit_config, &s);
+       status_init_config(&s, git_commit_config);
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
-       determine_whence(&s);
        s.colopts = 0;
  
        if (get_sha1("HEAD", sha1))
                                           !current_head
                                           ? NULL
                                           : current_head->object.sha1,
 -                                         0);
 +                                         0, NULL);
  
        nl = strchr(sb.buf, '\n');
        if (nl)
diff --combined wt-status.c
index 706a6f77a2fd95893cd64c703b7bf407a874547e,885ee666eec900e40a7f72516362abbf839c1801..cbdce726512f3daa5ad574c3aae07ed25b80c502
@@@ -1,5 -1,4 +1,5 @@@
  #include "cache.h"
 +#include "pathspec.h"
  #include "wt-status.h"
  #include "object.h"
  #include "dir.h"
@@@ -9,7 -8,6 +9,7 @@@
  #include "diffcore.h"
  #include "quote.h"
  #include "run-command.h"
 +#include "argv-array.h"
  #include "remote.h"
  #include "refs.h"
  #include "submodule.h"
@@@ -47,11 -45,9 +47,11 @@@ static void status_vprintf(struct wt_st
  
        strbuf_vaddf(&sb, fmt, ap);
        if (!sb.len) {
 -              strbuf_addch(&sb, comment_line_char);
 -              if (!trail)
 -                      strbuf_addch(&sb, ' ');
 +              if (s->display_comment_prefix) {
 +                      strbuf_addch(&sb, comment_line_char);
 +                      if (!trail)
 +                              strbuf_addch(&sb, ' ');
 +              }
                color_print_strbuf(s->fp, color, &sb);
                if (trail)
                        fprintf(s->fp, "%s", trail);
@@@ -62,7 -58,7 +62,7 @@@
                eol = strchr(line, '\n');
  
                strbuf_reset(&linebuf);
 -              if (at_bol) {
 +              if (at_bol && s->display_comment_prefix) {
                        strbuf_addch(&linebuf, comment_line_char);
                        if (*line != '\n' && *line != '\t')
                                strbuf_addch(&linebuf, ' ');
@@@ -132,7 -128,6 +132,7 @@@ void wt_status_prepare(struct wt_statu
        s->untracked.strdup_strings = 1;
        s->ignored.strdup_strings = 1;
        s->show_branch = -1;  /* unspecified */
 +      s->display_comment_prefix = 0;
  }
  
  static void wt_status_print_unmerged_header(struct wt_status *s)
                }
        }
  
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (s->whence != FROM_COMMIT)
                ;
@@@ -192,7 -187,7 +192,7 @@@ static void wt_status_print_cached_head
        const char *c = color(WT_STATUS_HEADER, s);
  
        status_printf_ln(s, c, _("Changes to be committed:"));
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (s->whence != FROM_COMMIT)
                ; /* NEEDSWORK: use "git reset --unresolve"??? */
@@@ -210,7 -205,7 +210,7 @@@ static void wt_status_print_dirty_heade
        const char *c = color(WT_STATUS_HEADER, s);
  
        status_printf_ln(s, c, _("Changes not staged for commit:"));
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (!has_deleted)
                status_printf_ln(s, c, _("  (use \"git add <file>...\" to update what will be committed)"));
@@@ -228,7 -223,7 +228,7 @@@ static void wt_status_print_other_heade
  {
        const char *c = color(WT_STATUS_HEADER, s);
        status_printf_ln(s, c, "%s:", what);
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        status_printf_ln(s, c, _("  (use \"git %s <file>...\" to include in what will be committed)"), how);
        status_printf_ln(s, c, "");
@@@ -443,7 -438,7 +443,7 @@@ static void wt_status_collect_changes_w
        }
        rev.diffopt.format_callback = wt_status_collect_changed_cb;
        rev.diffopt.format_callback_data = s;
 -      init_pathspec(&rev.prune_data, s->pathspec);
 +      copy_pathspec(&rev.prune_data, &s->pathspec);
        run_diff_files(&rev, 0);
  }
  
@@@ -468,20 -463,22 +468,20 @@@ static void wt_status_collect_changes_i
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 200;
        rev.diffopt.break_opt = 0;
 -      init_pathspec(&rev.prune_data, s->pathspec);
 +      copy_pathspec(&rev.prune_data, &s->pathspec);
        run_diff_index(&rev, 1);
  }
  
  static void wt_status_collect_changes_initial(struct wt_status *s)
  {
 -      struct pathspec pathspec;
        int i;
  
 -      init_pathspec(&pathspec, s->pathspec);
        for (i = 0; i < active_nr; i++) {
                struct string_list_item *it;
                struct wt_status_change_data *d;
                const struct cache_entry *ce = active_cache[i];
  
 -              if (!ce_path_match(ce, &pathspec))
 +              if (!ce_path_match(ce, &s->pathspec))
                        continue;
                it = string_list_insert(&s->change, ce->name);
                d = it->util;
                else
                        d->index_status = DIFF_STATUS_ADDED;
        }
 -      free_pathspec(&pathspec);
  }
  
  static void wt_status_collect_untracked(struct wt_status *s)
                dir.flags |= DIR_SHOW_IGNORED_TOO;
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, s->pathspec);
 +      fill_directory(&dir, &s->pathspec);
  
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
                if (cache_name_is_other(ent->name, ent->len) &&
 -                  match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
 +                  match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
                        string_list_insert(&s->untracked, ent->name);
                free(ent);
        }
        for (i = 0; i < dir.ignored_nr; i++) {
                struct dir_entry *ent = dir.ignored[i];
                if (cache_name_is_other(ent->name, ent->len) &&
 -                  match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
 +                  match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
                        string_list_insert(&s->ignored, ent->name);
                free(ent);
        }
@@@ -665,57 -663,29 +665,57 @@@ static void wt_status_print_submodule_s
        char summary_limit[64];
        char index[PATH_MAX];
        const char *env[] = { NULL, NULL };
 -      const char *argv[8];
 -
 -      env[0] =        index;
 -      argv[0] =       "submodule";
 -      argv[1] =       "summary";
 -      argv[2] =       uncommitted ? "--files" : "--cached";
 -      argv[3] =       "--for-status";
 -      argv[4] =       "--summary-limit";
 -      argv[5] =       summary_limit;
 -      argv[6] =       uncommitted ? NULL : (s->amend ? "HEAD^" : "HEAD");
 -      argv[7] =       NULL;
 +      struct argv_array argv = ARGV_ARRAY_INIT;
 +      struct strbuf cmd_stdout = STRBUF_INIT;
 +      struct strbuf summary = STRBUF_INIT;
 +      char *summary_content;
 +      size_t len;
  
        sprintf(summary_limit, "%d", s->submodule_summary);
        snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
  
 +      env[0] = index;
 +      argv_array_push(&argv, "submodule");
 +      argv_array_push(&argv, "summary");
 +      argv_array_push(&argv, uncommitted ? "--files" : "--cached");
 +      argv_array_push(&argv, "--for-status");
 +      argv_array_push(&argv, "--summary-limit");
 +      argv_array_push(&argv, summary_limit);
 +      if (!uncommitted)
 +              argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
 +
        memset(&sm_summary, 0, sizeof(sm_summary));
 -      sm_summary.argv = argv;
 +      sm_summary.argv = argv.argv;
        sm_summary.env = env;
        sm_summary.git_cmd = 1;
        sm_summary.no_stdin = 1;
        fflush(s->fp);
 -      sm_summary.out = dup(fileno(s->fp));    /* run_command closes it */
 +      sm_summary.out = -1;
 +
        run_command(&sm_summary);
 +      argv_array_clear(&argv);
 +
 +      len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);
 +
 +      /* prepend header, only if there's an actual output */
 +      if (len) {
 +              if (uncommitted)
 +                      strbuf_addstr(&summary, _("Submodules changed but not updated:"));
 +              else
 +                      strbuf_addstr(&summary, _("Submodule changes to be committed:"));
 +              strbuf_addstr(&summary, "\n\n");
 +      }
 +      strbuf_addbuf(&summary, &cmd_stdout);
 +      strbuf_release(&cmd_stdout);
 +
 +      if (s->display_comment_prefix) {
 +              summary_content = strbuf_detach(&summary, &len);
 +              strbuf_add_commented_lines(&summary, summary_content, len);
 +              free(summary_content);
 +      }
 +
 +      fputs(summary.buf, s->fp);
 +      strbuf_release(&summary);
  }
  
  static void wt_status_print_other(struct wt_status *s,
  
        strbuf_release(&buf);
        if (!column_active(s->colopts))
 -              return;
 +              goto conclude;
  
 -      strbuf_addf(&buf, "%s#\t%s",
 +      strbuf_addf(&buf, "%s%s\t%s",
                    color(WT_STATUS_HEADER, s),
 +                  s->display_comment_prefix ? "#" : "",
                    color(WT_STATUS_UNTRACKED, s));
        memset(&copts, 0, sizeof(copts));
        copts.padding = 1;
        print_columns(&output, s->colopts, &copts);
        string_list_clear(&output, 0);
        strbuf_release(&buf);
 +conclude:
 +      status_printf_ln(s, GIT_COLOR_NORMAL, "");
  }
  
  static void wt_status_print_verbose(struct wt_status *s)
@@@ -799,8 -766,6 +799,8 @@@ static void wt_status_print_tracking(st
        struct strbuf sb = STRBUF_INIT;
        const char *cp, *ep;
        struct branch *branch;
 +      char comment_line_string[3];
 +      int i;
  
        assert(s->branch && !s->is_initial);
        if (prefixcmp(s->branch, "refs/heads/"))
        if (!format_tracking_info(branch, &sb))
                return;
  
 +      i = 0;
 +      if (s->display_comment_prefix) {
 +              comment_line_string[i++] = comment_line_char;
 +              comment_line_string[i++] = ' ';
 +      }
 +      comment_line_string[i] = '\0';
 +
        for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
                color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
 -                               "%c %.*s", comment_line_char,
 +                               "%s%.*s", comment_line_string,
                                 (int)(ep - cp), cp);
 -      color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
 -                       comment_line_char);
 +      if (s->display_comment_prefix)
 +              color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
 +                               comment_line_char);
 +      else
 +              fprintf_ln(s->fp, "");
  }
  
  static int has_unmerged(struct wt_status *s)
@@@ -846,13 -801,13 +846,13 @@@ static void show_merge_in_progress(stru
  {
        if (has_unmerged(s)) {
                status_printf_ln(s, color, _("You have unmerged paths."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git commit\")"));
        } else {
                status_printf_ln(s, color,
                        _("All conflicts fixed but you are still merging."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (use \"git commit\" to conclude merge)"));
        }
@@@ -868,7 -823,7 +868,7 @@@ static void show_am_in_progress(struct 
        if (state->am_empty_patch)
                status_printf_ln(s, color,
                        _("The current patch is empty."));
-       if (advice_status_hints) {
+       if (s->hints) {
                if (!state->am_empty_patch)
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git am --continue\")"));
@@@ -941,7 -896,7 +941,7 @@@ static void show_rebase_in_progress(str
                else
                        status_printf_ln(s, color,
                                         _("You are currently rebasing."));
-               if (advice_status_hints) {
+               if (s->hints) {
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git rebase --continue\")"));
                        status_printf_ln(s, color,
                else
                        status_printf_ln(s, color,
                                         _("You are currently rebasing."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (all conflicts fixed: run \"git rebase --continue\")"));
        } else if (split_commit_in_progress(s)) {
                else
                        status_printf_ln(s, color,
                                         _("You are currently splitting a commit during a rebase."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (Once your working directory is clean, run \"git rebase --continue\")"));
        } else {
                else
                        status_printf_ln(s, color,
                                         _("You are currently editing a commit during a rebase."));
-               if (advice_status_hints && !s->amend) {
+               if (s->hints && !s->amend) {
                        status_printf_ln(s, color,
                                _("  (use \"git commit --amend\" to amend the current commit)"));
                        status_printf_ln(s, color,
@@@ -997,7 -952,7 +997,7 @@@ static void show_cherry_pick_in_progres
                                        const char *color)
  {
        status_printf_ln(s, color, _("You are currently cherry-picking."));
-       if (advice_status_hints) {
+       if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git cherry-pick --continue\")"));
@@@ -1016,7 -971,7 +1016,7 @@@ static void show_revert_in_progress(str
  {
        status_printf_ln(s, color, _("You are currently reverting commit %s."),
                         find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
-       if (advice_status_hints) {
+       if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git revert --continue\")"));
@@@ -1040,7 -995,7 +1040,7 @@@ static void show_bisect_in_progress(str
        else
                status_printf_ln(s, color,
                                 _("You are currently bisecting."));
-       if (advice_status_hints)
+       if (s->hints)
                status_printf_ln(s, color,
                        _("  (use \"git bisect reset\" to get back to the original branch)"));
        wt_status_print_trailer(s);
@@@ -1278,7 -1233,7 +1278,7 @@@ void wt_status_print(struct wt_status *
                }
        } else if (s->commitable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
-                       advice_status_hints
+                       s->hints
                        ? _(" (use -u option to show untracked files)") : "");
  
        if (s->verbose)
                else if (s->nowarn)
                        ; /* nothing */
                else if (s->workdir_dirty) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("no changes added to commit "
                                         "(use \"git add\" and/or \"git commit -a\")\n"));
                        else
                                printf(_("no changes added to commit\n"));
                } else if (s->untracked.nr) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing added to commit but untracked files "
                                         "present (use \"git add\" to track)\n"));
                        else
                                printf(_("nothing added to commit but untracked files present\n"));
                } else if (s->is_initial) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing to commit (create/copy files "
                                         "and use \"git add\" to track)\n"));
                        else
                                printf(_("nothing to commit\n"));
                } else if (!s->show_untracked_files) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing to commit (use -u to show untracked files)\n"));
                        else
                                printf(_("nothing to commit\n"));
@@@ -1410,7 -1365,6 +1410,7 @@@ static void wt_shortstatus_print_tracki
        const char *base;
        const char *branch_name;
        int num_ours, num_theirs;
 +      int upstream_is_gone = 0;
  
        color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
  
        branch = branch_get(s->branch + 11);
        if (s->is_initial)
                color_fprintf(s->fp, header_color, _("Initial commit on "));
 -      if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
 -              color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 +
 +      color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 +
 +      switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
 +      case 0:
 +              /* no base */
                fputc(s->null_termination ? '\0' : '\n', s->fp);
                return;
 +      case -1:
 +              /* with "gone" base */
 +              upstream_is_gone = 1;
 +              break;
 +      default:
 +              /* with base */
 +              break;
        }
  
        base = branch->merge[0]->dst;
        base = shorten_unambiguous_ref(base, 0);
 -      color_fprintf(s->fp, branch_color_local, "%s", branch_name);
        color_fprintf(s->fp, header_color, "...");
        color_fprintf(s->fp, branch_color_remote, "%s", base);
  
 +      if (!upstream_is_gone && !num_ours && !num_theirs) {
 +              fputc(s->null_termination ? '\0' : '\n', s->fp);
 +              return;
 +      }
 +
        color_fprintf(s->fp, header_color, " [");
 -      if (!num_ours) {
 +      if (upstream_is_gone) {
 +              color_fprintf(s->fp, header_color, _("gone"));
 +      } else if (!num_ours) {
                color_fprintf(s->fp, header_color, _("behind "));
                color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
        } else if (!num_theirs) {
diff --combined wt-status.h
index 009c954c73461366434ce7ab51d03fe0dd15f505,b4c9cb46c75a6fc67302987611894c682ec2d5a6..9341c569a52e53cc939fa3bd94e013bbc2c8444d
@@@ -44,13 -44,12 +44,13 @@@ struct wt_status 
        int is_initial;
        char *branch;
        const char *reference;
 -      const char **pathspec;
 +      struct pathspec pathspec;
        int verbose;
        int amend;
        enum commit_whence whence;
        int nowarn;
        int use_color;
 +      int display_comment_prefix;
        int relative_paths;
        int submodule_summary;
        int show_ignored_files;
@@@ -60,6 -59,7 +60,7 @@@
        unsigned colopts;
        int null_termination;
        int show_branch;
+       int hints;
  
        /* These are computed during processing of the individual sections */
        int commitable;