Skip to content

Commit

Permalink
Allow custom "comment char"
Browse files Browse the repository at this point in the history
Some users do want to write a line that begin with a pound sign, #,
in their commit log message.  Many tracking system recognise
a token of #<bugid> form, for example.

The support we offer these use cases is not very friendly to the end
users.  They have a choice between

 - Don't do it.  Avoid such a line by rewrapping or indenting; and

 - Use --cleanup=whitespace but remove all the hint lines we add.

Give them a way to set a custom comment char, e.g.

    $ git -c core.commentchar="%" commit

so that they do not have to do either of the two workarounds.

[jc: although I started the topic, all the tests and documentation
updates, many of the call sites of the new strbuf_add_commented_*()
functions, and the change to git-submodule.sh scripted Porcelain are
from Ralf.]

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
gitster committed Jan 16, 2013
1 parent 44fe835 commit eff80a9
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 78 deletions.
6 changes: 6 additions & 0 deletions Documentation/config.txt
Expand Up @@ -528,6 +528,12 @@ core.editor::
variable when it is set, and the environment variable
`GIT_EDITOR` is not set. See linkgit:git-var[1].

core.commentchar::
Commands such as `commit` and `tag` that lets you edit
messages consider a line that begins with this character
commented, and removes them after the editor returns
(default '#').

sequence.editor::
Text editor used by `git rebase -i` for editing the rebase insn file.
The value is meant to be interpreted by the shell when it is used.
Expand Down
8 changes: 7 additions & 1 deletion Documentation/git-stripspace.txt
Expand Up @@ -35,7 +35,13 @@ OPTIONS
-------
-s::
--strip-comments::
Skip and remove all lines starting with '#'.
Skip and remove all lines starting with comment character (default '#').

-c::
--comment-lines::
Prepend comment character and blank to each line. Lines will automatically
be terminated with a newline. On empty lines, only the comment character
will be prepended.

EXAMPLES
--------
Expand Down
10 changes: 10 additions & 0 deletions Documentation/technical/api-strbuf.txt
Expand Up @@ -156,6 +156,11 @@ then they will free() it.
Remove the bytes between `pos..pos+len` and replace it with the given
data.

`strbuf_add_commented_lines`::

Add a NUL-terminated string to the buffer. Each line will be prepended
by a comment character and a blank.

`strbuf_add`::

Add data of given length to the buffer.
Expand Down Expand Up @@ -229,6 +234,11 @@ which can be used by the programmer of the callback as she sees fit.

Add a formatted string to the buffer.

`strbuf_commented_addf`::

Add a formatted string prepended by a comment character and a
blank to the buffer.

`strbuf_fread`::

Read a given size of data from a FILE* pointer to the buffer.
Expand Down
10 changes: 5 additions & 5 deletions builtin/branch.c
Expand Up @@ -706,11 +706,11 @@ static int edit_branch_description(const char *branch_name)
read_branch_desc(&buf, branch_name);
if (!buf.len || buf.buf[buf.len-1] != '\n')
strbuf_addch(&buf, '\n');
strbuf_addf(&buf,
"# Please edit the description for the branch\n"
"# %s\n"
"# Lines starting with '#' will be stripped.\n",
branch_name);
strbuf_commented_addf(&buf,
"Please edit the description for the branch\n"
" %s\n"
"Lines starting with '%c' will be stripped.\n",
branch_name, comment_line_char);
fp = fopen(git_path(edit_description), "w");
if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
strbuf_release(&buf);
Expand Down
12 changes: 6 additions & 6 deletions builtin/commit.c
Expand Up @@ -733,15 +733,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (cleanup_mode == CLEANUP_ALL)
status_printf(s, GIT_COLOR_NORMAL,
_("Please enter the commit message for your changes."
" Lines starting\nwith '#' will be ignored, and an empty"
" message aborts the commit.\n"));
" Lines starting\nwith '%c' will be ignored, and an empty"
" message aborts the commit.\n"), comment_line_char);
else /* CLEANUP_SPACE, that is. */
status_printf(s, GIT_COLOR_NORMAL,
_("Please enter the commit message for your changes."
" Lines starting\n"
"with '#' will be kept; you may remove them"
" yourself if you want to.\n"
"An empty message aborts the commit.\n"));
" Lines starting\n"
"with '%c' will be kept; you may remove them"
" yourself if you want to.\n"
"An empty message aborts the commit.\n"), comment_line_char);
if (only_include_assumed)
status_printf_ln(s, GIT_COLOR_NORMAL,
"%s", only_include_assumed);
Expand Down
2 changes: 1 addition & 1 deletion builtin/fmt-merge-msg.c
Expand Up @@ -464,7 +464,7 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_complete_line(tagbuf);
if (sig->len) {
strbuf_addch(tagbuf, '\n');
strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
}
}

Expand Down
5 changes: 2 additions & 3 deletions builtin/merge.c
Expand Up @@ -788,17 +788,16 @@ static const char merge_editor_comment[] =
N_("Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
"\n"
"Lines starting with '#' will be ignored, and an empty message aborts\n"
"Lines starting with '%c' will be ignored, and an empty message aborts\n"
"the commit.\n");

static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
const char *comment = _(merge_editor_comment);
strbuf_addbuf(&msg, &merge_msg);
strbuf_addch(&msg, '\n');
if (0 < option_edit)
strbuf_add_lines(&msg, "# ", comment, strlen(comment));
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
write_merge_msg(&msg);
if (run_hook(get_index_file(), "prepare-commit-msg",
git_path("MERGE_MSG"), "merge", NULL, NULL))
Expand Down
34 changes: 15 additions & 19 deletions builtin/notes.c
Expand Up @@ -92,10 +92,7 @@ static const char * const git_notes_get_ref_usage[] = {
};

static const char note_template[] =
"\n"
"#\n"
"# Write/edit the notes for the following object:\n"
"#\n";
"\nWrite/edit the notes for the following object:\n";

struct msg_arg {
int given;
Expand Down Expand Up @@ -129,7 +126,7 @@ static void write_commented_object(int fd, const unsigned char *object)
{"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
struct child_process show;
struct strbuf buf = STRBUF_INIT;
FILE *show_out;
struct strbuf cbuf = STRBUF_INIT;

/* Invoke "git show --stat --no-notes $object" */
memset(&show, 0, sizeof(show));
Expand All @@ -142,21 +139,14 @@ static void write_commented_object(int fd, const unsigned char *object)
die(_("unable to start 'show' for object '%s'"),
sha1_to_hex(object));

/* Open the output as FILE* so strbuf_getline() can be used. */
show_out = xfdopen(show.out, "r");
if (show_out == NULL)
die_errno(_("can't fdopen 'show' output fd"));
if (strbuf_read(&buf, show.out, 0) < 0)
die_errno(_("could not read 'show' output"));
strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
write_or_die(fd, cbuf.buf, cbuf.len);

/* Prepend "# " to each output line and write result to 'fd' */
while (strbuf_getline(&buf, show_out, '\n') != EOF) {
write_or_die(fd, "# ", 2);
write_or_die(fd, buf.buf, buf.len);
write_or_die(fd, "\n", 1);
}
strbuf_release(&cbuf);
strbuf_release(&buf);
if (fclose(show_out))
die_errno(_("failed to close pipe to 'show' for object '%s'"),
sha1_to_hex(object));

if (finish_command(&show))
die(_("failed to finish 'show' for object '%s'"),
sha1_to_hex(object));
Expand All @@ -170,6 +160,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,

if (msg->use_editor || !msg->given) {
int fd;
struct strbuf buf = STRBUF_INIT;

/* write the template message before editing: */
path = git_pathdup("NOTES_EDITMSG");
Expand All @@ -181,11 +172,16 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
write_or_die(fd, msg->buf.buf, msg->buf.len);
else if (prev && !append_only)
write_note_data(fd, prev);
write_or_die(fd, note_template, strlen(note_template));

strbuf_addch(&buf, '\n');
strbuf_add_commented_lines(&buf, note_template, strlen(note_template));
strbuf_addch(&buf, '\n');
write_or_die(fd, buf.buf, buf.len);

write_commented_object(fd, object);

close(fd);
strbuf_release(&buf);
strbuf_reset(&(msg->buf));

if (launch_editor(path, &(msg->buf), NULL)) {
Expand Down
49 changes: 41 additions & 8 deletions builtin/stripspace.c
Expand Up @@ -30,7 +30,8 @@ static size_t cleanup(char *line, size_t len)
*
* If last line does not have a newline at the end, one is added.
*
* Enable skip_comments to skip every line starting with "#".
* Enable skip_comments to skip every line starting with comment
* character.
*/
void stripspace(struct strbuf *sb, int skip_comments)
{
Expand All @@ -45,7 +46,7 @@ void stripspace(struct strbuf *sb, int skip_comments)
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;

if (skip_comments && len && sb->buf[i] == '#') {
if (skip_comments && len && sb->buf[i] == comment_line_char) {
newlen = 0;
continue;
}
Expand All @@ -66,21 +67,53 @@ void stripspace(struct strbuf *sb, int skip_comments)
strbuf_setlen(sb, j);
}

static void comment_lines(struct strbuf *buf)
{
char *msg;
size_t len;

msg = strbuf_detach(buf, &len);
strbuf_add_commented_lines(buf, msg, len);
free(msg);
}

static const char *usage_msg = "\n"
" git stripspace [-s | --strip-comments] < input\n"
" git stripspace [-c | --comment-lines] < input";

int cmd_stripspace(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
int strip_comments = 0;
enum { INVAL = 0, STRIP_SPACE = 1, COMMENT_LINES = 2 } mode = STRIP_SPACE;

if (argc == 2) {
if (!strcmp(argv[1], "-s") ||
!strcmp(argv[1], "--strip-comments")) {
strip_comments = 1;
} else if (!strcmp(argv[1], "-c") ||
!strcmp(argv[1], "--comment-lines")) {
mode = COMMENT_LINES;
} else {
mode = INVAL;
}
} else if (argc > 1) {
mode = INVAL;
}

if (mode == INVAL)
usage(usage_msg);

if (argc == 2 && (!strcmp(argv[1], "-s") ||
!strcmp(argv[1], "--strip-comments")))
strip_comments = 1;
else if (argc > 1)
usage("git stripspace [-s | --strip-comments] < input");
if (strip_comments || mode == COMMENT_LINES)
git_config(git_default_config, NULL);

if (strbuf_read(&buf, 0, 1024) < 0)
die_errno("could not read the input");

stripspace(&buf, strip_comments);
if (mode == STRIP_SPACE)
stripspace(&buf, strip_comments);
else
comment_lines(&buf);

write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
Expand Down
34 changes: 16 additions & 18 deletions builtin/tag.c
Expand Up @@ -246,19 +246,13 @@ static int do_sign(struct strbuf *buffer)
}

static const char tag_template[] =
N_("\n"
"#\n"
"# Write a tag message\n"
"# Lines starting with '#' will be ignored.\n"
"#\n");
N_("\nWrite a tag message\n"
"Lines starting with '%c' will be ignored.\n");

static const char tag_template_nocleanup[] =
N_("\n"
"#\n"
"# Write a tag message\n"
"# Lines starting with '#' will be kept; you may remove them"
" yourself if you want to.\n"
"#\n");
N_("\nWrite a tag message\n"
"Lines starting with '%c' will be kept; you may remove them"
" yourself if you want to.\n");

static int git_tag_config(const char *var, const char *value, void *cb)
{
Expand Down Expand Up @@ -346,14 +340,18 @@ static void create_tag(const unsigned char *object, const char *tag,
if (fd < 0)
die_errno(_("could not create file '%s'"), path);

if (!is_null_sha1(prev))
if (!is_null_sha1(prev)) {
write_tag_body(fd, prev);
else if (opt->cleanup_mode == CLEANUP_ALL)
write_or_die(fd, _(tag_template),
strlen(_(tag_template)));
else
write_or_die(fd, _(tag_template_nocleanup),
strlen(_(tag_template_nocleanup)));
} else {
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
strbuf_commented_addf(&buf, _(tag_template), comment_line_char);
else
strbuf_commented_addf(&buf, _(tag_template_nocleanup), comment_line_char);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
close(fd);

if (launch_editor(path, buf, NULL)) {
Expand Down
6 changes: 6 additions & 0 deletions cache.h
Expand Up @@ -562,6 +562,12 @@ extern int core_preload_index;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;

/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
*/
extern char comment_line_char;

enum branch_track {
BRANCH_TRACK_UNSPECIFIED = -1,
BRANCH_TRACK_NEVER = 0,
Expand Down
8 changes: 8 additions & 0 deletions config.c
Expand Up @@ -717,6 +717,14 @@ static int git_default_core_config(const char *var, const char *value)
if (!strcmp(var, "core.editor"))
return git_config_string(&editor_program, var, value);

if (!strcmp(var, "core.commentchar")) {
const char *comment;
int ret = git_config_string(&comment, var, value);
if (!ret)
comment_line_char = comment[0];
return ret;
}

if (!strcmp(var, "core.askpass"))
return git_config_string(&askpass_program, var, value);

Expand Down
6 changes: 6 additions & 0 deletions environment.c
Expand Up @@ -62,6 +62,12 @@ int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
struct startup_info *startup_info;
unsigned long pack_size_limit_cfg;

/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
*/
char comment_line_char = '#';

/* Parallel index stat data preload? */
int core_preload_index = 0;

Expand Down
8 changes: 4 additions & 4 deletions git-submodule.sh
Expand Up @@ -976,12 +976,12 @@ cmd_summary() {
done |
if test -n "$for_status"; then
if [ -n "$files" ]; then
gettextln "# Submodules changed but not updated:"
gettextln "Submodules changed but not updated:" | git stripspace -c
else
gettextln "# Submodule changes to be committed:"
gettextln "Submodule changes to be committed:" | git stripspace -c
fi
echo "#"
sed -e 's|^|# |' -e 's|^# $|#|'
printf "\n" | git stripspace -c
git stripspace -c
else
cat
fi
Expand Down

0 comments on commit eff80a9

Please sign in to comment.