Merge branch 'ab/gc-auto-in-commit'
authorJunio C Hamano <gitster@pobox.com>
Thu, 8 Mar 2018 20:36:30 +0000 (12:36 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 8 Mar 2018 20:36:30 +0000 (12:36 -0800)
"git commit" used to run "gc --auto" near the end, which was lost
when the command was reimplemented in C by mistake.

* ab/gc-auto-in-commit:
commit: run git gc --auto just before the post-commit hook

1  2 
builtin/commit.c
diff --combined builtin/commit.c
index c14f95dbf6b11826f11e728354e6c7107878a07a,3a28a2ac61c498f9162c9bf43f4dc8d83a8ab1c0..092077c3eef7a81b3d814cee951cee98e37eac02
@@@ -31,7 -31,9 +31,7 @@@
  #include "gpg-interface.h"
  #include "column.h"
  #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>..."),
@@@ -43,6 -45,31 +43,6 @@@ static const char * const builtin_statu
        NULL
  };
  
 -static const char implicit_ident_advice_noconfig[] =
 -N_("Your name and email address were configured automatically based\n"
 -"on your username and hostname. Please check that they are accurate.\n"
 -"You can suppress this message by setting them explicitly. Run the\n"
 -"following command and follow the instructions in your editor to edit\n"
 -"your configuration file:\n"
 -"\n"
 -"    git config --global --edit\n"
 -"\n"
 -"After doing this, you may fix the identity used for this commit with:\n"
 -"\n"
 -"    git commit --amend --reset-author\n");
 -
 -static const char implicit_ident_advice_config[] =
 -N_("Your name and email address were configured automatically based\n"
 -"on your username and hostname. Please check that they are accurate.\n"
 -"You can suppress this message by setting them explicitly:\n"
 -"\n"
 -"    git config --global user.name \"Your Name\"\n"
 -"    git config --global user.email you@example.com\n"
 -"\n"
 -"After doing this, you may fix the identity used for this commit with:\n"
 -"\n"
 -"    git commit --amend --reset-author\n");
 -
  static const char empty_amend_advice[] =
  N_("You asked to amend the most recent commit, but doing so would make\n"
  "it empty. You can repeat your command with --allow-empty, or you can\n"
@@@ -66,6 -93,8 +66,6 @@@ 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 struct lock_file index_lock; /* real index */
  static struct lock_file false_lock; /* used only for partial commits */
@@@ -99,7 -128,12 +99,7 @@@ static char *sign_commit
   * if editor is used, and only the whitespaces if the message
   * is specified explicitly.
   */
 -static enum {
 -      CLEANUP_SPACE,
 -      CLEANUP_NONE,
 -      CLEANUP_SCISSORS,
 -      CLEANUP_ALL
 -} cleanup_mode;
 +static enum commit_msg_cleanup_mode cleanup_mode;
  static const char *cleanup_arg;
  
  static enum commit_whence whence;
@@@ -639,7 -673,7 +639,7 @@@ static int prepare_to_commit(const cha
        struct strbuf sb = STRBUF_INIT;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
 -      int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
 +      int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
        int old_display_comment_prefix;
  
        /* This checks and barfs if author is badly specified */
                struct ident_split ci, ai;
  
                if (whence != FROM_COMMIT) {
 -                      if (cleanup_mode == CLEANUP_SCISSORS)
 +                      if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                                wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                            whence == FROM_MERGE
                }
  
                fprintf(s->fp, "\n");
 -              if (cleanup_mode == CLEANUP_ALL)
 +              if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\nwith '%c' will be ignored, and an empty"
                                  " message aborts the commit.\n"), comment_line_char);
 -              else if (cleanup_mode == CLEANUP_SCISSORS && whence == FROM_COMMIT)
 +              else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
 +                       whence == FROM_COMMIT)
                        wt_status_add_cut_line(s->fp);
 -              else /* CLEANUP_SPACE, that is. */
 +              else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\n"
        return 1;
  }
  
 -static int rest_is_empty(struct strbuf *sb, int start)
 -{
 -      int i, eol;
 -      const char *nl;
 -
 -      /* Check if the rest is just whitespace and Signed-off-by's. */
 -      for (i = start; i < sb->len; i++) {
 -              nl = memchr(sb->buf + i, '\n', sb->len - i);
 -              if (nl)
 -                      eol = nl - sb->buf;
 -              else
 -                      eol = sb->len;
 -
 -              if (strlen(sign_off_header) <= eol - i &&
 -                  starts_with(sb->buf + i, sign_off_header)) {
 -                      i = eol;
 -                      continue;
 -              }
 -              while (i < eol)
 -                      if (!isspace(sb->buf[i++]))
 -                              return 0;
 -      }
 -
 -      return 1;
 -}
 -
 -/*
 - * Find out if the message in the strbuf contains only whitespace and
 - * Signed-off-by lines.
 - */
 -static int message_is_empty(struct strbuf *sb)
 -{
 -      if (cleanup_mode == CLEANUP_NONE && sb->len)
 -              return 0;
 -      return rest_is_empty(sb, 0);
 -}
 -
 -/*
 - * See if the user edited the message in the editor or left what
 - * was in the template intact
 - */
 -static int template_untouched(struct strbuf *sb)
 -{
 -      struct strbuf tmpl = STRBUF_INIT;
 -      const char *start;
 -
 -      if (cleanup_mode == CLEANUP_NONE && sb->len)
 -              return 0;
 -
 -      if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
 -              return 0;
 -
 -      strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
 -      if (!skip_prefix(sb->buf, tmpl.buf, &start))
 -              start = sb->buf;
 -      strbuf_release(&tmpl);
 -      return rest_is_empty(sb, start - sb->buf);
 -}
 -
  static const char *find_author_by_nickname(const char *name)
  {
        struct rev_info revs;
@@@ -1061,9 -1153,6 +1061,9 @@@ static void finalize_deferred_config(st
                s->show_branch = status_deferred_config.show_branch;
        if (s->show_branch < 0)
                s->show_branch = 0;
 +
 +      if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED)
 +              s->ahead_behind_flags = AHEAD_BEHIND_FULL;
  }
  
  static int parse_and_validate_options(int argc, const char *argv[],
        if (argc == 0 && (also || (only && !amend && !allow_empty)))
                die(_("No paths with --include/--only does not make sense."));
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 -              cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
 +              cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
 +                                          COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "verbatim"))
 -              cleanup_mode = CLEANUP_NONE;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
        else if (!strcmp(cleanup_arg, "whitespace"))
 -              cleanup_mode = CLEANUP_SPACE;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "strip"))
 -              cleanup_mode = CLEANUP_ALL;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
        else if (!strcmp(cleanup_arg, "scissors"))
 -              cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
 +              cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
 +                                          COMMIT_MSG_CLEANUP_SPACE;
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
  
@@@ -1280,8 -1367,6 +1280,8 @@@ int cmd_status(int argc, const char **a
                         N_("show branch information")),
                OPT_BOOL(0, "show-stash", &s.show_stash,
                         N_("show stash information")),
 +              OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
 +                       N_("compute full ahead/behind values")),
                { OPTION_CALLBACK, 0, "porcelain", &status_format,
                  N_("version"), N_("machine-readable output"),
                  PARSE_OPT_OPTARG, opt_parse_porcelain },
        return 0;
  }
  
 -static const char *implicit_ident_advice(void)
 -{
 -      char *user_config = expand_user_path("~/.gitconfig", 0);
 -      char *xdg_config = xdg_config_home("config");
 -      int config_exists = file_exists(user_config) || file_exists(xdg_config);
 -
 -      free(user_config);
 -      free(xdg_config);
 -
 -      if (config_exists)
 -              return _(implicit_ident_advice_config);
 -      else
 -              return _(implicit_ident_advice_noconfig);
 -
 -}
 -
 -static void print_summary(const char *prefix, const struct object_id *oid,
 -                        int initial_commit)
 -{
 -      struct rev_info rev;
 -      struct commit *commit;
 -      struct strbuf format = STRBUF_INIT;
 -      const char *head;
 -      struct pretty_print_context pctx = {0};
 -      struct strbuf author_ident = STRBUF_INIT;
 -      struct strbuf committer_ident = STRBUF_INIT;
 -
 -      commit = lookup_commit(oid);
 -      if (!commit)
 -              die(_("couldn't look up newly created commit"));
 -      if (parse_commit(commit))
 -              die(_("could not parse newly created commit"));
 -
 -      strbuf_addstr(&format, "format:%h] %s");
 -
 -      format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
 -      format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
 -      if (strbuf_cmp(&author_ident, &committer_ident)) {
 -              strbuf_addstr(&format, "\n Author: ");
 -              strbuf_addbuf_percentquote(&format, &author_ident);
 -      }
 -      if (author_date_is_interesting()) {
 -              struct strbuf date = STRBUF_INIT;
 -              format_commit_message(commit, "%ad", &date, &pctx);
 -              strbuf_addstr(&format, "\n Date: ");
 -              strbuf_addbuf_percentquote(&format, &date);
 -              strbuf_release(&date);
 -      }
 -      if (!committer_ident_sufficiently_given()) {
 -              strbuf_addstr(&format, "\n Committer: ");
 -              strbuf_addbuf_percentquote(&format, &committer_ident);
 -              if (advice_implicit_identity) {
 -                      strbuf_addch(&format, '\n');
 -                      strbuf_addstr(&format, implicit_ident_advice());
 -              }
 -      }
 -      strbuf_release(&author_ident);
 -      strbuf_release(&committer_ident);
 -
 -      init_revisions(&rev, prefix);
 -      setup_revisions(0, NULL, &rev, NULL);
 -
 -      rev.diff = 1;
 -      rev.diffopt.output_format =
 -              DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
 -
 -      rev.verbose_header = 1;
 -      rev.show_root_diff = 1;
 -      get_commit_format(format.buf, &rev);
 -      rev.always_show_header = 0;
 -      rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
 -      rev.diffopt.break_opt = 0;
 -      diff_setup_done(&rev.diffopt);
 -
 -      head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 -      if (!head)
 -              die_errno(_("unable to resolve HEAD after creating commit"));
 -      if (!strcmp(head, "HEAD"))
 -              head = _("detached HEAD");
 -      else
 -              skip_prefix(head, "refs/heads/", &head);
 -      printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : "");
 -
 -      if (!log_tree_commit(&rev, commit)) {
 -              rev.always_show_header = 1;
 -              rev.use_terminator = 1;
 -              log_tree_commit(&rev, commit);
 -      }
 -
 -      strbuf_release(&format);
 -}
 -
  static int git_commit_config(const char *k, const char *v, void *cb)
  {
        struct wt_status *s = cb;
        return git_status_config(k, v, s);
  }
  
 -static int run_rewrite_hook(const struct object_id *oldoid,
 -                          const struct object_id *newoid)
 -{
 -      struct child_process proc = CHILD_PROCESS_INIT;
 -      const char *argv[3];
 -      int code;
 -      struct strbuf sb = STRBUF_INIT;
 -
 -      argv[0] = find_hook("post-rewrite");
 -      if (!argv[0])
 -              return 0;
 -
 -      argv[1] = "amend";
 -      argv[2] = NULL;
 -
 -      proc.argv = argv;
 -      proc.in = -1;
 -      proc.stdout_to_stderr = 1;
 -
 -      code = start_command(&proc);
 -      if (code)
 -              return code;
 -      strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
 -      sigchain_push(SIGPIPE, SIG_IGN);
 -      write_in_full(proc.in, sb.buf, sb.len);
 -      close(proc.in);
 -      strbuf_release(&sb);
 -      sigchain_pop(SIGPIPE);
 -      return finish_command(&proc);
 -}
 -
  int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
  {
        struct argv_array hook_env = ARGV_ARRAY_INIT;
  
  int cmd_commit(int argc, const char **argv, const char *prefix)
  {
+       const char *argv_gc_auto[] = {"gc", "--auto", NULL};
        static struct wt_status s;
        static struct option builtin_commit_options[] = {
                OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
                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_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
 +                       N_("compute full ahead/behind values")),
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
                OPT_SET_INT(0, "long", &status_format,
        struct strbuf sb = STRBUF_INIT;
        struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
 -      char *nl;
        struct object_id oid;
        struct commit_list *parents = NULL;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
 -      struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
  
        if (argc == 2 && !strcmp(argv[1], "-h"))
        }
  
        if (verbose || /* Truncate the message just before the diff, if any. */
 -          cleanup_mode == CLEANUP_SCISSORS)
 +          cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
 -      if (cleanup_mode != CLEANUP_NONE)
 -              strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
 +      if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
 +              strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
  
 -      if (message_is_empty(&sb) && !allow_empty_message) {
 +      if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
 -      if (template_untouched(&sb) && !allow_empty_message) {
 +      if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
                exit(1);
                append_merge_tag_headers(parents, &tail);
        }
  
 -      if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
 -                       parents, oid.hash, author_ident.buf, sign_commit, extra)) {
 +      if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
 +                               parents, &oid, author_ident.buf, sign_commit,
 +                               extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
        }
        strbuf_release(&author_ident);
        free_commit_extra_headers(extra);
  
 -      nl = strchr(sb.buf, '\n');
 -      if (nl)
 -              strbuf_setlen(&sb, nl + 1 - sb.buf);
 -      else
 -              strbuf_addch(&sb, '\n');
 -      strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
 -      strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
 -
 -      transaction = ref_transaction_begin(&err);
 -      if (!transaction ||
 -          ref_transaction_update(transaction, "HEAD", &oid,
 -                                 current_head
 -                                 ? &current_head->object.oid : &null_oid,
 -                                 0, sb.buf, &err) ||
 -          ref_transaction_commit(transaction, &err)) {
 +      if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
 +                                  &err)) {
                rollback_index_files();
                die("%s", err.buf);
        }
 -      ref_transaction_free(transaction);
  
        unlink(git_path_cherry_pick_head());
        unlink(git_path_revert_head());
                     "not exceeded, and then \"git reset HEAD\" to recover."));
  
        rerere(0);
+       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
 -              struct notes_rewrite_cfg *cfg;
 -              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.oid, &oid);
 -                      finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
 -              }
 -              run_rewrite_hook(&current_head->object.oid, &oid);
 +              commit_post_rewrite(current_head, &oid);
 +      }
 +      if (!quiet) {
 +              unsigned int flags = 0;
 +
 +              if (!current_head)
 +                      flags |= SUMMARY_INITIAL_COMMIT;
 +              if (author_date_is_interesting())
 +                      flags |= SUMMARY_SHOW_AUTHOR_DATE;
 +              print_commit_summary(prefix, &oid, flags);
        }
 -      if (!quiet)
 -              print_summary(prefix, &oid, !current_head);
  
        UNLEAK(err);
        UNLEAK(sb);