rebase: store orig_head as a commit
Using a struct commit rather than a struct oid to hold orig_head means that we error out straight away if the branch being rebased does not point to a commit. It also simplifies the code that handles finding the merge base and fork point as it no longer has to convert from an oid to a commit. To avoid changing the behavior of "git rebase <upstream> <branch>" we keep the existing call to read_ref() and use lookup_commit_object() on the oid returned by that rather than calling lookup_commit_reference_by_name() which applies the ref dwim rules to its argument. Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									b8dbfd030c
								
							
						
					
					
						commit
						f21becdd94
					
				|  | @ -68,7 +68,7 @@ struct rebase_options { | ||||||
| 	const char *upstream_name; | 	const char *upstream_name; | ||||||
| 	const char *upstream_arg; | 	const char *upstream_arg; | ||||||
| 	char *head_name; | 	char *head_name; | ||||||
| 	struct object_id orig_head; | 	struct commit *orig_head; | ||||||
| 	struct commit *onto; | 	struct commit *onto; | ||||||
| 	const char *onto_name; | 	const char *onto_name; | ||||||
| 	const char *revisions; | 	const char *revisions; | ||||||
|  | @ -260,13 +260,13 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) | ||||||
| 	struct replay_opts replay = get_replay_opts(opts); | 	struct replay_opts replay = get_replay_opts(opts); | ||||||
| 	struct string_list commands = STRING_LIST_INIT_DUP; | 	struct string_list commands = STRING_LIST_INIT_DUP; | ||||||
|  |  | ||||||
| 	if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head, | 	if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid, | ||||||
| 				&revisions, &shortrevisions)) | 				&revisions, &shortrevisions)) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| 	if (init_basic_state(&replay, | 	if (init_basic_state(&replay, | ||||||
| 			     opts->head_name ? opts->head_name : "detached HEAD", | 			     opts->head_name ? opts->head_name : "detached HEAD", | ||||||
| 			     opts->onto, &opts->orig_head)) { | 			     opts->onto, &opts->orig_head->object.oid)) { | ||||||
| 		free(revisions); | 		free(revisions); | ||||||
| 		free(shortrevisions); | 		free(shortrevisions); | ||||||
|  |  | ||||||
|  | @ -297,8 +297,8 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) | ||||||
| 		split_exec_commands(opts->cmd, &commands); | 		split_exec_commands(opts->cmd, &commands); | ||||||
| 		ret = complete_action(the_repository, &replay, flags, | 		ret = complete_action(the_repository, &replay, flags, | ||||||
| 			shortrevisions, opts->onto_name, opts->onto, | 			shortrevisions, opts->onto_name, opts->onto, | ||||||
| 			&opts->orig_head, &commands, opts->autosquash, | 			&opts->orig_head->object.oid, &commands, | ||||||
| 			&todo_list); | 			opts->autosquash, &todo_list); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	string_list_clear(&commands, 0); | 	string_list_clear(&commands, 0); | ||||||
|  | @ -446,7 +446,8 @@ static int read_basic_state(struct rebase_options *opts) | ||||||
| 	} else if (!read_oneliner(&buf, state_dir_path("head", opts), | 	} else if (!read_oneliner(&buf, state_dir_path("head", opts), | ||||||
| 				  READ_ONELINER_WARN_MISSING)) | 				  READ_ONELINER_WARN_MISSING)) | ||||||
| 		return -1; | 		return -1; | ||||||
| 	if (get_oid_hex(buf.buf, &opts->orig_head)) | 	if (get_oid_hex(buf.buf, &oid) || | ||||||
|  | 	    !(opts->orig_head = lookup_commit_object(the_repository, &oid))) | ||||||
| 		return error(_("invalid orig-head: '%s'"), buf.buf); | 		return error(_("invalid orig-head: '%s'"), buf.buf); | ||||||
|  |  | ||||||
| 	if (file_exists(state_dir_path("quiet", opts))) | 	if (file_exists(state_dir_path("quiet", opts))) | ||||||
|  | @ -515,7 +516,7 @@ static int rebase_write_basic_state(struct rebase_options *opts) | ||||||
| 	write_file(state_dir_path("onto", opts), "%s", | 	write_file(state_dir_path("onto", opts), "%s", | ||||||
| 		   opts->onto ? oid_to_hex(&opts->onto->object.oid) : ""); | 		   opts->onto ? oid_to_hex(&opts->onto->object.oid) : ""); | ||||||
| 	write_file(state_dir_path("orig-head", opts), "%s", | 	write_file(state_dir_path("orig-head", opts), "%s", | ||||||
| 		   oid_to_hex(&opts->orig_head)); | 		   oid_to_hex(&opts->orig_head->object.oid)); | ||||||
| 	if (!(opts->flags & REBASE_NO_QUIET)) | 	if (!(opts->flags & REBASE_NO_QUIET)) | ||||||
| 		write_file(state_dir_path("quiet", opts), "%s", ""); | 		write_file(state_dir_path("quiet", opts), "%s", ""); | ||||||
| 	if (opts->flags & REBASE_VERBOSE) | 	if (opts->flags & REBASE_VERBOSE) | ||||||
|  | @ -644,7 +645,7 @@ static int run_am(struct rebase_options *opts) | ||||||
| 			       /* this is now equivalent to !opts->upstream */ | 			       /* this is now equivalent to !opts->upstream */ | ||||||
| 			       &opts->onto->object.oid : | 			       &opts->onto->object.oid : | ||||||
| 			       &opts->upstream->object.oid), | 			       &opts->upstream->object.oid), | ||||||
| 		    oid_to_hex(&opts->orig_head)); | 		    oid_to_hex(&opts->orig_head->object.oid)); | ||||||
|  |  | ||||||
| 	rebased_patches = xstrdup(git_path("rebased-patches")); | 	rebased_patches = xstrdup(git_path("rebased-patches")); | ||||||
| 	format_patch.out = open(rebased_patches, | 	format_patch.out = open(rebased_patches, | ||||||
|  | @ -678,7 +679,7 @@ static int run_am(struct rebase_options *opts) | ||||||
| 		free(rebased_patches); | 		free(rebased_patches); | ||||||
| 		strvec_clear(&am.args); | 		strvec_clear(&am.args); | ||||||
|  |  | ||||||
| 		ropts.oid = &opts->orig_head; | 		ropts.oid = &opts->orig_head->object.oid; | ||||||
| 		ropts.branch = opts->head_name; | 		ropts.branch = opts->head_name; | ||||||
| 		ropts.default_reflog_action = DEFAULT_REFLOG_ACTION; | 		ropts.default_reflog_action = DEFAULT_REFLOG_ACTION; | ||||||
| 		reset_head(the_repository, &ropts); | 		reset_head(the_repository, &ropts); | ||||||
|  | @ -826,7 +827,7 @@ static int checkout_up_to_date(struct rebase_options *options) | ||||||
| 	strbuf_addf(&buf, "%s: checkout %s", | 	strbuf_addf(&buf, "%s: checkout %s", | ||||||
| 		    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), | 		    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), | ||||||
| 		    options->switch_to); | 		    options->switch_to); | ||||||
| 	ropts.oid = &options->orig_head; | 	ropts.oid = &options->orig_head->object.oid; | ||||||
| 	ropts.branch = options->head_name; | 	ropts.branch = options->head_name; | ||||||
| 	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK; | 	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK; | ||||||
| 	if (!ropts.branch) | 	if (!ropts.branch) | ||||||
|  | @ -859,15 +860,11 @@ static int is_linear_history(struct commit *from, struct commit *to) | ||||||
|  |  | ||||||
| static int can_fast_forward(struct commit *onto, struct commit *upstream, | static int can_fast_forward(struct commit *onto, struct commit *upstream, | ||||||
| 			    struct commit *restrict_revision, | 			    struct commit *restrict_revision, | ||||||
| 			    struct object_id *head_oid, struct object_id *merge_base) | 			    struct commit *head, struct object_id *merge_base) | ||||||
| { | { | ||||||
| 	struct commit *head = lookup_commit(the_repository, head_oid); |  | ||||||
| 	struct commit_list *merge_bases = NULL; | 	struct commit_list *merge_bases = NULL; | ||||||
| 	int res = 0; | 	int res = 0; | ||||||
|  |  | ||||||
| 	if (!head) |  | ||||||
| 		goto done; |  | ||||||
|  |  | ||||||
| 	merge_bases = get_merge_bases(onto, head); | 	merge_bases = get_merge_bases(onto, head); | ||||||
| 	if (!merge_bases || merge_bases->next) { | 	if (!merge_bases || merge_bases->next) { | ||||||
| 		oidcpy(merge_base, null_oid()); | 		oidcpy(merge_base, null_oid()); | ||||||
|  | @ -1302,13 +1299,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
|  |  | ||||||
| 		if (read_basic_state(&options)) | 		if (read_basic_state(&options)) | ||||||
| 			exit(1); | 			exit(1); | ||||||
| 		ropts.oid = &options.orig_head; | 		ropts.oid = &options.orig_head->object.oid; | ||||||
| 		ropts.branch = options.head_name; | 		ropts.branch = options.head_name; | ||||||
| 		ropts.flags = RESET_HEAD_HARD; | 		ropts.flags = RESET_HEAD_HARD; | ||||||
| 		ropts.default_reflog_action = DEFAULT_REFLOG_ACTION; | 		ropts.default_reflog_action = DEFAULT_REFLOG_ACTION; | ||||||
| 		if (reset_head(the_repository, &ropts) < 0) | 		if (reset_head(the_repository, &ropts) < 0) | ||||||
| 			die(_("could not move back to %s"), | 			die(_("could not move back to %s"), | ||||||
| 			    oid_to_hex(&options.orig_head)); | 			    oid_to_hex(&options.orig_head->object.oid)); | ||||||
| 		remove_branch_state(the_repository, 0); | 		remove_branch_state(the_repository, 0); | ||||||
| 		ret = finish_rebase(&options); | 		ret = finish_rebase(&options); | ||||||
| 		goto cleanup; | 		goto cleanup; | ||||||
|  | @ -1594,25 +1591,27 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 	 */ | 	 */ | ||||||
| 	if (argc == 1) { | 	if (argc == 1) { | ||||||
| 		/* Is it "rebase other branchname" or "rebase other commit"? */ | 		/* Is it "rebase other branchname" or "rebase other commit"? */ | ||||||
|  | 		struct object_id branch_oid; | ||||||
| 		branch_name = argv[0]; | 		branch_name = argv[0]; | ||||||
| 		options.switch_to = argv[0]; | 		options.switch_to = argv[0]; | ||||||
|  |  | ||||||
| 		/* Is it a local branch? */ | 		/* Is it a local branch? */ | ||||||
| 		strbuf_reset(&buf); | 		strbuf_reset(&buf); | ||||||
| 		strbuf_addf(&buf, "refs/heads/%s", branch_name); | 		strbuf_addf(&buf, "refs/heads/%s", branch_name); | ||||||
| 		if (!read_ref(buf.buf, &options.orig_head)) { | 		if (!read_ref(buf.buf, &branch_oid)) { | ||||||
| 			die_if_checked_out(buf.buf, 1); | 			die_if_checked_out(buf.buf, 1); | ||||||
| 			options.head_name = xstrdup(buf.buf); | 			options.head_name = xstrdup(buf.buf); | ||||||
|  | 			options.orig_head = | ||||||
|  | 				lookup_commit_object(the_repository, | ||||||
|  | 						     &branch_oid); | ||||||
| 		/* If not is it a valid ref (branch or commit)? */ | 		/* If not is it a valid ref (branch or commit)? */ | ||||||
| 		} else { | 		} else { | ||||||
| 			struct commit *commit = | 			options.orig_head = | ||||||
| 				lookup_commit_reference_by_name(branch_name); | 				lookup_commit_reference_by_name(branch_name); | ||||||
| 			if (!commit) |  | ||||||
| 				die(_("no such branch/commit '%s'"), |  | ||||||
| 				    branch_name); |  | ||||||
| 			oidcpy(&options.orig_head, &commit->object.oid); |  | ||||||
| 			options.head_name = NULL; | 			options.head_name = NULL; | ||||||
| 		} | 		} | ||||||
|  | 		if (!options.orig_head) | ||||||
|  | 			die(_("no such branch/commit '%s'"), branch_name); | ||||||
| 	} else if (argc == 0) { | 	} else if (argc == 0) { | ||||||
| 		/* Do not need to switch branches, we are already on it. */ | 		/* Do not need to switch branches, we are already on it. */ | ||||||
| 		options.head_name = | 		options.head_name = | ||||||
|  | @ -1629,8 +1628,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 			FREE_AND_NULL(options.head_name); | 			FREE_AND_NULL(options.head_name); | ||||||
| 			branch_name = "HEAD"; | 			branch_name = "HEAD"; | ||||||
| 		} | 		} | ||||||
| 		if (get_oid("HEAD", &options.orig_head)) | 		options.orig_head = lookup_commit_reference_by_name("HEAD"); | ||||||
| 			die(_("Could not resolve HEAD to a revision")); | 		if (!options.orig_head) | ||||||
|  | 			die(_("Could not resolve HEAD to a commit")); | ||||||
| 	} else | 	} else | ||||||
| 		BUG("unexpected number of arguments left to parse"); | 		BUG("unexpected number of arguments left to parse"); | ||||||
|  |  | ||||||
|  | @ -1662,13 +1662,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 				options.onto_name); | 				options.onto_name); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (options.fork_point > 0) { | 	if (options.fork_point > 0) | ||||||
| 		struct commit *head = |  | ||||||
| 			lookup_commit_reference(the_repository, |  | ||||||
| 						&options.orig_head); |  | ||||||
| 		options.restrict_revision = | 		options.restrict_revision = | ||||||
| 			get_fork_point(options.upstream_name, head); | 			get_fork_point(options.upstream_name, options.orig_head); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (repo_read_index(the_repository) < 0) | 	if (repo_read_index(the_repository) < 0) | ||||||
| 		die(_("could not read index")); | 		die(_("could not read index")); | ||||||
|  | @ -1698,7 +1694,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 	 * call it before checking allow_preemptive_ff. | 	 * call it before checking allow_preemptive_ff. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (can_fast_forward(options.onto, options.upstream, options.restrict_revision, | 	if (can_fast_forward(options.onto, options.upstream, options.restrict_revision, | ||||||
| 		    &options.orig_head, &merge_base) && | 		    options.orig_head, &merge_base) && | ||||||
| 	    allow_preemptive_ff) { | 	    allow_preemptive_ff) { | ||||||
| 		int flag; | 		int flag; | ||||||
|  |  | ||||||
|  | @ -1775,7 +1771,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 	strbuf_addf(&msg, "%s: checkout %s", | 	strbuf_addf(&msg, "%s: checkout %s", | ||||||
| 		    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); | 		    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); | ||||||
| 	ropts.oid = &options.onto->object.oid; | 	ropts.oid = &options.onto->object.oid; | ||||||
| 	ropts.orig_head = &options.orig_head, | 	ropts.orig_head = &options.orig_head->object.oid, | ||||||
| 	ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD | | 	ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD | | ||||||
| 			RESET_HEAD_RUN_POST_CHECKOUT_HOOK; | 			RESET_HEAD_RUN_POST_CHECKOUT_HOOK; | ||||||
| 	ropts.head_msg = msg.buf; | 	ropts.head_msg = msg.buf; | ||||||
|  | @ -1789,7 +1785,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 	 * we just fast-forwarded. | 	 * we just fast-forwarded. | ||||||
| 	 */ | 	 */ | ||||||
| 	strbuf_reset(&msg); | 	strbuf_reset(&msg); | ||||||
| 	if (oideq(&merge_base, &options.orig_head)) { | 	if (oideq(&merge_base, &options.orig_head->object.oid)) { | ||||||
| 		printf(_("Fast-forwarded %s to %s.\n"), | 		printf(_("Fast-forwarded %s to %s.\n"), | ||||||
| 			branch_name, options.onto_name); | 			branch_name, options.onto_name); | ||||||
| 		strbuf_addf(&msg, "rebase finished: %s onto %s", | 		strbuf_addf(&msg, "rebase finished: %s onto %s", | ||||||
|  | @ -1810,7 +1806,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) | ||||||
| 		    (options.restrict_revision ? | 		    (options.restrict_revision ? | ||||||
| 		     oid_to_hex(&options.restrict_revision->object.oid) : | 		     oid_to_hex(&options.restrict_revision->object.oid) : | ||||||
| 		     oid_to_hex(&options.upstream->object.oid)), | 		     oid_to_hex(&options.upstream->object.oid)), | ||||||
| 		    oid_to_hex(&options.orig_head)); | 		    oid_to_hex(&options.orig_head->object.oid)); | ||||||
|  |  | ||||||
| 	options.revisions = revisions.buf; | 	options.revisions = revisions.buf; | ||||||
|  |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Phillip Wood
						Phillip Wood