Allow custom "comment char"
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>
			
			
				maint
			
			
		
							parent
							
								
									44fe83502e
								
							
						
					
					
						commit
						eff80a9fd9
					
				|  | @ -528,6 +528,12 @@ core.editor:: | ||||||
| 	variable when it is set, and the environment variable | 	variable when it is set, and the environment variable | ||||||
| 	`GIT_EDITOR` is not set.  See linkgit:git-var[1]. | 	`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:: | sequence.editor:: | ||||||
| 	Text editor used by `git rebase -i` for editing the rebase insn file. | 	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. | 	The value is meant to be interpreted by the shell when it is used. | ||||||
|  |  | ||||||
|  | @ -35,7 +35,13 @@ OPTIONS | ||||||
| ------- | ------- | ||||||
| -s:: | -s:: | ||||||
| --strip-comments:: | --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 | EXAMPLES | ||||||
| -------- | -------- | ||||||
|  |  | ||||||
|  | @ -156,6 +156,11 @@ then they will free() it. | ||||||
| 	Remove the bytes between `pos..pos+len` and replace it with the given | 	Remove the bytes between `pos..pos+len` and replace it with the given | ||||||
| 	data. | 	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`:: | `strbuf_add`:: | ||||||
|  |  | ||||||
| 	Add data of given length to the buffer. | 	Add data of given length to the buffer. | ||||||
|  | @ -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. | 	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`:: | `strbuf_fread`:: | ||||||
|  |  | ||||||
| 	Read a given size of data from a FILE* pointer to the buffer. | 	Read a given size of data from a FILE* pointer to the buffer. | ||||||
|  |  | ||||||
|  | @ -706,11 +706,11 @@ static int edit_branch_description(const char *branch_name) | ||||||
| 	read_branch_desc(&buf, branch_name); | 	read_branch_desc(&buf, branch_name); | ||||||
| 	if (!buf.len || buf.buf[buf.len-1] != '\n') | 	if (!buf.len || buf.buf[buf.len-1] != '\n') | ||||||
| 		strbuf_addch(&buf, '\n'); | 		strbuf_addch(&buf, '\n'); | ||||||
| 	strbuf_addf(&buf, | 	strbuf_commented_addf(&buf, | ||||||
| 		    "# Please edit the description for the branch\n" | 		    "Please edit the description for the branch\n" | ||||||
| 		    "#   %s\n" | 		    "  %s\n" | ||||||
| 		    "# Lines starting with '#' will be stripped.\n", | 		    "Lines starting with '%c' will be stripped.\n", | ||||||
| 		    branch_name); | 		    branch_name, comment_line_char); | ||||||
| 	fp = fopen(git_path(edit_description), "w"); | 	fp = fopen(git_path(edit_description), "w"); | ||||||
| 	if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) { | 	if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) { | ||||||
| 		strbuf_release(&buf); | 		strbuf_release(&buf); | ||||||
|  |  | ||||||
|  | @ -733,15 +733,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix, | ||||||
| 		if (cleanup_mode == CLEANUP_ALL) | 		if (cleanup_mode == CLEANUP_ALL) | ||||||
| 			status_printf(s, GIT_COLOR_NORMAL, | 			status_printf(s, GIT_COLOR_NORMAL, | ||||||
| 				_("Please enter the commit message for your changes." | 				_("Please enter the commit message for your changes." | ||||||
| 				" Lines starting\nwith '#' will be ignored, and an empty" | 				  " Lines starting\nwith '%c' will be ignored, and an empty" | ||||||
| 				" message aborts the commit.\n")); | 				  " message aborts the commit.\n"), comment_line_char); | ||||||
| 		else /* CLEANUP_SPACE, that is. */ | 		else /* CLEANUP_SPACE, that is. */ | ||||||
| 			status_printf(s, GIT_COLOR_NORMAL, | 			status_printf(s, GIT_COLOR_NORMAL, | ||||||
| 				_("Please enter the commit message for your changes." | 				_("Please enter the commit message for your changes." | ||||||
| 				" Lines starting\n" | 				  " Lines starting\n" | ||||||
| 				"with '#' will be kept; you may remove them" | 				  "with '%c' will be kept; you may remove them" | ||||||
| 				" yourself if you want to.\n" | 				  " yourself if you want to.\n" | ||||||
| 				"An empty message aborts the commit.\n")); | 				  "An empty message aborts the commit.\n"), comment_line_char); | ||||||
| 		if (only_include_assumed) | 		if (only_include_assumed) | ||||||
| 			status_printf_ln(s, GIT_COLOR_NORMAL, | 			status_printf_ln(s, GIT_COLOR_NORMAL, | ||||||
| 					"%s", only_include_assumed); | 					"%s", only_include_assumed); | ||||||
|  |  | ||||||
|  | @ -464,7 +464,7 @@ static void fmt_tag_signature(struct strbuf *tagbuf, | ||||||
| 	strbuf_complete_line(tagbuf); | 	strbuf_complete_line(tagbuf); | ||||||
| 	if (sig->len) { | 	if (sig->len) { | ||||||
| 		strbuf_addch(tagbuf, '\n'); | 		strbuf_addch(tagbuf, '\n'); | ||||||
| 		strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len); | 		strbuf_add_commented_lines(tagbuf, sig->buf, sig->len); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -788,17 +788,16 @@ static const char merge_editor_comment[] = | ||||||
| N_("Please enter a commit message to explain why this merge is necessary,\n" | 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" |    "especially if it merges an updated upstream into a topic branch.\n" | ||||||
|    "\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"); |    "the commit.\n"); | ||||||
|  |  | ||||||
| static void prepare_to_commit(struct commit_list *remoteheads) | static void prepare_to_commit(struct commit_list *remoteheads) | ||||||
| { | { | ||||||
| 	struct strbuf msg = STRBUF_INIT; | 	struct strbuf msg = STRBUF_INIT; | ||||||
| 	const char *comment = _(merge_editor_comment); |  | ||||||
| 	strbuf_addbuf(&msg, &merge_msg); | 	strbuf_addbuf(&msg, &merge_msg); | ||||||
| 	strbuf_addch(&msg, '\n'); | 	strbuf_addch(&msg, '\n'); | ||||||
| 	if (0 < option_edit) | 	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); | 	write_merge_msg(&msg); | ||||||
| 	if (run_hook(get_index_file(), "prepare-commit-msg", | 	if (run_hook(get_index_file(), "prepare-commit-msg", | ||||||
| 		     git_path("MERGE_MSG"), "merge", NULL, NULL)) | 		     git_path("MERGE_MSG"), "merge", NULL, NULL)) | ||||||
|  |  | ||||||
|  | @ -92,10 +92,7 @@ static const char * const git_notes_get_ref_usage[] = { | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static const char note_template[] = | static const char note_template[] = | ||||||
| 	"\n" | 	"\nWrite/edit the notes for the following object:\n"; | ||||||
| 	"#\n" |  | ||||||
| 	"# Write/edit the notes for the following object:\n" |  | ||||||
| 	"#\n"; |  | ||||||
|  |  | ||||||
| struct msg_arg { | struct msg_arg { | ||||||
| 	int given; | 	int given; | ||||||
|  | @ -129,7 +126,7 @@ static void write_commented_object(int fd, const unsigned char *object) | ||||||
| 		{"show", "--stat", "--no-notes", sha1_to_hex(object), NULL}; | 		{"show", "--stat", "--no-notes", sha1_to_hex(object), NULL}; | ||||||
| 	struct child_process show; | 	struct child_process show; | ||||||
| 	struct strbuf buf = STRBUF_INIT; | 	struct strbuf buf = STRBUF_INIT; | ||||||
| 	FILE *show_out; | 	struct strbuf cbuf = STRBUF_INIT; | ||||||
|  |  | ||||||
| 	/* Invoke "git show --stat --no-notes $object" */ | 	/* Invoke "git show --stat --no-notes $object" */ | ||||||
| 	memset(&show, 0, sizeof(show)); | 	memset(&show, 0, sizeof(show)); | ||||||
|  | @ -142,21 +139,14 @@ static void write_commented_object(int fd, const unsigned char *object) | ||||||
| 		die(_("unable to start 'show' for object '%s'"), | 		die(_("unable to start 'show' for object '%s'"), | ||||||
| 		    sha1_to_hex(object)); | 		    sha1_to_hex(object)); | ||||||
|  |  | ||||||
| 	/* Open the output as FILE* so strbuf_getline() can be used. */ | 	if (strbuf_read(&buf, show.out, 0) < 0) | ||||||
| 	show_out = xfdopen(show.out, "r"); | 		die_errno(_("could not read 'show' output")); | ||||||
| 	if (show_out == NULL) | 	strbuf_add_commented_lines(&cbuf, buf.buf, buf.len); | ||||||
| 		die_errno(_("can't fdopen 'show' output fd")); | 	write_or_die(fd, cbuf.buf, cbuf.len); | ||||||
|  |  | ||||||
| 	/* Prepend "# " to each output line and write result to 'fd' */ | 	strbuf_release(&cbuf); | ||||||
| 	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(&buf); | 	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)) | 	if (finish_command(&show)) | ||||||
| 		die(_("failed to finish 'show' for object '%s'"), | 		die(_("failed to finish 'show' for object '%s'"), | ||||||
| 		    sha1_to_hex(object)); | 		    sha1_to_hex(object)); | ||||||
|  | @ -170,6 +160,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg, | ||||||
|  |  | ||||||
| 	if (msg->use_editor || !msg->given) { | 	if (msg->use_editor || !msg->given) { | ||||||
| 		int fd; | 		int fd; | ||||||
|  | 		struct strbuf buf = STRBUF_INIT; | ||||||
|  |  | ||||||
| 		/* write the template message before editing: */ | 		/* write the template message before editing: */ | ||||||
| 		path = git_pathdup("NOTES_EDITMSG"); | 		path = git_pathdup("NOTES_EDITMSG"); | ||||||
|  | @ -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); | 			write_or_die(fd, msg->buf.buf, msg->buf.len); | ||||||
| 		else if (prev && !append_only) | 		else if (prev && !append_only) | ||||||
| 			write_note_data(fd, prev); | 			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); | 		write_commented_object(fd, object); | ||||||
|  |  | ||||||
| 		close(fd); | 		close(fd); | ||||||
|  | 		strbuf_release(&buf); | ||||||
| 		strbuf_reset(&(msg->buf)); | 		strbuf_reset(&(msg->buf)); | ||||||
|  |  | ||||||
| 		if (launch_editor(path, &(msg->buf), NULL)) { | 		if (launch_editor(path, &(msg->buf), NULL)) { | ||||||
|  |  | ||||||
|  | @ -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. |  * 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) | void stripspace(struct strbuf *sb, int skip_comments) | ||||||
| { | { | ||||||
|  | @ -45,7 +46,7 @@ void stripspace(struct strbuf *sb, int skip_comments) | ||||||
| 		eol = memchr(sb->buf + i, '\n', sb->len - i); | 		eol = memchr(sb->buf + i, '\n', sb->len - i); | ||||||
| 		len = eol ? eol - (sb->buf + i) + 1 : 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; | 			newlen = 0; | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | @ -66,21 +67,53 @@ void stripspace(struct strbuf *sb, int skip_comments) | ||||||
| 	strbuf_setlen(sb, j); | 	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) | int cmd_stripspace(int argc, const char **argv, const char *prefix) | ||||||
| { | { | ||||||
| 	struct strbuf buf = STRBUF_INIT; | 	struct strbuf buf = STRBUF_INIT; | ||||||
| 	int strip_comments = 0; | 	int strip_comments = 0; | ||||||
|  | 	enum { INVAL = 0, STRIP_SPACE = 1, COMMENT_LINES = 2 } mode = STRIP_SPACE; | ||||||
|  |  | ||||||
| 	if (argc == 2 && (!strcmp(argv[1], "-s") || | 	if (argc == 2) { | ||||||
| 				!strcmp(argv[1], "--strip-comments"))) | 		if (!strcmp(argv[1], "-s") || | ||||||
| 		strip_comments = 1; | 			!strcmp(argv[1], "--strip-comments")) { | ||||||
| 	else if (argc > 1) | 			 strip_comments = 1; | ||||||
| 		usage("git stripspace [-s | --strip-comments] < input"); | 		} 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 (strip_comments || mode == COMMENT_LINES) | ||||||
|  | 		git_config(git_default_config, NULL); | ||||||
|  |  | ||||||
| 	if (strbuf_read(&buf, 0, 1024) < 0) | 	if (strbuf_read(&buf, 0, 1024) < 0) | ||||||
| 		die_errno("could not read the input"); | 		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); | 	write_or_die(1, buf.buf, buf.len); | ||||||
| 	strbuf_release(&buf); | 	strbuf_release(&buf); | ||||||
|  |  | ||||||
|  | @ -246,19 +246,13 @@ static int do_sign(struct strbuf *buffer) | ||||||
| } | } | ||||||
|  |  | ||||||
| static const char tag_template[] = | static const char tag_template[] = | ||||||
| 	N_("\n" | 	N_("\nWrite a tag message\n" | ||||||
| 	"#\n" | 	"Lines starting with '%c' will be ignored.\n"); | ||||||
| 	"# Write a tag message\n" |  | ||||||
| 	"# Lines starting with '#' will be ignored.\n" |  | ||||||
| 	"#\n"); |  | ||||||
|  |  | ||||||
| static const char tag_template_nocleanup[] = | static const char tag_template_nocleanup[] = | ||||||
| 	N_("\n" | 	N_("\nWrite a tag message\n" | ||||||
| 	"#\n" | 	"Lines starting with '%c' will be kept; you may remove them" | ||||||
| 	"# Write a tag message\n" | 	" yourself if you want to.\n"); | ||||||
| 	"# Lines starting with '#' will be kept; you may remove them" |  | ||||||
| 	" yourself if you want to.\n" |  | ||||||
| 	"#\n"); |  | ||||||
|  |  | ||||||
| static int git_tag_config(const char *var, const char *value, void *cb) | static int git_tag_config(const char *var, const char *value, void *cb) | ||||||
| { | { | ||||||
|  | @ -346,14 +340,18 @@ static void create_tag(const unsigned char *object, const char *tag, | ||||||
| 		if (fd < 0) | 		if (fd < 0) | ||||||
| 			die_errno(_("could not create file '%s'"), path); | 			die_errno(_("could not create file '%s'"), path); | ||||||
|  |  | ||||||
| 		if (!is_null_sha1(prev)) | 		if (!is_null_sha1(prev)) { | ||||||
| 			write_tag_body(fd, prev); | 			write_tag_body(fd, prev); | ||||||
| 		else if (opt->cleanup_mode == CLEANUP_ALL) | 		} else { | ||||||
| 			write_or_die(fd, _(tag_template), | 			struct strbuf buf = STRBUF_INIT; | ||||||
| 					strlen(_(tag_template))); | 			strbuf_addch(&buf, '\n'); | ||||||
| 		else | 			if (opt->cleanup_mode == CLEANUP_ALL) | ||||||
| 			write_or_die(fd, _(tag_template_nocleanup), | 				strbuf_commented_addf(&buf, _(tag_template), comment_line_char); | ||||||
| 					strlen(_(tag_template_nocleanup))); | 			else | ||||||
|  | 				strbuf_commented_addf(&buf, _(tag_template_nocleanup), comment_line_char); | ||||||
|  | 			write_or_die(fd, buf.buf, buf.len); | ||||||
|  | 			strbuf_release(&buf); | ||||||
|  | 		} | ||||||
| 		close(fd); | 		close(fd); | ||||||
|  |  | ||||||
| 		if (launch_editor(path, buf, NULL)) { | 		if (launch_editor(path, buf, NULL)) { | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										6
									
								
								cache.h
								
								
								
								
							|  | @ -562,6 +562,12 @@ extern int core_preload_index; | ||||||
| extern int core_apply_sparse_checkout; | extern int core_apply_sparse_checkout; | ||||||
| extern int precomposed_unicode; | 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 { | enum branch_track { | ||||||
| 	BRANCH_TRACK_UNSPECIFIED = -1, | 	BRANCH_TRACK_UNSPECIFIED = -1, | ||||||
| 	BRANCH_TRACK_NEVER = 0, | 	BRANCH_TRACK_NEVER = 0, | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								config.c
								
								
								
								
							
							
						
						
									
										8
									
								
								config.c
								
								
								
								
							|  | @ -717,6 +717,14 @@ static int git_default_core_config(const char *var, const char *value) | ||||||
| 	if (!strcmp(var, "core.editor")) | 	if (!strcmp(var, "core.editor")) | ||||||
| 		return git_config_string(&editor_program, var, value); | 		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")) | 	if (!strcmp(var, "core.askpass")) | ||||||
| 		return git_config_string(&askpass_program, var, value); | 		return git_config_string(&askpass_program, var, value); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -62,6 +62,12 @@ int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ | ||||||
| struct startup_info *startup_info; | struct startup_info *startup_info; | ||||||
| unsigned long pack_size_limit_cfg; | 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? */ | /* Parallel index stat data preload? */ | ||||||
| int core_preload_index = 0; | int core_preload_index = 0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -976,12 +976,12 @@ cmd_summary() { | ||||||
| 	done | | 	done | | ||||||
| 	if test -n "$for_status"; then | 	if test -n "$for_status"; then | ||||||
| 		if [ -n "$files" ]; then | 		if [ -n "$files" ]; then | ||||||
| 			gettextln "# Submodules changed but not updated:" | 			gettextln "Submodules changed but not updated:" | git stripspace -c | ||||||
| 		else | 		else | ||||||
| 			gettextln "# Submodule changes to be committed:" | 			gettextln "Submodule changes to be committed:" | git stripspace -c | ||||||
| 		fi | 		fi | ||||||
| 		echo "#" | 		printf "\n" | git stripspace -c | ||||||
| 		sed -e 's|^|# |' -e 's|^# $|#|' | 		git stripspace -c | ||||||
| 	else | 	else | ||||||
| 		cat | 		cat | ||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
							
								
								
									
										58
									
								
								strbuf.c
								
								
								
								
							
							
						
						
									
										58
									
								
								strbuf.c
								
								
								
								
							|  | @ -204,6 +204,54 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) | ||||||
| 	va_end(ap); | 	va_end(ap); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void add_lines(struct strbuf *out, | ||||||
|  | 			const char *prefix1, | ||||||
|  | 			const char *prefix2, | ||||||
|  | 			const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	while (size) { | ||||||
|  | 		const char *prefix; | ||||||
|  | 		const char *next = memchr(buf, '\n', size); | ||||||
|  | 		next = next ? (next + 1) : (buf + size); | ||||||
|  |  | ||||||
|  | 		prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1; | ||||||
|  | 		strbuf_addstr(out, prefix); | ||||||
|  | 		strbuf_add(out, buf, next - buf); | ||||||
|  | 		size -= next - buf; | ||||||
|  | 		buf = next; | ||||||
|  | 	} | ||||||
|  | 	strbuf_complete_line(out); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	static char prefix1[3]; | ||||||
|  | 	static char prefix2[2]; | ||||||
|  |  | ||||||
|  | 	if (prefix1[0] != comment_line_char) { | ||||||
|  | 		sprintf(prefix1, "%c ", comment_line_char); | ||||||
|  | 		sprintf(prefix2, "%c", comment_line_char); | ||||||
|  | 	} | ||||||
|  | 	add_lines(out, prefix1, prefix2, buf, size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list params; | ||||||
|  | 	struct strbuf buf = STRBUF_INIT; | ||||||
|  | 	int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n'; | ||||||
|  |  | ||||||
|  | 	va_start(params, fmt); | ||||||
|  | 	strbuf_vaddf(&buf, fmt, params); | ||||||
|  | 	va_end(params); | ||||||
|  |  | ||||||
|  | 	strbuf_add_commented_lines(sb, buf.buf, buf.len); | ||||||
|  | 	if (incomplete_line) | ||||||
|  | 		sb->buf[--sb->len] = '\0'; | ||||||
|  |  | ||||||
|  | 	strbuf_release(&buf); | ||||||
|  | } | ||||||
|  |  | ||||||
| void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap) | void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap) | ||||||
| { | { | ||||||
| 	int len; | 	int len; | ||||||
|  | @ -414,15 +462,7 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) | ||||||
| void strbuf_add_lines(struct strbuf *out, const char *prefix, | void strbuf_add_lines(struct strbuf *out, const char *prefix, | ||||||
| 		      const char *buf, size_t size) | 		      const char *buf, size_t size) | ||||||
| { | { | ||||||
| 	while (size) { | 	add_lines(out, prefix, NULL, buf, size); | ||||||
| 		const char *next = memchr(buf, '\n', size); |  | ||||||
| 		next = next ? (next + 1) : (buf + size); |  | ||||||
| 		strbuf_addstr(out, prefix); |  | ||||||
| 		strbuf_add(out, buf, next - buf); |  | ||||||
| 		size -= next - buf; |  | ||||||
| 		buf = next; |  | ||||||
| 	} |  | ||||||
| 	strbuf_complete_line(out); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s) | void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s) | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								strbuf.h
								
								
								
								
							
							
						
						
									
										4
									
								
								strbuf.h
								
								
								
								
							|  | @ -110,6 +110,8 @@ extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); | ||||||
| extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, | extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, | ||||||
|                           const void *, size_t); |                           const void *, size_t); | ||||||
|  |  | ||||||
|  | extern void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size); | ||||||
|  |  | ||||||
| extern void strbuf_add(struct strbuf *, const void *, size_t); | extern void strbuf_add(struct strbuf *, const void *, size_t); | ||||||
| static inline void strbuf_addstr(struct strbuf *sb, const char *s) { | static inline void strbuf_addstr(struct strbuf *sb, const char *s) { | ||||||
| 	strbuf_add(sb, s, strlen(s)); | 	strbuf_add(sb, s, strlen(s)); | ||||||
|  | @ -131,6 +133,8 @@ extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf * | ||||||
|  |  | ||||||
| __attribute__((format (printf,2,3))) | __attribute__((format (printf,2,3))) | ||||||
| extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); | extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); | ||||||
|  | __attribute__((format (printf, 2, 3))) | ||||||
|  | extern void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...); | ||||||
| __attribute__((format (printf,2,0))) | __attribute__((format (printf,2,0))) | ||||||
| extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap); | extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -397,4 +397,39 @@ test_expect_success 'strip comments, too' ' | ||||||
| 	test -z "$(echo "# comment" | git stripspace -s)" | 	test -z "$(echo "# comment" | git stripspace -s)" | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'strip comments with changed comment char' ' | ||||||
|  | 	test ! -z "$(echo "; comment" | git -c core.commentchar=";" stripspace)" && | ||||||
|  | 	test -z "$(echo "; comment" | git -c core.commentchar=";" stripspace -s)" | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '-c with single line' ' | ||||||
|  | 	printf "# foo\n" >expect && | ||||||
|  | 	printf "foo" | git stripspace -c >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '-c with single line followed by empty line' ' | ||||||
|  | 	printf "# foo\n#\n" >expect && | ||||||
|  | 	printf "foo\n\n" | git stripspace -c >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '-c with newline only' ' | ||||||
|  | 	printf "#\n" >expect && | ||||||
|  | 	printf "\n" | git stripspace -c >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '--comment-lines with single line' ' | ||||||
|  | 	printf "# foo\n" >expect && | ||||||
|  | 	printf "foo" | git stripspace -c >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '-c with changed comment char' ' | ||||||
|  | 	printf "; foo\n" >expect && | ||||||
|  | 	printf "foo" | git -c core.commentchar=";" stripspace -c >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_done | test_done | ||||||
|  |  | ||||||
|  | @ -447,4 +447,11 @@ use_template="-t template" | ||||||
|  |  | ||||||
| try_commit_status_combo | try_commit_status_combo | ||||||
|  |  | ||||||
|  | test_expect_success 'commit --status with custom comment character' ' | ||||||
|  | 	test_when_finished "git config --unset core.commentchar" && | ||||||
|  | 	git config core.commentchar ";" && | ||||||
|  | 	try_commit --status && | ||||||
|  | 	test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_done | test_done | ||||||
|  |  | ||||||
|  | @ -1253,6 +1253,56 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary | ||||||
| 	git config -f .gitmodules  --remove-section submodule.subname | 	git config -f .gitmodules  --remove-section submodule.subname | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | cat > expect << EOF | ||||||
|  | ; On branch master | ||||||
|  | ; Changes to be committed: | ||||||
|  | ;   (use "git reset HEAD <file>..." to unstage) | ||||||
|  | ; | ||||||
|  | ;	modified:   sm | ||||||
|  | ; | ||||||
|  | ; Changes not staged for commit: | ||||||
|  | ;   (use "git add <file>..." to update what will be committed) | ||||||
|  | ;   (use "git checkout -- <file>..." to discard changes in working directory) | ||||||
|  | ; | ||||||
|  | ;	modified:   dir1/modified | ||||||
|  | ;	modified:   sm (new commits) | ||||||
|  | ; | ||||||
|  | ; Submodule changes to be committed: | ||||||
|  | ; | ||||||
|  | ; * sm $head...$new_head (1): | ||||||
|  | ;   > Add bar | ||||||
|  | ; | ||||||
|  | ; Submodules changed but not updated: | ||||||
|  | ; | ||||||
|  | ; * sm $new_head...$head2 (1): | ||||||
|  | ;   > 2nd commit | ||||||
|  | ; | ||||||
|  | ; Untracked files: | ||||||
|  | ;   (use "git add <file>..." to include in what will be committed) | ||||||
|  | ; | ||||||
|  | ;	.gitmodules | ||||||
|  | ;	dir1/untracked | ||||||
|  | ;	dir2/modified | ||||||
|  | ;	dir2/untracked | ||||||
|  | ;	expect | ||||||
|  | ;	output | ||||||
|  | ;	untracked | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  | test_expect_success "status (core.commentchar with submodule summary)" ' | ||||||
|  | 	test_when_finished "git config --unset core.commentchar" && | ||||||
|  | 	git config core.commentchar ";" && | ||||||
|  | 	git status >output && | ||||||
|  | 	test_i18ncmp expect output | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success "status (core.commentchar with two chars with submodule summary)" ' | ||||||
|  | 	test_when_finished "git config --unset core.commentchar" && | ||||||
|  | 	git config core.commentchar ";;" && | ||||||
|  | 	git status >output && | ||||||
|  | 	test_i18ncmp expect output | ||||||
|  | ' | ||||||
|  |  | ||||||
| cat > expect << EOF | cat > expect << EOF | ||||||
| # On branch master | # On branch master | ||||||
| # Changes not staged for commit: | # Changes not staged for commit: | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								wt-status.c
								
								
								
								
							
							
						
						
									
										10
									
								
								wt-status.c
								
								
								
								
							|  | @ -45,7 +45,7 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color, | ||||||
|  |  | ||||||
| 	strbuf_vaddf(&sb, fmt, ap); | 	strbuf_vaddf(&sb, fmt, ap); | ||||||
| 	if (!sb.len) { | 	if (!sb.len) { | ||||||
| 		strbuf_addch(&sb, '#'); | 		strbuf_addch(&sb, comment_line_char); | ||||||
| 		if (!trail) | 		if (!trail) | ||||||
| 			strbuf_addch(&sb, ' '); | 			strbuf_addch(&sb, ' '); | ||||||
| 		color_print_strbuf(s->fp, color, &sb); | 		color_print_strbuf(s->fp, color, &sb); | ||||||
|  | @ -59,7 +59,7 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color, | ||||||
|  |  | ||||||
| 		strbuf_reset(&linebuf); | 		strbuf_reset(&linebuf); | ||||||
| 		if (at_bol) { | 		if (at_bol) { | ||||||
| 			strbuf_addch(&linebuf, '#'); | 			strbuf_addch(&linebuf, comment_line_char); | ||||||
| 			if (*line != '\n' && *line != '\t') | 			if (*line != '\n' && *line != '\t') | ||||||
| 				strbuf_addch(&linebuf, ' '); | 				strbuf_addch(&linebuf, ' '); | ||||||
| 		} | 		} | ||||||
|  | @ -760,8 +760,10 @@ static void wt_status_print_tracking(struct wt_status *s) | ||||||
|  |  | ||||||
| 	for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) | 	for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) | ||||||
| 		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), | 		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), | ||||||
| 				 "# %.*s", (int)(ep - cp), cp); | 				 "%c %.*s", comment_line_char, | ||||||
| 	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); | 				 (int)(ep - cp), cp); | ||||||
|  | 	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c", | ||||||
|  | 			 comment_line_char); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int has_unmerged(struct wt_status *s) | static int has_unmerged(struct wt_status *s) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano