Re: [PATCH v6 05/15] sequencer: introduce the `merge` command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 13/04/18 11:12, Phillip Wood wrote:
> On 10/04/18 13:29, Johannes Schindelin wrote:
>> +static int do_merge(struct commit *commit, const char *arg, int arg_len,
>> +		    int flags, struct replay_opts *opts)
>> +{
>> +	int run_commit_flags = (flags & TODO_EDIT_MERGE_MSG) ?
>> +		EDIT_MSG | VERIFY_MSG : 0;
>> +	struct strbuf ref_name = STRBUF_INIT;
>> +	struct commit *head_commit, *merge_commit, *i;
>> +	struct commit_list *bases, *j, *reversed = NULL;
>> +	struct merge_options o;
>> +	int merge_arg_len, oneline_offset, ret;
>> +	static struct lock_file lock;
>> +	const char *p;
>> +
>> +	oneline_offset = arg_len;
>> +	merge_arg_len = strcspn(arg, " \t\n");
>> +	p = arg + merge_arg_len;
>> +	p += strspn(p, " \t\n");
>> +	if (*p == '#' && (!p[1] || isspace(p[1]))) {
>> +		p += 1 + strspn(p + 1, " \t\n");
>> +		oneline_offset = p - arg;
>> +	} else if (p - arg < arg_len)
>> +		BUG("octopus merges are not supported yet: '%s'", p);
>> +
>> +	strbuf_addf(&ref_name, "refs/rewritten/%.*s", merge_arg_len, arg);
>> +	merge_commit = lookup_commit_reference_by_name(ref_name.buf);
>> +	if (!merge_commit) {
>> +		/* fall back to non-rewritten ref or commit */
>> +		strbuf_splice(&ref_name, 0, strlen("refs/rewritten/"), "", 0);
>> +		merge_commit = lookup_commit_reference_by_name(ref_name.buf);
>> +	}
>> +	if (!merge_commit) {
>> +		error(_("could not resolve '%s'"), ref_name.buf);
>> +		strbuf_release(&ref_name);
>> +		return -1;
>> +	}
>> +
>> +	if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
>> +		return -1;
>> +
>> +	head_commit = lookup_commit_reference_by_name("HEAD");
>> +	if (!head_commit) {
>> +		rollback_lock_file(&lock);
>> +		return error(_("cannot merge without a current revision"));
>> +	}
>> +
>> +	if (commit) {
>> +		const char *message = get_commit_buffer(commit, NULL);
>> +		const char *body;
>> +		int len;
>> +
>> +		if (!message) {
>> +			rollback_lock_file(&lock);
>> +			return error(_("could not get commit message of '%s'"),
>> +				     oid_to_hex(&commit->object.oid));
>> +		}
>> +		write_author_script(message);
>> +		find_commit_subject(message, &body);
>> +		len = strlen(body);
>> +		if (write_message(body, len, git_path_merge_msg(), 0) < 0) {
>> +			error_errno(_("could not write '%s'"),
>> +				    git_path_merge_msg());
>> +			unuse_commit_buffer(commit, message);
>> +			rollback_lock_file(&lock);
>> +			return -1;
>> +		}
>> +		unuse_commit_buffer(commit, message);
>> +	} else {
>> +		struct strbuf buf = STRBUF_INIT;
>> +		int len;
>> +
>> +		strbuf_addf(&buf, "author %s", git_author_info(0));
>> +		write_author_script(buf.buf);
>> +		strbuf_reset(&buf);
>> +
>> +		if (oneline_offset < arg_len) {
>> +			p = arg + oneline_offset;
>> +			len = arg_len - oneline_offset;
>> +		} else {
>> +			strbuf_addf(&buf, "Merge branch '%.*s'",
>> +				    merge_arg_len, arg);
>> +			p = buf.buf;
>> +			len = buf.len;
>> +		}
>> +
>> +		if (write_message(p, len, git_path_merge_msg(), 0) < 0) {
>> +			error_errno(_("could not write '%s'"),
>> +				    git_path_merge_msg());
>> +			strbuf_release(&buf);
>> +			rollback_lock_file(&lock);
>> +			return -1;
>> +		}
>> +		strbuf_release(&buf);
>> +	}
>> +
>> +	write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
>> +		      git_path_merge_head(), 0);
>> +	write_message("no-ff", 5, git_path_merge_mode(), 0);
>> +
>> +	bases = get_merge_bases(head_commit, merge_commit);
>> +	for (j = bases; j; j = j->next)
>> +		commit_list_insert(j->item, &reversed);
>> +	free_commit_list(bases);
>> +
>> +	read_cache();
>> +	init_merge_options(&o);
>> +	o.branch1 = "HEAD";
>> +	o.branch2 = ref_name.buf;
>> +	o.buffer_output = 2;
>> +
>> +	ret = merge_recursive(&o, head_commit, merge_commit, reversed, &i);
>> +	if (!ret)
>> +		rerere(opts->allow_rerere_auto);
>> +	if (ret <= 0)
>> +		fputs(o.obuf.buf, stdout);
>> +	strbuf_release(&o.obuf);
>> +	if (ret < 0) {
>> +		strbuf_release(&ref_name);
>> +		rollback_lock_file(&lock);
>> +		return error(_("conflicts while merging '%.*s'"),
>> +			     merge_arg_len, arg);
>> +	}
> 
> If there are conflicts then ret == 0 rather than -1
> 
>> +
>> +	if (active_cache_changed &&
>> +	    write_locked_index(&the_index, &lock, COMMIT_LOCK)) {
>> +		strbuf_release(&ref_name);
>> +		return error(_("merge: Unable to write new index file"));
>> +	}
>> +	rollback_lock_file(&lock);
>> +
>> +	ret = run_git_commit(git_path_merge_msg(), opts, run_commit_flags);
> 
> If there were conflicts this will try and run git commit with unmerged
> cache entries
> 
>> +	strbuf_release(&ref_name);
>> +
>> +	return ret;
>> +}
>> +
> 
> If the merge fails with an error rather than conflicts then I think it
> should be rescheduled as we do for picks that fail with an error. The
> patch below does that and also adjusts the logic following the merge so
> that it does not call 'git commit' when there are conflicts. I think we
> may want to say something about fixing the conflicts and running
> 'git rebase --continue' as we do for conflicts when picking.
> 
> Best Wishes
> 
> Phillip
> 
> --->8---
> From: Phillip Wood <phillip.wood@xxxxxxxxxxxxx>
> Subject: [PATCH] fixup! sequencer: introduce the `merge` command
> 
> 
> Signed-off-by: Phillip Wood <phillip.wood@xxxxxxxxxxxxx>
> ---
>  sequencer.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/sequencer.c b/sequencer.c
> index e1b9be7327..511b7fddca 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2807,27 +2807,26 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
>  	o.buffer_output = 2;
>  
>  	ret = merge_recursive(&o, head_commit, merge_commit, reversed, &i);
> -	if (!ret)
> -		rerere(opts->allow_rerere_auto);
> +	strbuf_release(&ref_name);
>  	if (ret <= 0)
>  		fputs(o.obuf.buf, stdout);
>  	strbuf_release(&o.obuf);
>  	if (ret < 0) {
> -		strbuf_release(&ref_name);
>  		rollback_lock_file(&lock);
> -		return error(_("conflicts while merging '%.*s'"),
> -			     merge_arg_len, arg);
> +		return ret;
>  	}
>  
>  	if (active_cache_changed &&
> -	    write_locked_index(&the_index, &lock, COMMIT_LOCK)) {
> -		strbuf_release(&ref_name);
> +	    write_locked_index(&the_index, &lock, COMMIT_LOCK))
>  		return error(_("merge: Unable to write new index file"));
> -	}
>  	rollback_lock_file(&lock);
> +	if (!ret) {
> +		rerere(opts->allow_rerere_auto);
> +		error(_("conflicts while merging '%.*s'"), merge_arg_len, arg);
> +		return 1;
> +	}
>  
>  	ret = run_git_commit(git_path_merge_msg(), opts, run_commit_flags);
> -	strbuf_release(&ref_name);
>  
>  	return ret;
>  }
> @@ -3030,7 +3029,8 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
>  			return error(_("unknown command %d"), item->command);
>  
>  		if (res < 0 && (item->command == TODO_LABEL ||
> -				item->command == TODO_RESET)) {
> +				item->command == TODO_RESET ||
> +				item->command == TODO_MERGE)) {

Unfortunately it's not as simple as that - we only want to reschedule if
merge_recursive() fails, not if run_git_commit() does.


>  			/* Reschedule */
>  			todo_list->current--;
>  			save_todo(todo_list, opts);
> 




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux