core.commentChar starts with '#' as in default but if it's already in
the prepared message, find another one among a small subset. This
should stop surprises because git strips some lines unexpectedly.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 Documentation/config.txt |  3 +++
 builtin/commit.c         | 36 ++++++++++++++++++++++++++++++++++++
 cache.h                  |  1 +
 config.c                 |  2 ++
 environment.c            |  1 +
 t/t7502-commit.sh        | 25 +++++++++++++++++++++++++
 6 files changed, 68 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1932e9b..d5bf4d0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -544,6 +544,9 @@ core.commentchar::
        messages consider a line that begins with this character
        commented, and removes them after the editor returns
        (default '#').
++
+If set to "auto", `git-commit` would select a character that is not
+the beginning character of any line of existing commit messages.
 
 sequence.editor::
        Text editor used by `git rebase -i` for editing the rebase instruction 
file.
diff --git a/builtin/commit.c b/builtin/commit.c
index 9cfef6c..039b426 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -594,6 +594,40 @@ static char *cut_ident_timestamp_part(char *string)
        return ket;
 }
 
+static void adjust_comment_line_char(const struct strbuf *sb)
+{
+       char candidates[] = " @!#$%^&|:;~";
+       char *candidate;
+       const char *p;
+
+       if (!sb->len)
+               return;
+
+       if (!strchr(candidates, comment_line_char))
+               candidates[0] = comment_line_char;
+       p = sb->buf;
+       candidate = strchr(candidates, *p);
+       if (candidate)
+               *candidate = ' ';
+       for (p = sb->buf; *p; p++) {
+               if ((p[0] == '\n' || p[0] == '\r') && p[1]) {
+                       candidate = strchr(candidates, p[1]);
+                       if (candidate)
+                               *candidate = ' ';
+               }
+       }
+
+       if (candidates[0] == comment_line_char)
+               return;
+       for (p = candidates; *p == ' '; p++)
+               ;
+       if (!*p)
+               die(_("the comment character '%c' exists in the commit 
message\n"
+                     "Please choose another character for core.commentChar"),
+                   comment_line_char);
+       comment_line_char = *p;
+}
+
 static int prepare_to_commit(const char *index_file, const char *prefix,
                             struct commit *current_head,
                             struct wt_status *s,
@@ -748,6 +782,8 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                die_errno(_("could not write commit template"));
 
+       if (auto_comment_line_char)
+               adjust_comment_line_char(&sb);
        strbuf_release(&sb);
 
        /* This checks if committer ident is explicitly given */
diff --git a/cache.h b/cache.h
index 107ac61..646fb81 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,7 @@ extern int precomposed_unicode;
  * that is subject to stripspace.
  */
 extern char comment_line_char;
+extern int auto_comment_line_char;
 
 enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
diff --git a/config.c b/config.c
index 05d909b..5ec3520 100644
--- a/config.c
+++ b/config.c
@@ -829,6 +829,8 @@ static int git_default_core_config(const char *var, const 
char *value)
                if (!ret) {
                        if (comment[0] && !comment[1])
                                comment_line_char = comment[0];
+                       else if (!strcasecmp(comment, "auto"))
+                               auto_comment_line_char = 1;
                        else
                                return error("core.commentChar should only be 
one character");
                }
diff --git a/environment.c b/environment.c
index 5c4815d..f2de1ee 100644
--- a/environment.c
+++ b/environment.c
@@ -69,6 +69,7 @@ unsigned long pack_size_limit_cfg;
  * that is subject to stripspace.
  */
 char comment_line_char = '#';
+int auto_comment_line_char;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 9a3f3a1..5cff300 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -563,4 +563,29 @@ test_expect_success 'commit --status with custom comment 
character' '
        test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
 '
 
+test_expect_success 'switch core.commentchar' '
+       test_commit "#foo" foo &&
+       GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend 
&&
+       test_i18ngrep "^@ Changes to be committed:" .git/COMMIT_EDITMSG
+'
+
+test_expect_success 'switch core.commentchar but out of options' '
+       cat >text <<\EOF &&
+# 1
+@ 2
+! 3
+$ 4
+% 5
+^ 6
+& 7
+| 8
+: 9
+; 10
+~ 11
+EOF
+       git commit --amend -F text &&
+       GIT_EDITOR=.git/FAKE_EDITOR test_must_fail \
+               git -c core.commentChar=auto commit --amend
+'
+
 test_done
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to