diff options
Diffstat (limited to 'builtin/commit.c')
| -rw-r--r-- | builtin/commit.c | 425 | 
1 files changed, 249 insertions, 176 deletions
| diff --git a/builtin/commit.c b/builtin/commit.c index 39cf8976e3..254477fd1d 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -6,6 +6,7 @@   */  #include "cache.h" +#include "lockfile.h"  #include "cache-tree.h"  #include "color.h"  #include "dir.h" @@ -33,16 +34,29 @@  #include "mailmap.h"  static const char * const builtin_commit_usage[] = { -	N_("git commit [options] [--] <pathspec>..."), +	N_("git commit [<options>] [--] <pathspec>..."),  	NULL  };  static const char * const builtin_status_usage[] = { -	N_("git status [options] [--] <pathspec>..."), +	N_("git status [<options>] [--] <pathspec>..."),  	NULL  }; -static const char implicit_ident_advice[] = +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" @@ -156,7 +170,7 @@ static void determine_whence(struct wt_status *s)  		whence = FROM_MERGE;  	else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {  		whence = FROM_CHERRY_PICK; -		if (file_exists(git_path("sequencer"))) +		if (file_exists(git_path(SEQ_DIR)))  			sequencer_in_use = 1;  	}  	else @@ -215,7 +229,7 @@ static int commit_index_files(void)  static int list_paths(struct string_list *list, const char *with_tree,  		      const char *prefix, const struct pathspec *pattern)  { -	int i; +	int i, ret;  	char *m;  	if (!pattern->nr) @@ -242,7 +256,9 @@ static int list_paths(struct string_list *list, const char *with_tree,  			item->util = item; /* better a valid pointer than a fake one */  	} -	return report_path_error(m, pattern, prefix); +	ret = report_path_error(m, pattern, prefix); +	free(m); +	return ret;  }  static void add_remove_files(struct string_list *list) @@ -302,10 +318,9 @@ static void refresh_cache_or_die(int refresh_flags)  		die_resolve_conflict("commit");  } -static char *prepare_index(int argc, const char **argv, const char *prefix, -			   const struct commit *current_head, int is_status) +static const char *prepare_index(int argc, const char **argv, const char *prefix, +				 const struct commit *current_head, int is_status)  { -	int fd;  	struct string_list partial;  	struct pathspec pathspec;  	int refresh_flags = REFRESH_QUIET; @@ -321,16 +336,15 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  	if (interactive) {  		char *old_index_env = NULL; -		fd = hold_locked_index(&index_lock, 1); +		hold_locked_index(&index_lock, 1);  		refresh_cache_or_die(refresh_flags); -		if (write_cache(fd, active_cache, active_nr) || -		    close_lock_file(&index_lock)) +		if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))  			die(_("unable to create temporary index"));  		old_index_env = getenv(INDEX_ENVIRONMENT); -		setenv(INDEX_ENVIRONMENT, index_lock.filename, 1); +		setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);  		if (interactive_add(argc, argv, prefix, patch_interactive) != 0)  			die(_("interactive add failed")); @@ -341,10 +355,17 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  			unsetenv(INDEX_ENVIRONMENT);  		discard_cache(); -		read_cache_from(index_lock.filename); +		read_cache_from(index_lock.filename.buf); +		if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { +			if (reopen_lock_file(&index_lock) < 0) +				die(_("unable to write index file")); +			if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) +				die(_("unable to update temporary index")); +		} else +			warning(_("Failed to update main cache tree"));  		commit_style = COMMIT_NORMAL; -		return index_lock.filename; +		return index_lock.filename.buf;  	}  	/* @@ -360,15 +381,14 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  	 * (B) on failure, rollback the real index.  	 */  	if (all || (also && pathspec.nr)) { -		fd = hold_locked_index(&index_lock, 1); +		hold_locked_index(&index_lock, 1);  		add_files_to_cache(also ? prefix : NULL, &pathspec, 0);  		refresh_cache_or_die(refresh_flags);  		update_main_cache_tree(WRITE_TREE_SILENT); -		if (write_cache(fd, active_cache, active_nr) || -		    close_lock_file(&index_lock)) +		if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))  			die(_("unable to write new_index file"));  		commit_style = COMMIT_NORMAL; -		return index_lock.filename; +		return index_lock.filename.buf;  	}  	/* @@ -381,12 +401,16 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  	 * We still need to refresh the index here.  	 */  	if (!only && !pathspec.nr) { -		fd = hold_locked_index(&index_lock, 1); +		hold_locked_index(&index_lock, 1);  		refresh_cache_or_die(refresh_flags); -		if (active_cache_changed) { +		if (active_cache_changed +		    || !cache_tree_fully_valid(active_cache_tree)) {  			update_main_cache_tree(WRITE_TREE_SILENT); -			if (write_cache(fd, active_cache, active_nr) || -			    commit_locked_index(&index_lock)) +			active_cache_changed = 1; +		} +		if (active_cache_changed) { +			if (write_locked_index(&the_index, &index_lock, +					       COMMIT_LOCK))  				die(_("unable to write new_index file"));  		} else {  			rollback_lock_file(&index_lock); @@ -423,8 +447,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  			die(_("cannot do a partial commit during a cherry-pick."));  	} -	memset(&partial, 0, sizeof(partial)); -	partial.strdup_strings = 1; +	string_list_init(&partial, 1);  	if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))  		exit(1); @@ -432,30 +455,29 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,  	if (read_cache() < 0)  		die(_("cannot read the index")); -	fd = hold_locked_index(&index_lock, 1); +	hold_locked_index(&index_lock, 1);  	add_remove_files(&partial);  	refresh_cache(REFRESH_QUIET); -	if (write_cache(fd, active_cache, active_nr) || -	    close_lock_file(&index_lock)) +	update_main_cache_tree(WRITE_TREE_SILENT); +	if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))  		die(_("unable to write new_index file")); -	fd = hold_lock_file_for_update(&false_lock, -				       git_path("next-index-%"PRIuMAX, -						(uintmax_t) getpid()), -				       LOCK_DIE_ON_ERROR); +	hold_lock_file_for_update(&false_lock, +				  git_path("next-index-%"PRIuMAX, +					   (uintmax_t) getpid()), +				  LOCK_DIE_ON_ERROR);  	create_base_index(current_head);  	add_remove_files(&partial);  	refresh_cache(REFRESH_QUIET); -	if (write_cache(fd, active_cache, active_nr) || -	    close_lock_file(&false_lock)) +	if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))  		die(_("unable to write temporary index file"));  	discard_cache(); -	read_cache_from(false_lock.filename); +	read_cache_from(false_lock.filename.buf); -	return false_lock.filename; +	return false_lock.filename.buf;  }  static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, @@ -502,6 +524,12 @@ static int is_a_merge(const struct commit *current_head)  	return !!(current_head->parents && current_head->parents->next);  } +static void assert_split_ident(struct ident_split *id, const struct strbuf *buf) +{ +	if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin) +		die("BUG: unable to parse our own ident: %s", buf->buf); +} +  static void export_one(const char *var, const char *s, const char *e, int hack)  {  	struct strbuf buf = STRBUF_INIT; @@ -512,18 +540,25 @@ static void export_one(const char *var, const char *s, const char *e, int hack)  	strbuf_release(&buf);  } -static int sane_ident_split(struct ident_split *person) +static int parse_force_date(const char *in, struct strbuf *out)  { -	if (!person->name_begin || !person->name_end || -	    person->name_begin == person->name_end) -		return 0; /* no human readable name */ -	if (!person->mail_begin || !person->mail_end || -	    person->mail_begin == person->mail_end) -		return 0; /* no usable mail */ -	if (!person->date_begin || !person->date_end || -	    !person->tz_begin || !person->tz_end) -		return 0; -	return 1; +	strbuf_addch(out, '@'); + +	if (parse_date(in, out) < 0) { +		int errors = 0; +		unsigned long t = approxidate_careful(in, &errors); +		if (errors) +			return -1; +		strbuf_addf(out, "%lu", t); +	} + +	return 0; +} + +static void set_ident_var(char **buf, char *val) +{ +	free(*buf); +	*buf = val;  }  static void determine_author_info(struct strbuf *author_ident) @@ -531,67 +566,93 @@ static void determine_author_info(struct strbuf *author_ident)  	char *name, *email, *date;  	struct ident_split author; -	name = getenv("GIT_AUTHOR_NAME"); -	email = getenv("GIT_AUTHOR_EMAIL"); -	date = getenv("GIT_AUTHOR_DATE"); +	name = xstrdup_or_null(getenv("GIT_AUTHOR_NAME")); +	email = xstrdup_or_null(getenv("GIT_AUTHOR_EMAIL")); +	date = xstrdup_or_null(getenv("GIT_AUTHOR_DATE"));  	if (author_message) { -		const char *a, *lb, *rb, *eol; +		struct ident_split ident;  		size_t len; +		const char *a; -		a = strstr(author_message_buffer, "\nauthor "); +		a = find_commit_header(author_message_buffer, "author", &len);  		if (!a) -			die(_("invalid commit: %s"), author_message); - -		lb = strchrnul(a + strlen("\nauthor "), '<'); -		rb = strchrnul(lb, '>'); -		eol = strchrnul(rb, '\n'); -		if (!*lb || !*rb || !*eol) -			die(_("invalid commit: %s"), author_message); - -		if (lb == a + strlen("\nauthor ")) -			/* \nauthor <foo@example.com> */ -			name = xcalloc(1, 1); -		else -			name = xmemdupz(a + strlen("\nauthor "), -					(lb - strlen(" ") - -					 (a + strlen("\nauthor ")))); -		email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<"))); -		len = eol - (rb + strlen("> ")); -		date = xmalloc(len + 2); -		*date = '@'; -		memcpy(date + 1, rb + strlen("> "), len); -		date[len + 1] = '\0'; +			die(_("commit '%s' lacks author header"), author_message); +		if (split_ident_line(&ident, a, len) < 0) +			die(_("commit '%s' has malformed author line"), author_message); + +		set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin)); +		set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin)); + +		if (ident.date_begin) { +			struct strbuf date_buf = STRBUF_INIT; +			strbuf_addch(&date_buf, '@'); +			strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin); +			strbuf_addch(&date_buf, ' '); +			strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin); +			set_ident_var(&date, strbuf_detach(&date_buf, NULL)); +		}  	}  	if (force_author) { -		const char *lb = strstr(force_author, " <"); -		const char *rb = strchr(force_author, '>'); +		struct ident_split ident; -		if (!lb || !rb) +		if (split_ident_line(&ident, force_author, strlen(force_author)) < 0)  			die(_("malformed --author parameter")); -		name = xstrndup(force_author, lb - force_author); -		email = xstrndup(lb + 2, rb - (lb + 2)); +		set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin)); +		set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));  	} -	if (force_date) -		date = force_date; -	strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); -	if (!split_ident_line(&author, author_ident->buf, author_ident->len) && -	    sane_ident_split(&author)) { -		export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); -		export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); -		export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@'); +	if (force_date) { +		struct strbuf date_buf = STRBUF_INIT; +		if (parse_force_date(force_date, &date_buf)) +			die(_("invalid date format: %s"), force_date); +		set_ident_var(&date, strbuf_detach(&date_buf, NULL));  	} + +	strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); +	assert_split_ident(&author, author_ident); +	export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); +	export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); +	export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@'); +	free(name); +	free(email); +	free(date);  } -static char *cut_ident_timestamp_part(char *string) +static int author_date_is_interesting(void)  { -	char *ket = strrchr(string, '>'); -	if (!ket || ket[1] != ' ') -		die(_("Malformed ident string: '%s'"), string); -	*++ket = '\0'; -	return ket; +	return author_message || force_date; +} + +static void adjust_comment_line_char(const struct strbuf *sb) +{ +	char candidates[] = "#;@!$%^&|:"; +	char *candidate; +	const char *p; + +	comment_line_char = candidates[0]; +	if (!memchr(sb->buf, comment_line_char, sb->len)) +		return; + +	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 = ' '; +		} +	} + +	for (p = candidates; *p == ' '; p++) +		; +	if (!*p) +		die(_("unable to select a comment character that is not used\n" +		      "in the current commit message")); +	comment_line_char = *p;  }  static int prepare_to_commit(const char *index_file, const char *prefix, @@ -651,7 +712,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,  		char *buffer;  		buffer = strstr(use_message_buffer, "\n\n");  		if (buffer) -			strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); +			strbuf_addstr(&sb, buffer + 2);  		hook_arg1 = "commit";  		hook_arg2 = use_message;  	} else if (fixup_message) { @@ -717,36 +778,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,  	if (clean_message_contents)  		stripspace(&sb, 0); -	if (signoff) { -		/* -		 * See if we have a Conflicts: block at the end. If yes, count -		 * its size, so we can ignore it. -		 */ -		int ignore_footer = 0; -		int i, eol, previous = 0; -		const char *nl; - -		for (i = 0; i < sb.len; i++) { -			nl = memchr(sb.buf + i, '\n', sb.len - i); -			if (nl) -				eol = nl - sb.buf; -			else -				eol = sb.len; -			if (starts_with(sb.buf + previous, "\nConflicts:\n")) { -				ignore_footer = sb.len - previous; -				break; -			} -			while (i < eol) -				i++; -			previous = eol; -		} - -		append_signoff(&sb, ignore_footer, 0); -	} +	if (signoff) +		append_signoff(&sb, ignore_non_trailer(&sb), 0);  	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 */ @@ -754,7 +793,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,  	if (use_editor && include_status) {  		int ident_shown = 0;  		int saved_color_setting; -		char *ai_tmp, *ci_tmp; +		struct ident_split ci, ai; +  		if (whence != FROM_COMMIT) {  			if (cleanup_mode == CLEANUP_SCISSORS)  				wt_status_add_cut_line(s->fp); @@ -794,32 +834,45 @@ static int prepare_to_commit(const char *index_file, const char *prefix,  			status_printf_ln(s, GIT_COLOR_NORMAL,  					"%s", only_include_assumed); -		ai_tmp = cut_ident_timestamp_part(author_ident->buf); -		ci_tmp = cut_ident_timestamp_part(committer_ident.buf); -		if (strcmp(author_ident->buf, committer_ident.buf)) +		/* +		 * These should never fail because they come from our own +		 * fmt_ident. They may fail the sane_ident test, but we know +		 * that the name and mail pointers will at least be valid, +		 * which is enough for our tests and printing here. +		 */ +		assert_split_ident(&ai, author_ident); +		assert_split_ident(&ci, &committer_ident); + +		if (ident_cmp(&ai, &ci))  			status_printf_ln(s, GIT_COLOR_NORMAL,  				_("%s" -				"Author:    %s"), +				"Author:    %.*s <%.*s>"),  				ident_shown++ ? "" : "\n", -				author_ident->buf); +				(int)(ai.name_end - ai.name_begin), ai.name_begin, +				(int)(ai.mail_end - ai.mail_begin), ai.mail_begin); + +		if (author_date_is_interesting()) +			status_printf_ln(s, GIT_COLOR_NORMAL, +				_("%s" +				"Date:      %s"), +				ident_shown++ ? "" : "\n", +				show_ident_date(&ai, DATE_NORMAL));  		if (!committer_ident_sufficiently_given())  			status_printf_ln(s, GIT_COLOR_NORMAL,  				_("%s" -				"Committer: %s"), +				"Committer: %.*s <%.*s>"),  				ident_shown++ ? "" : "\n", -				committer_ident.buf); +				(int)(ci.name_end - ci.name_begin), ci.name_begin, +				(int)(ci.mail_end - ci.mail_begin), ci.mail_begin);  		if (ident_shown) -			status_printf_ln(s, GIT_COLOR_NORMAL, ""); +			status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");  		saved_color_setting = s->use_color;  		s->use_color = 0;  		commitable = run_status(s->fp, index_file, prefix, 1, s);  		s->use_color = saved_color_setting; - -		*ai_tmp = ' '; -		*ci_tmp = ' ';  	} else {  		unsigned char sha1[20];  		const char *parent = "HEAD"; @@ -954,7 +1007,7 @@ static int message_is_empty(struct strbuf *sb)  static int template_untouched(struct strbuf *sb)  {  	struct strbuf tmpl = STRBUF_INIT; -	char *start; +	const char *start;  	if (cleanup_mode == CLEANUP_NONE && sb->len)  		return 0; @@ -963,8 +1016,7 @@ static int template_untouched(struct strbuf *sb)  		return 0;  	stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); -	start = (char *)skip_prefix(sb->buf, tmpl.buf); -	if (!start) +	if (!skip_prefix(sb->buf, tmpl.buf, &start))  		start = sb->buf;  	strbuf_release(&tmpl);  	return rest_is_empty(sb, start - sb->buf); @@ -989,7 +1041,8 @@ static const char *find_author_by_nickname(const char *name)  	revs.mailmap = &mailmap;  	read_mailmap(revs.mailmap, NULL); -	prepare_revision_walk(&revs); +	if (prepare_revision_walk(&revs)) +		die(_("revision walk setup failed"));  	commit = get_revision(&revs);  	if (commit) {  		struct pretty_print_context ctx = {0}; @@ -999,7 +1052,7 @@ static const char *find_author_by_nickname(const char *name)  		clear_mailmap(&mailmap);  		return strbuf_detach(&buf, NULL);  	} -	die(_("No existing author found with '%s'"), name); +	die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);  } @@ -1179,22 +1232,21 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix,  	return commitable ? 0 : 1;  } -static int parse_status_slot(const char *var, int offset) +static int parse_status_slot(const char *slot)  { -	if (!strcasecmp(var+offset, "header")) +	if (!strcasecmp(slot, "header"))  		return WT_STATUS_HEADER; -	if (!strcasecmp(var+offset, "branch")) +	if (!strcasecmp(slot, "branch"))  		return WT_STATUS_ONBRANCH; -	if (!strcasecmp(var+offset, "updated") -		|| !strcasecmp(var+offset, "added")) +	if (!strcasecmp(slot, "updated") || !strcasecmp(slot, "added"))  		return WT_STATUS_UPDATED; -	if (!strcasecmp(var+offset, "changed")) +	if (!strcasecmp(slot, "changed"))  		return WT_STATUS_CHANGED; -	if (!strcasecmp(var+offset, "untracked")) +	if (!strcasecmp(slot, "untracked"))  		return WT_STATUS_UNTRACKED; -	if (!strcasecmp(var+offset, "nobranch")) +	if (!strcasecmp(slot, "nobranch"))  		return WT_STATUS_NOBRANCH; -	if (!strcasecmp(var+offset, "unmerged")) +	if (!strcasecmp(slot, "unmerged"))  		return WT_STATUS_UNMERGED;  	return -1;  } @@ -1202,6 +1254,7 @@ static int parse_status_slot(const char *var, int offset)  static int git_status_config(const char *k, const char *v, void *cb)  {  	struct wt_status *s = cb; +	const char *slot_name;  	if (starts_with(k, "column."))  		return git_column_config(k, v, "status", &s->colopts); @@ -1231,14 +1284,14 @@ static int git_status_config(const char *k, const char *v, void *cb)  		s->display_comment_prefix = git_config_bool(k, v);  		return 0;  	} -	if (starts_with(k, "status.color.") || starts_with(k, "color.status.")) { -		int slot = parse_status_slot(k, 13); +	if (skip_prefix(k, "status.color.", &slot_name) || +	    skip_prefix(k, "color.status.", &slot_name)) { +		int slot = parse_status_slot(slot_name);  		if (slot < 0)  			return 0;  		if (!v)  			return config_error_nonbool(k); -		color_parse(v, k, s->color_palette[slot]); -		return 0; +		return color_parse(v, s->color_palette[slot]);  	}  	if (!strcmp(k, "status.relativepaths")) {  		s->relative_paths = git_config_bool(k, v); @@ -1313,13 +1366,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)  	refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);  	fd = hold_locked_index(&index_lock, 0); -	if (0 <= fd) -		update_index_if_able(&the_index, &index_lock);  	s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;  	s.ignore_submodule_arg = ignore_submodule_arg;  	wt_status_collect(&s); +	if (0 <= fd) +		update_index_if_able(&the_index, &index_lock); +  	if (s.relative_paths)  		s.prefix = prefix; @@ -1343,6 +1397,22 @@ int cmd_status(int argc, const char **argv, const char *prefix)  	return 0;  } +static const char *implicit_ident_advice(void) +{ +	char *user_config = expand_user_path("~/.gitconfig"); +	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 unsigned char *sha1,  			  int initial_commit)  { @@ -1369,12 +1439,19 @@ static void print_summary(const char *prefix, const unsigned char *sha1,  		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_addstr(&format, implicit_ident_advice());  		}  	}  	strbuf_release(&author_ident); @@ -1395,14 +1472,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1,  	rev.diffopt.break_opt = 0;  	diff_setup_done(&rev.diffopt); -	head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL); -	printf("[%s%s ", -		starts_with(head, "refs/heads/") ? -			head + 11 : -			!strcmp(head, "HEAD") ? -				_("detached HEAD") : -				head, -		initial_commit ? _(" (root-commit)") : ""); +	head = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL); +	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; @@ -1442,7 +1517,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,  {  	/* oldsha1 SP newsha1 LF NUL */  	static char buf[2*40 + 3]; -	struct child_process proc; +	struct child_process proc = CHILD_PROCESS_INIT;  	const char *argv[3];  	int code;  	size_t n; @@ -1454,7 +1529,6 @@ static int run_rewrite_hook(const unsigned char *oldsha1,  	argv[1] = "amend";  	argv[2] = NULL; -	memset(&proc, 0, sizeof(proc));  	proc.argv = argv;  	proc.in = -1;  	proc.stdout_to_stderr = 1; @@ -1554,11 +1628,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)  	const char *index_file, *reflog_msg;  	char *nl;  	unsigned char sha1[20]; -	struct ref_lock *ref_lock;  	struct commit_list *parents = NULL, **pptr = &parents;  	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"))  		usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1680,12 +1755,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)  	strbuf_release(&author_ident);  	free_commit_extra_headers(extra); -	ref_lock = lock_any_ref_for_update("HEAD", -					   !current_head -					   ? NULL -					   : current_head->object.sha1, -					   0, NULL); -  	nl = strchr(sb.buf, '\n');  	if (nl)  		strbuf_setlen(&sb, nl + 1 - sb.buf); @@ -1694,14 +1763,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)  	strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));  	strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); -	if (!ref_lock) { -		rollback_index_files(); -		die(_("cannot lock HEAD ref")); -	} -	if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { +	transaction = ref_transaction_begin(&err); +	if (!transaction || +	    ref_transaction_update(transaction, "HEAD", sha1, +				   current_head +				   ? current_head->object.sha1 : null_sha1, +				   0, sb.buf, &err) || +	    ref_transaction_commit(transaction, &err)) {  		rollback_index_files(); -		die(_("cannot update HEAD ref")); +		die("%s", err.buf);  	} +	ref_transaction_free(transaction);  	unlink(git_path("CHERRY_PICK_HEAD"));  	unlink(git_path("REVERT_HEAD")); @@ -1712,7 +1784,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)  	if (commit_index_files())  		die (_("Repository has been updated, but unable to write\n" -		     "new_index file. Check that disk is not full or quota is\n" +		     "new_index file. Check that disk is not full and quota is\n"  		     "not exceeded, and then \"git reset HEAD\" to recover."));  	rerere(0); @@ -1730,5 +1802,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)  	if (!quiet)  		print_summary(prefix, sha1, !current_head); +	strbuf_release(&err);  	return 0;  } | 
