Merge branch 'nd/commit-editor-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Tue, 25 Mar 2014 18:07:47 +0000 (11:07 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 25 Mar 2014 18:07:48 +0000 (11:07 -0700)
"git commit --cleanup=<mode>" learned a new mode, scissors.

* nd/commit-editor-cleanup:
commit: add --cleanup=scissors
wt-status.c: move cut-line print code out to wt_status_add_cut_line
wt-status.c: make cut_line[] const to shrink .data section a bit

1  2 
Documentation/git-commit.txt
builtin/commit.c
wt-status.c
index 7c42e9cabcb250b93cd286e8efe23df90ea0f71c,794823303581e161c21f4147cb0d453ba0cfc816..429267abf640ef42b5bf9361ed8ab78f6509f77f
@@@ -176,7 -176,7 +176,7 @@@ OPTION
  --cleanup=<mode>::
        This option determines how the supplied commit message should be
        cleaned up before committing.  The '<mode>' can be `strip`,
-       `whitespace`, `verbatim`, or `default`.
+       `whitespace`, `verbatim`, `scissors` or `default`.
  +
  --
  strip::
@@@ -186,6 -186,12 +186,12 @@@ whitespace:
        Same as `strip` except #commentary is not removed.
  verbatim::
        Do not change the message at all.
+ scissors::
+       Same as `whitespace`, except that everything from (and
+       including) the line
+       "`# ------------------------ >8 ------------------------`"
+       is truncated if the message is to be edited. "`#`" can be
+       customized with core.commentChar.
  default::
        Same as `strip` if the message is to be edited.
        Otherwise `whitespace`.
@@@ -302,10 -308,6 +308,10 @@@ configuration variable documented in li
  --gpg-sign[=<keyid>]::
        GPG-sign commit.
  
 +--no-gpg-sign::
 +      Countermand `commit.gpgsign` configuration variable that is
 +      set to force each and every commit to be signed.
 +
  \--::
        Do not interpret any more arguments as options.
  
diff --combined builtin/commit.c
index 3783bcadcd5232ceccab7f4fd2559a9999c53ffa,1033c500d22d06b903c7f9c1331ed993e42a86ca..38f34e7cd3c7ffd482eb13fcf810346e1da4d944
@@@ -113,6 -113,7 +113,7 @@@ static char *sign_commit
  static enum {
        CLEANUP_SPACE,
        CLEANUP_NONE,
+       CLEANUP_SCISSORS,
        CLEANUP_ALL
  } cleanup_mode;
  static const char *cleanup_arg;
@@@ -234,7 -235,7 +235,7 @@@ static int list_paths(struct string_lis
  
                if (ce->ce_flags & CE_UPDATE)
                        continue;
 -              if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
 +              if (!ce_path_match(ce, pattern, m))
                        continue;
                item = string_list_insert(list, ce->name);
                if (ce_skip_worktree(ce))
@@@ -307,6 -308,7 +308,6 @@@ static char *prepare_index(int argc, co
        int fd;
        struct string_list partial;
        struct pathspec pathspec;
 -      char *old_index_env = NULL;
        int refresh_flags = REFRESH_QUIET;
  
        if (is_status)
                die(_("index file corrupt"));
  
        if (interactive) {
 +              char *old_index_env = NULL;
                fd = hold_locked_index(&index_lock, 1);
  
                refresh_cache_or_die(refresh_flags);
@@@ -600,10 -601,12 +601,10 @@@ static int prepare_to_commit(const cha
  {
        struct stat statbuf;
        struct strbuf committer_ident = STRBUF_INIT;
 -      int commitable, saved_color_setting;
 +      int commitable;
        struct strbuf sb = STRBUF_INIT;
 -      char *buffer;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
 -      int ident_shown = 0;
        int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
        int old_display_comment_prefix;
  
                                  logfile);
                hook_arg1 = "message";
        } else if (use_message) {
 +              char *buffer;
                buffer = strstr(use_message_buffer, "\n\n");
                if (!use_editor && (!buffer || buffer[2] == '\0'))
                        die(_("commit has empty message"));
        /* This checks if committer ident is explicitly given */
        strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
        if (use_editor && include_status) {
 +              int ident_shown = 0;
 +              int saved_color_setting;
                char *ai_tmp, *ci_tmp;
-               if (whence != FROM_COMMIT)
+               if (whence != FROM_COMMIT) {
+                       if (cleanup_mode == CLEANUP_SCISSORS)
+                               wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                            whence == FROM_MERGE
                                ? _("\n"
                                git_path(whence == FROM_MERGE
                                         ? "MERGE_HEAD"
                                         : "CHERRY_PICK_HEAD"));
+               }
  
                fprintf(s->fp, "\n");
                if (cleanup_mode == CLEANUP_ALL)
                                _("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)
+                       wt_status_add_cut_line(s->fp);
                else /* CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
@@@ -1133,6 -1138,8 +1139,8 @@@ static int parse_and_validate_options(i
                cleanup_mode = CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "strip"))
                cleanup_mode = CLEANUP_ALL;
+       else if (!strcmp(cleanup_arg, "scissors"))
+               cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
  
@@@ -1407,10 -1414,6 +1415,10 @@@ static int git_commit_config(const cha
        }
        if (!strcmp(k, "commit.cleanup"))
                return git_config_string(&cleanup_arg, k, v);
 +      if (!strcmp(k, "commit.gpgsign")) {
 +              sign_commit = git_config_bool(k, v) ? "" : NULL;
 +              return 0;
 +      }
  
        status = git_gpg_config(k, v, NULL);
        if (status)
@@@ -1515,6 -1518,7 +1523,6 @@@ int cmd_commit(int argc, const char **a
        struct ref_lock *ref_lock;
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
 -      int allow_fast_forward = 1;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
  
        } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
                FILE *fp;
 +              int allow_fast_forward = 1;
  
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
                die(_("could not read commit message: %s"), strerror(saved_errno));
        }
  
-       /* Truncate the message just before the diff, if any. */
-       if (verbose)
+       if (verbose || /* Truncate the message just before the diff, if any. */
+           cleanup_mode == CLEANUP_SCISSORS)
                wt_status_truncate_message_at_cut_line(&sb);
  
        if (cleanup_mode != CLEANUP_NONE)
diff --combined wt-status.c
index c89c3bb5373c49490980eba45f5a81707cc79bea,ed31b6afbeadf93d23b5d9c4c3005074c7744fa3..e1827faf073ce384bea6a697dd903ffc643bdfdc
@@@ -17,7 -17,7 +17,7 @@@
  #include "strbuf.h"
  #include "utf8.h"
  
- static char cut_line[] =
+ static const char cut_line[] =
  "------------------------ >8 ------------------------\n";
  
  static char default_wt_status_colors[][COLOR_MAXLEN] = {
@@@ -245,92 -245,53 +245,92 @@@ static void wt_status_print_trailer(str
  
  #define quote_path quote_path_relative
  
 -static void wt_status_print_unmerged_data(struct wt_status *s,
 -                                        struct string_list_item *it)
 +static const char *wt_status_unmerged_status_string(int stagemask)
  {
 -      const char *c = color(WT_STATUS_UNMERGED, s);
 -      struct wt_status_change_data *d = it->util;
 -      struct strbuf onebuf = STRBUF_INIT;
 -      const char *one, *how = _("bug");
 -
 -      one = quote_path(it->string, s->prefix, &onebuf);
 -      status_printf(s, color(WT_STATUS_HEADER, s), "\t");
 -      switch (d->stagemask) {
 -      case 1: how = _("both deleted:"); break;
 -      case 2: how = _("added by us:"); break;
 -      case 3: how = _("deleted by them:"); break;
 -      case 4: how = _("added by them:"); break;
 -      case 5: how = _("deleted by us:"); break;
 -      case 6: how = _("both added:"); break;
 -      case 7: how = _("both modified:"); break;
 +      switch (stagemask) {
 +      case 1:
 +              return _("both deleted:");
 +      case 2:
 +              return _("added by us:");
 +      case 3:
 +              return _("deleted by them:");
 +      case 4:
 +              return _("added by them:");
 +      case 5:
 +              return _("deleted by us:");
 +      case 6:
 +              return _("both added:");
 +      case 7:
 +              return _("both modified:");
 +      default:
 +              die(_("bug: unhandled unmerged status %x"), stagemask);
        }
 -      status_printf_more(s, c, "%-20s%s\n", how, one);
 -      strbuf_release(&onebuf);
  }
  
  static const char *wt_status_diff_status_string(int status)
  {
        switch (status) {
        case DIFF_STATUS_ADDED:
 -              return _("new file");
 +              return _("new file:");
        case DIFF_STATUS_COPIED:
 -              return _("copied");
 +              return _("copied:");
        case DIFF_STATUS_DELETED:
 -              return _("deleted");
 +              return _("deleted:");
        case DIFF_STATUS_MODIFIED:
 -              return _("modified");
 +              return _("modified:");
        case DIFF_STATUS_RENAMED:
 -              return _("renamed");
 +              return _("renamed:");
        case DIFF_STATUS_TYPE_CHANGED:
 -              return _("typechange");
 +              return _("typechange:");
        case DIFF_STATUS_UNKNOWN:
 -              return _("unknown");
 +              return _("unknown:");
        case DIFF_STATUS_UNMERGED:
 -              return _("unmerged");
 +              return _("unmerged:");
        default:
                return NULL;
        }
  }
  
 +static int maxwidth(const char *(*label)(int), int minval, int maxval)
 +{
 +      int result = 0, i;
 +
 +      for (i = minval; i <= maxval; i++) {
 +              const char *s = label(i);
 +              int len = s ? utf8_strwidth(s) : 0;
 +              if (len > result)
 +                      result = len;
 +      }
 +      return result;
 +}
 +
 +static void wt_status_print_unmerged_data(struct wt_status *s,
 +                                        struct string_list_item *it)
 +{
 +      const char *c = color(WT_STATUS_UNMERGED, s);
 +      struct wt_status_change_data *d = it->util;
 +      struct strbuf onebuf = STRBUF_INIT;
 +      static char *padding;
 +      static int label_width;
 +      const char *one, *how;
 +      int len;
 +
 +      if (!padding) {
 +              label_width = maxwidth(wt_status_unmerged_status_string, 1, 7);
 +              label_width += strlen(" ");
 +              padding = xmallocz(label_width);
 +              memset(padding, ' ', label_width);
 +      }
 +
 +      one = quote_path(it->string, s->prefix, &onebuf);
 +      status_printf(s, color(WT_STATUS_HEADER, s), "\t");
 +
 +      how = wt_status_unmerged_status_string(d->stagemask);
 +      len = label_width - utf8_strwidth(how);
 +      status_printf_more(s, c, "%s%.*s%s\n", how, len, padding, one);
 +      strbuf_release(&onebuf);
 +}
 +
  static void wt_status_print_change_data(struct wt_status *s,
                                        int change_type,
                                        struct string_list_item *it)
        struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
        struct strbuf extra = STRBUF_INIT;
        static char *padding;
 +      static int label_width;
        const char *what;
        int len;
  
        if (!padding) {
 -              int width = 0;
 -              /* If DIFF_STATUS_* uses outside this range, we're in trouble */
 -              for (status = 'A'; status <= 'Z'; status++) {
 -                      what = wt_status_diff_status_string(status);
 -                      len = what ? strlen(what) : 0;
 -                      if (len > width)
 -                              width = len;
 -              }
 -              width += 2;     /* colon and a space */
 -              padding = xmallocz(width);
 -              memset(padding, ' ', width);
 +              /* If DIFF_STATUS_* uses outside the range [A..Z], we're in trouble */
 +              label_width = maxwidth(wt_status_diff_status_string, 'A', 'Z');
 +              label_width += strlen(" ");
 +              padding = xmallocz(label_width);
 +              memset(padding, ' ', label_width);
        }
  
        one_name = two_name = it->string;
        what = wt_status_diff_status_string(status);
        if (!what)
                die(_("bug: unhandled diff status %c"), status);
 -      /* 1 for colon, which is not part of "what" */
 -      len = strlen(padding) - (utf8_strwidth(what) + 1);
 +      len = label_width - utf8_strwidth(what);
        assert(len >= 0);
        if (status == DIFF_STATUS_COPIED || status == DIFF_STATUS_RENAMED)
 -              status_printf_more(s, c, "%s:%.*s%s -> %s",
 +              status_printf_more(s, c, "%s%.*s%s -> %s",
                                   what, len, padding, one, two);
        else
 -              status_printf_more(s, c, "%s:%.*s%s",
 +              status_printf_more(s, c, "%s%.*s%s",
                                   what, len, padding, one);
        if (extra.len) {
                status_printf_more(s, color(WT_STATUS_HEADER, s), "%s", extra.buf);
@@@ -543,7 -510,7 +543,7 @@@ static void wt_status_collect_changes_i
                struct wt_status_change_data *d;
                const struct cache_entry *ce = active_cache[i];
  
 -              if (!ce_path_match(ce, &s->pathspec))
 +              if (!ce_path_match(ce, &s->pathspec, NULL))
                        continue;
                it = string_list_insert(&s->change, ce->name);
                d = it->util;
@@@ -585,7 -552,7 +585,7 @@@ static void wt_status_collect_untracked
        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_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
 +                  dir_path_match(ent, &s->pathspec, 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_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
 +                  dir_path_match(ent, &s->pathspec, 0, NULL))
                        string_list_insert(&s->ignored, ent->name);
                free(ent);
        }
@@@ -841,6 -808,17 +841,17 @@@ void wt_status_truncate_message_at_cut_
        strbuf_release(&pattern);
  }
  
+ void wt_status_add_cut_line(FILE *fp)
+ {
+       const char *explanation = _("Do not touch the line above.\nEverything below will be removed.");
+       struct strbuf buf = STRBUF_INIT;
+       fprintf(fp, "%c %s", comment_line_char, cut_line);
+       strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+       fputs(buf.buf, fp);
+       strbuf_release(&buf);
+ }
  static void wt_status_print_verbose(struct wt_status *s)
  {
        struct rev_info rev;
         * diff before committing.
         */
        if (s->fp != stdout) {
-               const char *explanation = _("Do not touch the line above.\nEverything below will be removed.");
-               struct strbuf buf = STRBUF_INIT;
                rev.diffopt.use_color = 0;
-               fprintf(s->fp, "%c %s", comment_line_char, cut_line);
-               strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
-               fputs(buf.buf, s->fp);
-               strbuf_release(&buf);
+               wt_status_add_cut_line(s->fp);
        }
        run_diff_index(&rev, 1);
  }