static int pick_commits()

in sequencer.c [4943:5174]


static int pick_commits(struct repository *r,
			struct todo_list *todo_list,
			struct replay_opts *opts)
{
	struct replay_ctx *ctx = opts->ctx;
	int res = 0, reschedule = 0;

	ctx->reflog_message = sequencer_reflog_action(opts);
	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;

	unlink(rebase_path_message());
	unlink(rebase_path_stopped_sha());
	unlink(rebase_path_amend());
	unlink(rebase_path_patch());

	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, reschedule))
			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_author_script());
			unlink(git_path_merge_head(r));
			refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
					NULL, REF_NO_DEREF);
			refs_delete_ref(get_main_ref_store(r), "", "REBASE_HEAD",
					NULL, REF_NO_DEREF);

			if (item->command == TODO_BREAK) {
				if (!opts->verbose)
					term_clear_line();
				return stopped_at_head(r);
			}
		}
		strbuf_reset(&ctx->message);
		ctx->have_message = 0;
		if (item->command <= TODO_SQUASH) {
			res = pick_one_commit(r, todo_list, opts, &check_todo,
					      &reschedule);
			if (!res && item->command == TODO_EDIT)
				return 0;
		} 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, opts->quiet);
			*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));
			if (save_todo(todo_list, opts, reschedule))
				return -1;
			if (item->commit)
				write_rebase_head(&item->commit->object.oid);
		} else if (is_rebase_i(opts) && check_todo && !res &&
			   reread_todo_if_changed(r, todo_list, opts)) {
			return -1;
		}

		if (res)
			return res;

		todo_list->current++;
	}

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

		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 (repo_get_oid(r, "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 (refs_update_ref(get_main_ref_store(the_repository), 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 (refs_update_symref(get_main_ref_store(the_repository), "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) &&
			    !repo_get_oid(r, buf.buf, &orig) &&
			    !repo_get_oid(r, "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;
			struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;

			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);

			hook_opt.path_to_stdin = rebase_path_rewritten_list();
			strvec_push(&hook_opt.args, "rebase");
			run_hooks_opt(r, "post-rewrite", &hook_opt);
		}
		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);
}