static int pick_commits()

in sequencer.c [4564:4866]


static int pick_commits(struct repository *r,
			struct todo_list *todo_list,
			struct replay_opts *opts)
{
	int res = 0, reschedule = 0;
	char *prev_reflog_action;

	/* Note that 0 for 3rd parameter of setenv means set only if not set */
	setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
	prev_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
	if (opts->allow_ff)
		assert(!(opts->signoff || opts->no_commit ||
			 opts->record_origin || should_edit(opts) ||
			 opts->committer_date_is_author_date ||
			 opts->ignore_date));
	if (read_and_refresh_cache(r, opts))
		return -1;

	while (todo_list->current < todo_list->nr) {
		struct todo_item *item = todo_list->items + todo_list->current;
		const char *arg = todo_item_get_arg(todo_list, item);
		int check_todo = 0;

		if (save_todo(todo_list, opts))
			return -1;
		if (is_rebase_i(opts)) {
			if (item->command != TODO_COMMENT) {
				FILE *f = fopen(rebase_path_msgnum(), "w");

				todo_list->done_nr++;

				if (f) {
					fprintf(f, "%d\n", todo_list->done_nr);
					fclose(f);
				}
				if (!opts->quiet)
					fprintf(stderr, _("Rebasing (%d/%d)%s"),
						todo_list->done_nr,
						todo_list->total_nr,
						opts->verbose ? "\n" : "\r");
			}
			unlink(rebase_path_message());
			unlink(rebase_path_author_script());
			unlink(rebase_path_stopped_sha());
			unlink(rebase_path_amend());
			unlink(git_path_merge_head(r));
			unlink(git_path_auto_merge(r));
			delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);

			if (item->command == TODO_BREAK) {
				if (!opts->verbose)
					term_clear_line();
				return stopped_at_head(r);
			}
		}
		if (item->command <= TODO_SQUASH) {
			if (is_rebase_i(opts))
				setenv(GIT_REFLOG_ACTION, reflog_message(opts,
					command_to_string(item->command), NULL),
					1);
			res = do_pick_commit(r, item, opts,
					     is_final_fixup(todo_list),
					     &check_todo);
			if (is_rebase_i(opts))
				setenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);
			if (is_rebase_i(opts) && res < 0) {
				/* Reschedule */
				advise(_(rescheduled_advice),
				       get_item_line_length(todo_list,
							    todo_list->current),
				       get_item_line(todo_list,
						     todo_list->current));
				todo_list->current--;
				if (save_todo(todo_list, opts))
					return -1;
			}
			if (item->command == TODO_EDIT) {
				struct commit *commit = item->commit;
				if (!res) {
					if (!opts->verbose)
						term_clear_line();
					fprintf(stderr,
						_("Stopped at %s...  %.*s\n"),
						short_commit_name(commit),
						item->arg_len, arg);
				}
				return error_with_patch(r, commit,
					arg, item->arg_len, opts, res, !res);
			}
			if (is_rebase_i(opts) && !res)
				record_in_rewritten(&item->commit->object.oid,
					peek_command(todo_list, 1));
			if (res && is_fixup(item->command)) {
				if (res == 1)
					intend_to_amend();
				return error_failed_squash(r, item->commit, opts,
					item->arg_len, arg);
			} else if (res && is_rebase_i(opts) && item->commit) {
				int to_amend = 0;
				struct object_id oid;

				/*
				 * If we are rewording and have either
				 * fast-forwarded already, or are about to
				 * create a new root commit, we want to amend,
				 * otherwise we do not.
				 */
				if (item->command == TODO_REWORD &&
				    !get_oid("HEAD", &oid) &&
				    (oideq(&item->commit->object.oid, &oid) ||
				     (opts->have_squash_onto &&
				      oideq(&opts->squash_onto, &oid))))
					to_amend = 1;

				return res | error_with_patch(r, item->commit,
						arg, item->arg_len, opts,
						res, to_amend);
			}
		} else if (item->command == TODO_EXEC) {
			char *end_of_arg = (char *)(arg + item->arg_len);
			int saved = *end_of_arg;

			if (!opts->verbose)
				term_clear_line();
			*end_of_arg = '\0';
			res = do_exec(r, arg);
			*end_of_arg = saved;

			if (res) {
				if (opts->reschedule_failed_exec)
					reschedule = 1;
			}
			check_todo = 1;
		} else if (item->command == TODO_LABEL) {
			if ((res = do_label(r, arg, item->arg_len)))
				reschedule = 1;
		} else if (item->command == TODO_RESET) {
			if ((res = do_reset(r, arg, item->arg_len, opts)))
				reschedule = 1;
		} else if (item->command == TODO_MERGE) {
			if ((res = do_merge(r, item->commit, arg, item->arg_len,
					    item->flags, &check_todo, opts)) < 0)
				reschedule = 1;
			else if (item->commit)
				record_in_rewritten(&item->commit->object.oid,
						    peek_command(todo_list, 1));
			if (res > 0)
				/* failed with merge conflicts */
				return error_with_patch(r, item->commit,
							arg, item->arg_len,
							opts, res, 0);
		} else if (item->command == TODO_UPDATE_REF) {
			struct strbuf ref = STRBUF_INIT;
			strbuf_add(&ref, arg, item->arg_len);
			if ((res = do_update_ref(r, ref.buf)))
				reschedule = 1;
			strbuf_release(&ref);
		} else if (!is_noop(item->command))
			return error(_("unknown command %d"), item->command);

		if (reschedule) {
			advise(_(rescheduled_advice),
			       get_item_line_length(todo_list,
						    todo_list->current),
			       get_item_line(todo_list, todo_list->current));
			todo_list->current--;
			if (save_todo(todo_list, opts))
				return -1;
			if (item->commit)
				return error_with_patch(r,
							item->commit,
							arg, item->arg_len,
							opts, res, 0);
		} else if (is_rebase_i(opts) && check_todo && !res &&
			   reread_todo_if_changed(r, todo_list, opts)) {
			return -1;
		}

		todo_list->current++;
		if (res)
			return res;
	}

	if (is_rebase_i(opts)) {
		struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
		struct stat st;

		/* Stopped in the middle, as planned? */
		if (todo_list->current < todo_list->nr)
			return 0;

		if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
				starts_with(head_ref.buf, "refs/")) {
			const char *msg;
			struct object_id head, orig;
			int res;

			if (get_oid("HEAD", &head)) {
				res = error(_("cannot read HEAD"));
cleanup_head_ref:
				strbuf_release(&head_ref);
				strbuf_release(&buf);
				return res;
			}
			if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
					get_oid_hex(buf.buf, &orig)) {
				res = error(_("could not read orig-head"));
				goto cleanup_head_ref;
			}
			strbuf_reset(&buf);
			if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
				res = error(_("could not read 'onto'"));
				goto cleanup_head_ref;
			}
			msg = reflog_message(opts, "finish", "%s onto %s",
				head_ref.buf, buf.buf);
			if (update_ref(msg, head_ref.buf, &head, &orig,
				       REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
				res = error(_("could not update %s"),
					head_ref.buf);
				goto cleanup_head_ref;
			}
			msg = reflog_message(opts, "finish", "returning to %s",
				head_ref.buf);
			if (create_symref("HEAD", head_ref.buf, msg)) {
				res = error(_("could not update HEAD to %s"),
					head_ref.buf);
				goto cleanup_head_ref;
			}
			strbuf_reset(&buf);
		}

		if (opts->verbose) {
			struct rev_info log_tree_opt;
			struct object_id orig, head;

			memset(&log_tree_opt, 0, sizeof(log_tree_opt));
			repo_init_revisions(r, &log_tree_opt, NULL);
			log_tree_opt.diff = 1;
			log_tree_opt.diffopt.output_format =
				DIFF_FORMAT_DIFFSTAT;
			log_tree_opt.disable_stdin = 1;

			if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
			    !get_oid(buf.buf, &orig) &&
			    !get_oid("HEAD", &head)) {
				diff_tree_oid(&orig, &head, "",
					      &log_tree_opt.diffopt);
				log_tree_diff_flush(&log_tree_opt);
			}
			release_revisions(&log_tree_opt);
		}
		flush_rewritten_pending();
		if (!stat(rebase_path_rewritten_list(), &st) &&
				st.st_size > 0) {
			struct child_process child = CHILD_PROCESS_INIT;
			const char *post_rewrite_hook =
				find_hook("post-rewrite");

			child.in = open(rebase_path_rewritten_list(), O_RDONLY);
			child.git_cmd = 1;
			strvec_push(&child.args, "notes");
			strvec_push(&child.args, "copy");
			strvec_push(&child.args, "--for-rewrite=rebase");
			/* we don't care if this copying failed */
			run_command(&child);

			if (post_rewrite_hook) {
				struct child_process hook = CHILD_PROCESS_INIT;

				hook.in = open(rebase_path_rewritten_list(),
					O_RDONLY);
				hook.stdout_to_stderr = 1;
				hook.trace2_hook_name = "post-rewrite";
				strvec_push(&hook.args, post_rewrite_hook);
				strvec_push(&hook.args, "rebase");
				/* we don't care if this hook failed */
				run_command(&hook);
			}
		}
		apply_autostash(rebase_path_autostash());

		if (!opts->quiet) {
			if (!opts->verbose)
				term_clear_line();
			fprintf(stderr,
				_("Successfully rebased and updated %s.\n"),
				head_ref.buf);
		}

		strbuf_release(&buf);
		strbuf_release(&head_ref);

		if (do_update_refs(r, opts->quiet))
			return -1;
	}

	/*
	 * Sequence of picks finished successfully; cleanup by
	 * removing the .git/sequencer directory
	 */
	return sequencer_remove_state(opts);
}