blob: 2c19846385baa1df3240e865752087db827ba36e [file] [log] [blame]
Elijah Newrenbc5c5ec2023-05-16 06:33:57 +00001#include "git-compat-util.h"
Elijah Newren0b027f62023-03-21 06:25:58 +00002#include "abspath.h"
Elijah Newren6c6ddf92023-04-11 03:00:39 +00003#include "advice.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07004#include "config.h"
Elijah Newrend5fff462023-04-22 20:17:12 +00005#include "copy.h"
Elijah Newren7ee24e12023-03-21 06:25:57 +00006#include "environment.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00007#include "gettext.h"
Elijah Newren41771fa2023-02-24 00:09:27 +00008#include "hex.h"
Michael Haggerty697cc8e2014-10-01 12:28:42 +02009#include "lockfile.h"
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +053010#include "dir.h"
Elijah Newren87bed172023-04-11 00:41:53 -070011#include "object-file.h"
Elijah Newrendabab1d2023-04-11 00:41:49 -070012#include "object-name.h"
Elijah Newrena034e912023-05-16 06:34:06 +000013#include "object-store-ll.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053014#include "object.h"
Elijah Newrenca4eed72023-04-11 00:41:59 -070015#include "pager.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053016#include "commit.h"
Phillip Wood0505d602017-11-17 11:34:47 +000017#include "sequencer.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053018#include "run-command.h"
Ævar Arnfjörð Bjarmason5e3aba32021-09-26 21:03:26 +020019#include "hook.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053020#include "utf8.h"
21#include "cache-tree.h"
22#include "diff.h"
Elijah Newrenc3399322023-05-16 06:33:59 +000023#include "path.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053024#include "revision.h"
25#include "rerere.h"
Elijah Newren750324d2023-05-16 06:33:54 +000026#include "merge.h"
Elijah Newren14c45862020-11-02 23:45:34 +000027#include "merge-ort.h"
28#include "merge-ort-wrappers.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053029#include "refs.h"
Elijah Newrenbaf889c2023-05-16 06:33:51 +000030#include "sparse-index.h"
Jeff Kingdbbcd442020-07-28 16:23:39 -040031#include "strvec.h"
Johannes Schindelina1c75762016-10-21 14:25:12 +020032#include "quote.h"
Jonathan Tan967dfd42016-11-02 10:29:20 -070033#include "trailer.h"
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +010034#include "log-tree.h"
Johannes Schindelin311af522017-01-02 16:26:47 +010035#include "wt-status.h"
Johannes Schindelinc44a4c62017-07-14 16:45:31 +020036#include "hashmap.h"
Phillip Wooda87a6f32017-11-17 11:34:48 +000037#include "notes-utils.h"
38#include "sigchain.h"
Johannes Schindelin9055e402018-04-25 14:28:47 +020039#include "unpack-trees.h"
Johannes Schindelin1644c732018-04-25 14:29:03 +020040#include "oidmap.h"
41#include "oidset.h"
Nguyễn Thái Ngọc Duy8315bd22018-05-19 07:28:22 +020042#include "commit-slab.h"
Nguyễn Thái Ngọc Duy65b5f942018-05-20 20:40:06 +020043#include "alias.h"
Derrick Stolee64043552018-07-20 16:33:04 +000044#include "commit-reach.h"
Alban Gruinb97e1872018-08-28 14:10:36 +020045#include "rebase-interactive.h"
Denton Liu0816f1d2020-04-07 10:28:03 -040046#include "reset.h"
Derrick Stolee900b50c2022-07-19 18:33:39 +000047#include "branch.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053048
49#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +053050
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +000051/*
52 * To accommodate common filesystem limitations, where the loose refs' file
53 * names must not exceed `NAME_MAX`, the labels generated by `git rebase
54 * --rebase-merges` need to be truncated if the corresponding commit subjects
55 * are too long.
56 * Add some margin to stay clear from reaching `NAME_MAX`.
57 */
58#define GIT_MAX_LABEL_LENGTH ((NAME_MAX) - (LOCK_SUFFIX_LEN) - 16)
59
Ramsay Jones5fe81432019-02-11 17:16:58 +000060static const char sign_off_header[] = "Signed-off-by: ";
Brandon Caseycd650a42013-02-12 02:17:32 -080061static const char cherry_picked_prefix[] = "(cherry picked from commit ";
Miklos Vajna5ed75e22012-09-14 08:52:03 +020062
Phillip Wood66618a52018-01-24 12:34:22 +000063GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
64
Phillip Wood901ba7b2019-12-06 16:06:11 +000065static GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
Johannes Schindelin8a2a0f52016-10-14 15:17:12 +020066
67static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
68static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
69static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
Stephan Beyer1e412292016-12-07 22:51:32 +010070static GIT_PATH_FUNC(git_path_abort_safety_file, "sequencer/abort-safety")
Jeff Kingf9327292015-08-10 05:38:57 -040071
Johannes Schindelin84583952017-01-02 16:26:28 +010072static GIT_PATH_FUNC(rebase_path, "rebase-merge")
73/*
74 * The file containing rebase commands, comments, and empty lines.
75 * This file is created by "git rebase -i" then edited by the user. As
76 * the lines are processed, they are removed from the front of this
77 * file and written to the tail of 'done'.
78 */
Alban Gruin44b776c2018-08-10 18:51:28 +020079GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
Alban Gruina930eb02019-03-05 20:18:03 +010080GIT_PATH_FUNC(rebase_path_todo_backup, "rebase-merge/git-rebase-todo.backup")
Alban Gruinb97e1872018-08-28 14:10:36 +020081
Alban Gruin5a5445d2020-01-28 22:12:46 +010082GIT_PATH_FUNC(rebase_path_dropped, "rebase-merge/dropped")
83
Johannes Schindelinb5a67042016-10-21 14:25:04 +020084/*
Johannes Schindelin1df6df02017-01-02 16:27:00 +010085 * The rebase command lines that have already been processed. A line
86 * is moved here when it is first handled, before any associated user
87 * actions.
88 */
89static GIT_PATH_FUNC(rebase_path_done, "rebase-merge/done")
90/*
Johannes Schindelinef800692017-01-02 16:36:20 +010091 * The file to keep track of how many commands were already processed (e.g.
92 * for the prompt).
93 */
Beat Bolli9ad36352018-07-09 21:25:35 +020094static GIT_PATH_FUNC(rebase_path_msgnum, "rebase-merge/msgnum")
Johannes Schindelinef800692017-01-02 16:36:20 +010095/*
96 * The file to keep track of how many commands are to be processed in total
97 * (e.g. for the prompt).
98 */
Beat Bolli9ad36352018-07-09 21:25:35 +020099static GIT_PATH_FUNC(rebase_path_msgtotal, "rebase-merge/end")
Johannes Schindelinef800692017-01-02 16:36:20 +0100100/*
Johannes Schindelin6e98de72017-01-02 16:27:07 +0100101 * The commit message that is planned to be used for any changes that
102 * need to be committed following a user interaction.
103 */
104static GIT_PATH_FUNC(rebase_path_message, "rebase-merge/message")
105/*
106 * The file into which is accumulated the suggested commit message for
107 * squash/fixup commands. When the first of a series of squash/fixups
108 * is seen, the file is created and the commit message from the
109 * previous commit and from the first squash/fixup commit are written
110 * to it. The commit message for each subsequent squash/fixup commit
111 * is appended to the file as it is processed.
Johannes Schindelin6e98de72017-01-02 16:27:07 +0100112 */
113static GIT_PATH_FUNC(rebase_path_squash_msg, "rebase-merge/message-squash")
114/*
115 * If the current series of squash/fixups has not yet included a squash
116 * command, then this file exists and holds the commit message of the
117 * original "pick" commit. (If the series ends without a "squash"
118 * command, then this can be used as the commit message of the combined
119 * commit without opening the editor.)
120 */
121static GIT_PATH_FUNC(rebase_path_fixup_msg, "rebase-merge/message-fixup")
122/*
Johannes Schindeline12a7ef2018-04-27 22:48:21 +0200123 * This file contains the list fixup/squash commands that have been
124 * accumulated into message-fixup or message-squash so far.
125 */
126static GIT_PATH_FUNC(rebase_path_current_fixups, "rebase-merge/current-fixups")
127/*
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200128 * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
129 * GIT_AUTHOR_DATE that will be used for the commit that is currently
130 * being rebased.
131 */
132static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
Johannes Schindelina1c75762016-10-21 14:25:12 +0200133/*
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +0100134 * When an "edit" rebase command is being processed, the SHA1 of the
135 * commit to be edited is recorded in this file. When "git rebase
136 * --continue" is executed, if there are any staged changes then they
137 * will be amended to the HEAD commit, but only provided the HEAD
138 * commit is still the commit to be edited. When any other rebase
139 * command is processed, this file is deleted.
140 */
141static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
142/*
143 * When we stop at a given patch via the "edit" command, this file contains
Junio C Hamano0512eab2020-09-24 22:49:12 -0700144 * the commit object name of the corresponding patch.
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +0100145 */
146static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
147/*
Phillip Wood206a78d2023-09-06 15:22:46 +0000148 * When we stop for the user to resolve conflicts this file contains
149 * the patch of the commit that is being picked.
150 */
151static GIT_PATH_FUNC(rebase_path_patch, "rebase-merge/patch")
152/*
Johannes Schindelin25cb8df2017-01-02 16:28:16 +0100153 * For the post-rewrite hook, we make a list of rewritten commits and
154 * their new sha1s. The rewritten-pending list keeps the sha1s of
155 * commits that have been processed, but not committed yet,
156 * e.g. because they are waiting for a 'squash' command.
157 */
158static GIT_PATH_FUNC(rebase_path_rewritten_list, "rebase-merge/rewritten-list")
159static GIT_PATH_FUNC(rebase_path_rewritten_pending,
160 "rebase-merge/rewritten-pending")
Johannes Schindelin9055e402018-04-25 14:28:47 +0200161
162/*
Elijah Newren15beaaa2019-11-05 17:07:23 +0000163 * The path of the file containing the OID of the "squash onto" commit, i.e.
Johannes Schindelind87d48b2018-05-04 01:01:17 +0200164 * the dummy commit used for `reset [new root]`.
165 */
166static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto")
167
168/*
Johannes Schindelin9055e402018-04-25 14:28:47 +0200169 * The path of the file listing refs that need to be deleted after the rebase
170 * finishes. This is used by the `label` command to record the need for cleanup.
171 */
172static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
173
Johannes Schindelin25cb8df2017-01-02 16:28:16 +0100174/*
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +0000175 * The update-refs file stores a list of refs that will be updated at the end
176 * of the rebase sequence. The 'update-ref <ref>' commands in the todo file
177 * update the OIDs for the refs in this file, but the refs are not updated
178 * until the end of the rebase sequence.
179 *
180 * rebase_path_update_refs() returns the path to this file for a given
181 * worktree directory. For the current worktree, pass the_repository->gitdir.
182 */
183static char *rebase_path_update_refs(const char *wt_git_dir)
184{
185 return xstrfmt("%s/rebase-merge/update-refs", wt_git_dir);
186}
187
188/*
Johannes Schindelina1c75762016-10-21 14:25:12 +0200189 * The following files are written by git-rebase just after parsing the
Alban Gruin65850682018-08-28 14:10:40 +0200190 * command-line.
Johannes Schindelina1c75762016-10-21 14:25:12 +0200191 */
192static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
Phillip Wood7573cec2020-08-17 18:40:02 +0100193static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
Phillip Wooda3894aa2020-08-17 18:40:03 +0100194static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
Johannes Schindelin556907f2017-01-02 16:26:53 +0100195static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
196static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
Elijah Newren899b49c2018-12-11 08:11:36 -0800197static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
Phillip Wooda852ec72018-03-20 11:10:55 +0000198static GIT_PATH_FUNC(rebase_path_signoff, "rebase-merge/signoff")
Johannes Schindelin4b83ce92017-01-02 16:27:53 +0100199static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name")
200static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
Johannes Schindelin796c7972017-01-02 16:28:27 +0100201static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash")
Johannes Schindelinca6c6b42017-01-02 16:28:30 +0100202static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
203static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
Phillip Wood9b6d7a62017-08-02 11:44:17 +0100204static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
Johannes Schindelind421afa2018-12-10 11:04:58 -0800205static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +0200206static GIT_PATH_FUNC(rebase_path_no_reschedule_failed_exec, "rebase-merge/no-reschedule-failed-exec")
Elijah Newrene98c4262020-02-15 21:36:25 +0000207static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
208static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200209
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +0000210/**
211 * A 'struct update_refs_record' represents a value in the update-refs
212 * list. We use a string_list to map refs to these (before, after) pairs.
213 */
214struct update_ref_record {
215 struct object_id before;
216 struct object_id after;
217};
218
Derrick Stolee89fc0b52022-07-19 18:33:40 +0000219static struct update_ref_record *init_update_ref_record(const char *ref)
220{
221 struct update_ref_record *rec;
222
223 CALLOC_ARRAY(rec, 1);
224
225 oidcpy(&rec->before, null_oid());
226 oidcpy(&rec->after, null_oid());
227
228 /* This may fail, but that's fine, we will keep the null OID. */
229 read_ref(ref, &rec->before);
230
231 return rec;
232}
233
Glen Chooa4e7e312023-06-28 19:26:22 +0000234static int git_sequencer_config(const char *k, const char *v,
235 const struct config_context *ctx, void *cb)
Phillip Wood28d6dae2017-12-13 11:46:21 +0000236{
237 struct replay_opts *opts = cb;
Phillip Wood28d6dae2017-12-13 11:46:21 +0000238
239 if (!strcmp(k, "commit.cleanup")) {
Jeff Kingea8f9492023-12-07 02:26:42 -0500240 if (!v)
241 return config_error_nonbool(k);
Phillip Wood28d6dae2017-12-13 11:46:21 +0000242
Jeff Kingea8f9492023-12-07 02:26:42 -0500243 if (!strcmp(v, "verbatim")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000244 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000245 opts->explicit_cleanup = 1;
Jeff Kingea8f9492023-12-07 02:26:42 -0500246 } else if (!strcmp(v, "whitespace")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000247 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000248 opts->explicit_cleanup = 1;
Jeff Kingea8f9492023-12-07 02:26:42 -0500249 } else if (!strcmp(v, "strip")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000250 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000251 opts->explicit_cleanup = 1;
Jeff Kingea8f9492023-12-07 02:26:42 -0500252 } else if (!strcmp(v, "scissors")) {
Denton Liu1a2b9852019-04-17 11:23:30 +0100253 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000254 opts->explicit_cleanup = 1;
255 } else {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000256 warning(_("invalid commit message cleanup mode '%s'"),
Jeff Kingea8f9492023-12-07 02:26:42 -0500257 v);
Phillip Woodd74f3e52019-03-29 11:08:42 +0000258 }
Phillip Wood28d6dae2017-12-13 11:46:21 +0000259
Jeff Kingea8f9492023-12-07 02:26:42 -0500260 return 0;
Phillip Wood28d6dae2017-12-13 11:46:21 +0000261 }
262
263 if (!strcmp(k, "commit.gpgsign")) {
Johannes Schindelined1e5282017-12-22 12:50:50 +0100264 opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
Phillip Wood28d6dae2017-12-13 11:46:21 +0000265 return 0;
266 }
267
Elijah Newren14c45862020-11-02 23:45:34 +0000268 if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
269 int ret = git_config_string((const char**)&opts->default_strategy, k, v);
270 if (ret == 0) {
271 /*
272 * pull.twohead is allowed to be multi-valued; we only
273 * care about the first value.
274 */
275 char *tmp = strchr(opts->default_strategy, ' ');
276 if (tmp)
277 *tmp = '\0';
278 }
279 return ret;
280 }
281
Junio C Hamano191faaf2022-05-31 09:22:20 -0700282 if (opts->action == REPLAY_REVERT && !strcmp(k, "revert.reference"))
Junio C Hamano43966ab2022-05-26 23:01:39 -0700283 opts->commit_use_reference = git_config_bool(k, v);
284
Glen Chooa4e7e312023-06-28 19:26:22 +0000285 return git_diff_basic_config(k, v, ctx, NULL);
Phillip Wood28d6dae2017-12-13 11:46:21 +0000286}
287
288void sequencer_init_config(struct replay_opts *opts)
289{
290 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
291 git_config(git_sequencer_config, opts);
292}
293
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200294static inline int is_rebase_i(const struct replay_opts *opts)
295{
Johannes Schindelin84583952017-01-02 16:26:28 +0100296 return opts->action == REPLAY_INTERACTIVE_REBASE;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200297}
298
Johannes Schindelin285abf52016-10-14 15:17:20 +0200299static const char *get_dir(const struct replay_opts *opts)
300{
Johannes Schindelin84583952017-01-02 16:26:28 +0100301 if (is_rebase_i(opts))
302 return rebase_path();
Johannes Schindelin285abf52016-10-14 15:17:20 +0200303 return git_path_seq_dir();
304}
305
Johannes Schindelinc0246502016-10-21 14:24:32 +0200306static const char *get_todo_path(const struct replay_opts *opts)
307{
Johannes Schindelin84583952017-01-02 16:26:28 +0100308 if (is_rebase_i(opts))
309 return rebase_path_todo();
Johannes Schindelinc0246502016-10-21 14:24:32 +0200310 return git_path_todo_file();
311}
312
Brandon Caseybab4d102013-02-12 02:17:35 -0800313/*
314 * Returns 0 for non-conforming footer
315 * Returns 1 for conforming footer
316 * Returns 2 when sob exists within conforming footer
317 * Returns 3 when sob exists within conforming footer as last entry
318 */
319static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
Jeff King66e83d92018-08-22 20:50:51 -0400320 size_t ignore_footer)
Brandon Caseyb971e042013-02-12 02:17:34 -0800321{
Jeff King00a21f52018-08-22 20:46:23 -0400322 struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
Jonathan Tan967dfd42016-11-02 10:29:20 -0700323 struct trailer_info info;
Jeff Kinga3b636e2018-08-22 20:45:44 -0400324 size_t i;
Jonathan Tan967dfd42016-11-02 10:29:20 -0700325 int found_sob = 0, found_sob_last = 0;
Jeff King9dad0732020-09-30 08:34:11 -0400326 char saved_char;
Brandon Caseyb971e042013-02-12 02:17:34 -0800327
Jeff Kingffce7f52018-08-22 20:50:37 -0400328 opts.no_divider = 1;
329
Jeff King9dad0732020-09-30 08:34:11 -0400330 if (ignore_footer) {
331 saved_char = sb->buf[sb->len - ignore_footer];
332 sb->buf[sb->len - ignore_footer] = '\0';
333 }
334
Linus Arver9aa1b2b2024-03-01 00:14:43 +0000335 trailer_info_get(&opts, sb->buf, &info);
Jonathan Tan967dfd42016-11-02 10:29:20 -0700336
Jeff King9dad0732020-09-30 08:34:11 -0400337 if (ignore_footer)
338 sb->buf[sb->len - ignore_footer] = saved_char;
339
Linus Arverde7c27a2023-10-20 19:01:35 +0000340 if (info.trailer_block_start == info.trailer_block_end)
Brandon Caseyb971e042013-02-12 02:17:34 -0800341 return 0;
342
Jonathan Tan967dfd42016-11-02 10:29:20 -0700343 for (i = 0; i < info.trailer_nr; i++)
344 if (sob && !strncmp(info.trailers[i], sob->buf, sob->len)) {
345 found_sob = 1;
346 if (i == info.trailer_nr - 1)
347 found_sob_last = 1;
348 }
Brandon Caseyb971e042013-02-12 02:17:34 -0800349
Jonathan Tan967dfd42016-11-02 10:29:20 -0700350 trailer_info_release(&info);
Brandon Caseyb971e042013-02-12 02:17:34 -0800351
Jonathan Tan967dfd42016-11-02 10:29:20 -0700352 if (found_sob_last)
Brandon Caseybab4d102013-02-12 02:17:35 -0800353 return 3;
354 if (found_sob)
355 return 2;
Brandon Caseyb971e042013-02-12 02:17:34 -0800356 return 1;
357}
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530358
Johannes Schindelina1c75762016-10-21 14:25:12 +0200359static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
360{
361 static struct strbuf buf = STRBUF_INIT;
362
363 strbuf_reset(&buf);
364 if (opts->gpg_sign)
365 sq_quotef(&buf, "-S%s", opts->gpg_sign);
366 return buf.buf;
367}
368
Ævar Arnfjörð Bjarmason9ff2f062023-02-06 20:08:08 +0100369void replay_opts_release(struct replay_opts *opts)
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100370{
371 free(opts->gpg_sign);
372 free(opts->reflog_action);
373 free(opts->default_strategy);
374 free(opts->strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +0100375 strvec_clear (&opts->xopts);
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100376 strbuf_release(&opts->current_fixups);
Ævar Arnfjörð Bjarmasona6a700a2023-02-06 20:08:09 +0100377 if (opts->revs)
378 release_revisions(opts->revs);
379 free(opts->revs);
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100380}
381
Johannes Schindelin28635842016-10-21 14:24:55 +0200382int sequencer_remove_state(struct replay_opts *opts)
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530383{
Johannes Schindelin9055e402018-04-25 14:28:47 +0200384 struct strbuf buf = STRBUF_INIT;
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100385 int ret = 0;
Johannes Schindelin03a4e262016-10-21 14:24:13 +0200386
Johannes Schindelin9055e402018-04-25 14:28:47 +0200387 if (is_rebase_i(opts) &&
388 strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
389 char *p = buf.buf;
390 while (*p) {
391 char *eol = strchr(p, '\n');
392 if (eol)
393 *eol = '\0';
Elijah Newrenc2417d32020-02-15 21:36:36 +0000394 if (delete_ref("(rebase) cleanup", p, NULL, 0) < 0) {
Johannes Schindelin9055e402018-04-25 14:28:47 +0200395 warning(_("could not delete '%s'"), p);
Phillip Wood37e9ee52019-05-14 19:03:48 +0100396 ret = -1;
397 }
Johannes Schindelin9055e402018-04-25 14:28:47 +0200398 if (!eol)
399 break;
400 p = eol + 1;
401 }
402 }
403
Johannes Schindelin9055e402018-04-25 14:28:47 +0200404 strbuf_reset(&buf);
405 strbuf_addstr(&buf, get_dir(opts));
Phillip Wood37e9ee52019-05-14 19:03:48 +0100406 if (remove_dir_recursively(&buf, 0))
407 ret = error(_("could not remove '%s'"), buf.buf);
Johannes Schindelin9055e402018-04-25 14:28:47 +0200408 strbuf_release(&buf);
Johannes Schindelin28635842016-10-21 14:24:55 +0200409
Phillip Wood37e9ee52019-05-14 19:03:48 +0100410 return ret;
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530411}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530412
413static const char *action_name(const struct replay_opts *opts)
414{
Johannes Schindelin84583952017-01-02 16:26:28 +0100415 switch (opts->action) {
416 case REPLAY_REVERT:
417 return N_("revert");
418 case REPLAY_PICK:
419 return N_("cherry-pick");
420 case REPLAY_INTERACTIVE_REBASE:
Elijah Newrenc2417d32020-02-15 21:36:36 +0000421 return N_("rebase");
Johannes Schindelin84583952017-01-02 16:26:28 +0100422 }
Nguyễn Thái Ngọc Duy1a07e592018-07-21 09:49:19 +0200423 die(_("unknown action: %d"), opts->action);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530424}
425
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530426struct commit_message {
427 char *parent_label;
Jeff King7b35eaf2016-02-22 17:44:57 -0500428 char *label;
429 char *subject;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530430 const char *message;
431};
432
Jeff Kingcb646ff2023-08-29 19:43:39 -0400433static const char *short_commit_name(struct repository *r, struct commit *commit)
Johannes Schindelin39755962016-10-21 14:24:37 +0200434{
Jeff Kingcb646ff2023-08-29 19:43:39 -0400435 return repo_find_unique_abbrev(r, &commit->object.oid, DEFAULT_ABBREV);
Johannes Schindelin39755962016-10-21 14:24:37 +0200436}
437
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530438static int get_message(struct commit *commit, struct commit_message *out)
439{
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530440 const char *abbrev, *subject;
Jeff King7b35eaf2016-02-22 17:44:57 -0500441 int subject_len;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530442
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200443 out->message = repo_logmsg_reencode(the_repository, commit, NULL,
444 get_commit_output_encoding());
Jeff Kingcb646ff2023-08-29 19:43:39 -0400445 abbrev = short_commit_name(the_repository, commit);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530446
447 subject_len = find_commit_subject(out->message, &subject);
448
Jeff King7b35eaf2016-02-22 17:44:57 -0500449 out->subject = xmemdupz(subject, subject_len);
Elijah Newren7d056de2020-08-12 14:40:04 +0000450 out->label = xstrfmt("%s (%s)", abbrev, out->subject);
Jeff King7b35eaf2016-02-22 17:44:57 -0500451 out->parent_label = xstrfmt("parent of %s", out->label);
452
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530453 return 0;
454}
455
Jeff Kingd74a4e52014-06-10 17:39:35 -0400456static void free_message(struct commit *commit, struct commit_message *msg)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530457{
458 free(msg->parent_label);
Jeff King7b35eaf2016-02-22 17:44:57 -0500459 free(msg->label);
460 free(msg->subject);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200461 repo_unuse_commit_buffer(the_repository, commit, msg->message);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530462}
463
Phillip Wood72a8d3f2024-02-27 14:06:23 +0000464const char *rebase_resolvemsg =
465N_("Resolve all conflicts manually, mark them as resolved with\n"
466"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
467"You can instead skip this commit: run \"git rebase --skip\".\n"
468"To abort and get back to the state before \"git rebase\", run "
469"\"git rebase --abort\".");
470
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100471static void print_advice(struct repository *r, int show_hint,
472 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530473{
Phillip Wood72a8d3f2024-02-27 14:06:23 +0000474 const char *msg;
475
476 if (is_rebase_i(opts))
477 msg = rebase_resolvemsg;
478 else
479 msg = getenv("GIT_CHERRY_PICK_HELP");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530480
481 if (msg) {
Philippe Blainec030092024-03-16 21:16:29 +0000482 advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", msg);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530483 /*
Stefano Lattarini41ccfdd2013-04-12 00:36:10 +0200484 * A conflict has occurred but the porcelain
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530485 * (typically rebase --interactive) wants to take care
486 * of the commit itself so remove CHERRY_PICK_HEAD
487 */
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +0000488 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
Patrick Steinhardt821f6632024-01-19 11:39:59 +0100489 NULL, REF_NO_DEREF);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530490 return;
491 }
492
Phil Horded727b12012-02-21 19:44:17 -0500493 if (show_hint) {
494 if (opts->no_commit)
Philippe Blainec030092024-03-16 21:16:29 +0000495 advise_if_enabled(ADVICE_MERGE_CONFLICT,
496 _("after resolving the conflicts, mark the corrected paths\n"
497 "with 'git add <paths>' or 'git rm <paths>'"));
ZheNing Huf1725562021-08-22 13:08:41 +0000498 else if (opts->action == REPLAY_PICK)
Philippe Blainec030092024-03-16 21:16:29 +0000499 advise_if_enabled(ADVICE_MERGE_CONFLICT,
500 _("After resolving the conflicts, mark them with\n"
501 "\"git add/rm <pathspec>\", then run\n"
502 "\"git cherry-pick --continue\".\n"
503 "You can instead skip this commit with \"git cherry-pick --skip\".\n"
504 "To abort and get back to the state before \"git cherry-pick\",\n"
505 "run \"git cherry-pick --abort\"."));
ZheNing Huf1725562021-08-22 13:08:41 +0000506 else if (opts->action == REPLAY_REVERT)
Philippe Blainec030092024-03-16 21:16:29 +0000507 advise_if_enabled(ADVICE_MERGE_CONFLICT,
508 _("After resolving the conflicts, mark them with\n"
509 "\"git add/rm <pathspec>\", then run\n"
510 "\"git revert --continue\".\n"
511 "You can instead skip this commit with \"git revert --skip\".\n"
512 "To abort and get back to the state before \"git revert\",\n"
513 "run \"git revert --abort\"."));
Phil Horded727b12012-02-21 19:44:17 -0500514 else
ZheNing Huf1725562021-08-22 13:08:41 +0000515 BUG("unexpected pick action in print_advice()");
Phil Horded727b12012-02-21 19:44:17 -0500516 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530517}
518
Alban Gruinddb81e52019-03-05 20:18:01 +0100519static int write_message(const void *buf, size_t len, const char *filename,
520 int append_eol)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530521{
Martin Ågren14bca6c2018-02-27 22:30:09 +0100522 struct lock_file msg_file = LOCK_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530523
Johannes Schindelin4ef3d8f2016-09-09 16:37:05 +0200524 int msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);
525 if (msg_fd < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200526 return error_errno(_("could not lock '%s'"), filename);
Johannes Schindelin75871492016-10-21 14:26:05 +0200527 if (write_in_full(msg_fd, buf, len) < 0) {
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200528 error_errno(_("could not write to '%s'"), filename);
Johannes Schindelin4f66c832016-10-21 14:26:00 +0200529 rollback_lock_file(&msg_file);
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200530 return -1;
Johannes Schindelin4f66c832016-10-21 14:26:00 +0200531 }
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200532 if (append_eol && write(msg_fd, "\n", 1) < 0) {
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200533 error_errno(_("could not write eol to '%s'"), filename);
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200534 rollback_lock_file(&msg_file);
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200535 return -1;
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200536 }
Martin Ågren350292a2018-02-28 20:07:58 +0100537 if (commit_lock_file(&msg_file) < 0)
538 return error(_("failed to finalize '%s'"), filename);
Johannes Schindelin4ef3d8f2016-09-09 16:37:05 +0200539
540 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530541}
542
Denton Liuc20de8b2020-04-07 10:27:54 -0400543int read_oneliner(struct strbuf *buf,
Denton Liu3442c3d2020-04-07 10:27:52 -0400544 const char *path, unsigned flags)
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200545{
546 int orig_len = buf->len;
547
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200548 if (strbuf_read_file(buf, path, 0) < 0) {
Denton Liubfa50c22020-04-07 10:27:53 -0400549 if ((flags & READ_ONELINER_WARN_MISSING) ||
550 (errno != ENOENT && errno != ENOTDIR))
Denton Liu5b2f6d92020-04-07 10:27:51 -0400551 warning_errno(_("could not read '%s'"), path);
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200552 return 0;
553 }
554
555 if (buf->len > orig_len && buf->buf[buf->len - 1] == '\n') {
556 if (--buf->len > orig_len && buf->buf[buf->len - 1] == '\r')
557 --buf->len;
558 buf->buf[buf->len] = '\0';
559 }
560
Denton Liu3442c3d2020-04-07 10:27:52 -0400561 if ((flags & READ_ONELINER_SKIP_IF_EMPTY) && buf->len == orig_len)
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200562 return 0;
563
564 return 1;
565}
566
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100567static struct tree *empty_tree(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530568{
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100569 return lookup_tree(r, the_hash_algo->empty_tree);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530570}
571
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700572static int error_dirty_index(struct repository *repo, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530573{
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700574 if (repo_read_index_unmerged(repo))
Michael J Gruber1c8dfc32022-08-18 15:13:27 +0200575 return error_resolve_conflict(action_name(opts));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530576
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200577 error(_("your local changes would be overwritten by %s."),
Johannes Schindelinc28cbc52016-10-21 14:26:17 +0200578 _(action_name(opts)));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530579
Ben Boeckeled9bff02021-08-23 12:44:00 +0200580 if (advice_enabled(ADVICE_COMMIT_BEFORE_MERGE))
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200581 advise(_("commit your changes or stash them to proceed."));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530582 return -1;
583}
584
Stephan Beyer1e412292016-12-07 22:51:32 +0100585static void update_abort_safety_file(void)
586{
587 struct object_id head;
588
589 /* Do nothing on a single-pick */
590 if (!file_exists(git_path_seq_dir()))
591 return;
592
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +0200593 if (!repo_get_oid(the_repository, "HEAD", &head))
Stephan Beyer1e412292016-12-07 22:51:32 +0100594 write_file(git_path_abort_safety_file(), "%s", oid_to_hex(&head));
595 else
596 write_file(git_path_abort_safety_file(), "%s", "");
597}
598
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100599static int fast_forward_to(struct repository *r,
600 const struct object_id *to,
601 const struct object_id *from,
602 int unborn,
603 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530604{
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700605 struct ref_transaction *transaction;
Ramkumar Ramachandraeb4be1c2013-06-19 13:07:09 +0530606 struct strbuf sb = STRBUF_INIT;
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700607 struct strbuf err = STRBUF_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530608
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700609 repo_read_index(r);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100610 if (checkout_fast_forward(r, from, to, 1))
Johannes Schindelin0e408fc2016-09-09 16:37:55 +0200611 return -1; /* the callee should have complained already */
Ronnie Sahlberg651ab9f2014-04-16 11:56:52 -0700612
Michael J Gruber5670e0e2022-08-18 15:13:26 +0200613 strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700614
615 transaction = ref_transaction_begin(&err);
616 if (!transaction ||
617 ref_transaction_update(transaction, "HEAD",
Johannes Schindelind87d48b2018-05-04 01:01:17 +0200618 to, unborn && !is_rebase_i(opts) ?
brian m. carlson14228442021-04-26 01:02:56 +0000619 null_oid() : from,
Michael Haggerty1d147bd2015-02-17 18:00:15 +0100620 0, sb.buf, &err) ||
Ronnie Sahlbergdb7516a2014-04-30 12:22:42 -0700621 ref_transaction_commit(transaction, &err)) {
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700622 ref_transaction_free(transaction);
623 error("%s", err.buf);
624 strbuf_release(&sb);
625 strbuf_release(&err);
626 return -1;
627 }
Ronnie Sahlberg651ab9f2014-04-16 11:56:52 -0700628
Ramkumar Ramachandraeb4be1c2013-06-19 13:07:09 +0530629 strbuf_release(&sb);
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700630 strbuf_release(&err);
631 ref_transaction_free(transaction);
Stephan Beyer1e412292016-12-07 22:51:32 +0100632 update_abort_safety_file();
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700633 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530634}
635
Denton Liuf29cd862019-04-17 11:23:25 +0100636enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
637 int use_editor)
638{
639 if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
640 return use_editor ? COMMIT_MSG_CLEANUP_ALL :
641 COMMIT_MSG_CLEANUP_SPACE;
642 else if (!strcmp(cleanup_arg, "verbatim"))
643 return COMMIT_MSG_CLEANUP_NONE;
644 else if (!strcmp(cleanup_arg, "whitespace"))
645 return COMMIT_MSG_CLEANUP_SPACE;
646 else if (!strcmp(cleanup_arg, "strip"))
647 return COMMIT_MSG_CLEANUP_ALL;
648 else if (!strcmp(cleanup_arg, "scissors"))
649 return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
650 COMMIT_MSG_CLEANUP_SPACE;
651 else
652 die(_("Invalid cleanup mode %s"), cleanup_arg);
653}
654
Phillip Wooddc42e9a2019-04-17 11:23:29 +0100655/*
656 * NB using int rather than enum cleanup_mode to stop clang's
657 * -Wtautological-constant-out-of-range-compare complaining that the comparison
658 * is always true.
659 */
660static const char *describe_cleanup_mode(int cleanup_mode)
661{
662 static const char *modes[] = { "whitespace",
663 "verbatim",
664 "scissors",
665 "strip" };
666
667 if (cleanup_mode < ARRAY_SIZE(modes))
668 return modes[cleanup_mode];
669
670 BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
671}
672
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100673void append_conflicts_hint(struct index_state *istate,
Denton Liu1a2b9852019-04-17 11:23:30 +0100674 struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
Junio C Hamano75c961b2014-10-24 11:34:59 -0700675{
676 int i;
677
Denton Liu1a2b9852019-04-17 11:23:30 +0100678 if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
679 strbuf_addch(msgbuf, '\n');
680 wt_status_append_cut_line(msgbuf);
Jeff Kingf99e1d92024-03-12 05:17:34 -0400681 strbuf_addstr(msgbuf, comment_line_str);
Denton Liu1a2b9852019-04-17 11:23:30 +0100682 }
683
Junio C Hamano261f3152014-10-28 13:04:38 -0700684 strbuf_addch(msgbuf, '\n');
Jeff King3a35d962024-03-12 05:17:29 -0400685 strbuf_commented_addf(msgbuf, comment_line_str, "Conflicts:\n");
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100686 for (i = 0; i < istate->cache_nr;) {
687 const struct cache_entry *ce = istate->cache[i++];
Junio C Hamano75c961b2014-10-24 11:34:59 -0700688 if (ce_stage(ce)) {
Jeff King3a35d962024-03-12 05:17:29 -0400689 strbuf_commented_addf(msgbuf, comment_line_str,
Calvin Wan787cb8a2023-06-06 19:48:43 +0000690 "\t%s\n", ce->name);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100691 while (i < istate->cache_nr &&
692 !strcmp(ce->name, istate->cache[i]->name))
Junio C Hamano75c961b2014-10-24 11:34:59 -0700693 i++;
694 }
695 }
696}
697
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100698static int do_recursive_merge(struct repository *r,
699 struct commit *base, struct commit *next,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530700 const char *base_label, const char *next_label,
brian m. carlson48be4c62017-05-06 22:10:36 +0000701 struct object_id *head, struct strbuf *msgbuf,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530702 struct replay_opts *opts)
703{
704 struct merge_options o;
Elijah Newren14c45862020-11-02 23:45:34 +0000705 struct merge_result result;
Elijah Newrenb4db8a22019-08-17 11:41:30 -0700706 struct tree *next_tree, *base_tree, *head_tree;
Elijah Newren14c45862020-11-02 23:45:34 +0000707 int clean, show_output;
Jeff Kingd20bc012020-01-29 00:46:47 -0500708 int i;
Martin Ågren14bca6c2018-02-27 22:30:09 +0100709 struct lock_file index_lock = LOCK_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530710
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +0700711 if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0)
Phillip Woodbd588862017-11-15 10:41:25 +0000712 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530713
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700714 repo_read_index(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530715
Nguyễn Thái Ngọc Duy0d6caa22019-01-12 09:13:29 +0700716 init_merge_options(&o, r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530717 o.ancestor = base ? base_label : "(empty tree)";
718 o.branch1 = "HEAD";
719 o.branch2 = next ? next_label : "(empty tree)";
Johannes Schindelin62fdb652017-01-02 16:35:39 +0100720 if (is_rebase_i(opts))
721 o.buffer_output = 2;
Elijah Newren9268cf42017-11-13 12:16:00 -0800722 o.show_rename_progress = 1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530723
724 head_tree = parse_tree_indirect(head);
Johannes Schindelinaa9f6182024-02-23 08:34:23 +0000725 if (!head_tree)
726 return error(_("unable to read tree (%s)"), oid_to_hex(head));
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +0200727 next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
728 base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530729
Phillip Woodfb60b9f2023-04-10 10:08:28 +0100730 for (i = 0; i < opts->xopts.nr; i++)
731 parse_merge_opt(&o, opts->xopts.v[i]);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530732
Elijah Newren6a5fb962021-08-04 05:38:01 +0000733 if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
Elijah Newren14c45862020-11-02 23:45:34 +0000734 memset(&result, 0, sizeof(result));
735 merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,
736 &result);
737 show_output = !is_rebase_i(opts) || !result.clean;
738 /*
739 * TODO: merge_switch_to_result will update index/working tree;
740 * we only really want to do that if !result.clean || this is
741 * the final patch to be picked. But determining this is the
742 * final patch would take some work, and "head_tree" would need
743 * to be replace with the tree the index matched before we
744 * started doing any picks.
745 */
746 merge_switch_to_result(&o, head_tree, &result, 1, show_output);
747 clean = result.clean;
748 } else {
Derrick Stolee5d9c9342021-09-08 11:24:00 +0000749 ensure_full_index(r->index);
Elijah Newren14c45862020-11-02 23:45:34 +0000750 clean = merge_trees(&o, head_tree, next_tree, base_tree);
751 if (is_rebase_i(opts) && clean <= 0)
752 fputs(o.obuf.buf, stdout);
753 strbuf_release(&o.obuf);
754 }
Martin Ågren64816522018-02-27 22:30:10 +0100755 if (clean < 0) {
756 rollback_lock_file(&index_lock);
Johannes Schindelinf241ff02016-07-26 18:06:02 +0200757 return clean;
Martin Ågren64816522018-02-27 22:30:10 +0100758 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530759
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100760 if (write_locked_index(r->index, &index_lock,
Martin Ågren61000812018-03-01 21:40:20 +0100761 COMMIT_LOCK | SKIP_IF_UNCHANGED))
Ævar Arnfjörð Bjarmason66f5f6d2017-05-11 21:20:12 +0000762 /*
763 * TRANSLATORS: %s will be "revert", "cherry-pick" or
Elijah Newrenc2417d32020-02-15 21:36:36 +0000764 * "rebase".
Johannes Schindelin84583952017-01-02 16:26:28 +0100765 */
Johannes Schindelinc527b552016-09-09 16:37:10 +0200766 return error(_("%s: Unable to write new index file"),
Johannes Schindelinc28cbc52016-10-21 14:26:17 +0200767 _(action_name(opts)));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530768
Junio C Hamano75c961b2014-10-24 11:34:59 -0700769 if (!clean)
Denton Liu1a2b9852019-04-17 11:23:30 +0100770 append_conflicts_hint(r->index, msgbuf,
771 opts->default_msg_cleanup);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530772
773 return !clean;
774}
775
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100776static struct object_id *get_cache_tree_oid(struct index_state *istate)
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200777{
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100778 if (!cache_tree_fully_valid(istate->cache_tree))
779 if (cache_tree_update(istate, 0)) {
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200780 error(_("unable to update cache tree"));
781 return NULL;
782 }
783
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100784 return &istate->cache_tree->oid;
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200785}
786
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100787static int is_index_unchanged(struct repository *r)
Neil Hormanb27cfb02012-04-20 10:36:15 -0400788{
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200789 struct object_id head_oid, *cache_tree_oid;
Brian Lyles1b905882024-03-25 18:16:51 -0500790 const struct object_id *head_tree_oid;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400791 struct commit *head_commit;
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100792 struct index_state *istate = r->index;
Brian Lyles1b905882024-03-25 18:16:51 -0500793 const char *head_name;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400794
Brian Lyles1b905882024-03-25 18:16:51 -0500795 if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) {
796 /* Check to see if this is an unborn branch */
797 head_name = resolve_ref_unsafe("HEAD",
798 RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
799 &head_oid, NULL);
800 if (!head_name ||
801 !starts_with(head_name, "refs/heads/") ||
802 !is_null_oid(&head_oid))
803 return error(_("could not resolve HEAD commit"));
804 head_tree_oid = the_hash_algo->empty_tree;
805 } else {
806 head_commit = lookup_commit(r, &head_oid);
Neil Hormanb27cfb02012-04-20 10:36:15 -0400807
Brian Lyles1b905882024-03-25 18:16:51 -0500808 /*
809 * If head_commit is NULL, check_commit, called from
810 * lookup_commit, would have indicated that head_commit is not
811 * a commit object already. repo_parse_commit() will return failure
812 * without further complaints in such a case. Otherwise, if
813 * the commit is invalid, repo_parse_commit() will complain. So
814 * there is nothing for us to say here. Just return failure.
815 */
816 if (repo_parse_commit(r, head_commit))
817 return -1;
Neil Horman4b580062012-05-03 08:10:22 -0400818
Brian Lyles1b905882024-03-25 18:16:51 -0500819 head_tree_oid = get_commit_tree_oid(head_commit);
820 }
Neil Hormanb27cfb02012-04-20 10:36:15 -0400821
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100822 if (!(cache_tree_oid = get_cache_tree_oid(istate)))
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200823 return -1;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400824
Brian Lyles1b905882024-03-25 18:16:51 -0500825 return oideq(cache_tree_oid, head_tree_oid);
Neil Hormanb27cfb02012-04-20 10:36:15 -0400826}
827
Johannes Schindelin0473f282017-01-02 16:27:18 +0100828static int write_author_script(const char *message)
829{
830 struct strbuf buf = STRBUF_INIT;
831 const char *eol;
832 int res;
833
834 for (;;)
835 if (!*message || starts_with(message, "\n")) {
836missing_author:
837 /* Missing 'author' line? */
838 unlink(rebase_path_author_script());
839 return 0;
840 } else if (skip_prefix(message, "author ", &message))
841 break;
842 else if ((eol = strchr(message, '\n')))
843 message = eol + 1;
844 else
845 goto missing_author;
846
847 strbuf_addstr(&buf, "GIT_AUTHOR_NAME='");
848 while (*message && *message != '\n' && *message != '\r')
849 if (skip_prefix(message, " <", &message))
850 break;
851 else if (*message != '\'')
852 strbuf_addch(&buf, *(message++));
853 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100854 strbuf_addf(&buf, "'\\%c'", *(message++));
Johannes Schindelin0473f282017-01-02 16:27:18 +0100855 strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
856 while (*message && *message != '\n' && *message != '\r')
857 if (skip_prefix(message, "> ", &message))
858 break;
859 else if (*message != '\'')
860 strbuf_addch(&buf, *(message++));
861 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100862 strbuf_addf(&buf, "'\\%c'", *(message++));
Johannes Schindelin0473f282017-01-02 16:27:18 +0100863 strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
864 while (*message && *message != '\n' && *message != '\r')
865 if (*message != '\'')
866 strbuf_addch(&buf, *(message++));
867 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100868 strbuf_addf(&buf, "'\\%c'", *(message++));
Eric Sunshine0f16c092018-07-31 03:33:29 -0400869 strbuf_addch(&buf, '\'');
Johannes Schindelin0473f282017-01-02 16:27:18 +0100870 res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
871 strbuf_release(&buf);
872 return res;
873}
874
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000875/**
876 * Take a series of KEY='VALUE' lines where VALUE part is
877 * sq-quoted, and append <KEY, VALUE> at the end of the string list
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100878 */
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000879static int parse_key_value_squoted(char *buf, struct string_list *list)
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100880{
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000881 while (*buf) {
882 struct string_list_item *item;
883 char *np;
884 char *cp = strchr(buf, '=');
885 if (!cp) {
886 np = strchrnul(buf, '\n');
887 return error(_("no key present in '%.*s'"),
888 (int) (np - buf), buf);
889 }
890 np = strchrnul(cp, '\n');
891 *cp++ = '\0';
892 item = string_list_append(list, buf);
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100893
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000894 buf = np + (*np == '\n');
895 *np = '\0';
896 cp = sq_dequote(cp);
897 if (!cp)
898 return error(_("unable to dequote value of '%s'"),
899 item->string);
900 item->util = xstrdup(cp);
901 }
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100902 return 0;
903}
904
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000905/**
906 * Reads and parses the state directory's "author-script" file, and sets name,
907 * email and date accordingly.
908 * Returns 0 on success, -1 if the file could not be parsed.
909 *
910 * The author script is of the format:
911 *
912 * GIT_AUTHOR_NAME='$author_name'
913 * GIT_AUTHOR_EMAIL='$author_email'
914 * GIT_AUTHOR_DATE='$author_date'
915 *
916 * where $author_name, $author_email and $author_date are quoted. We are strict
Johannes Schindelinc3c003e2019-05-14 04:22:33 -0700917 * with our parsing, as the file was meant to be eval'd in the now-removed
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000918 * git-am.sh/git-rebase--interactive.sh scripts, and thus if the file differs
919 * from what this function expects, it is better to bail out than to do
920 * something that the user does not expect.
921 */
922int read_author_script(const char *path, char **name, char **email, char **date,
923 int allow_missing)
924{
925 struct strbuf buf = STRBUF_INIT;
926 struct string_list kv = STRING_LIST_INIT_DUP;
927 int retval = -1; /* assume failure */
928 int i, name_i = -2, email_i = -2, date_i = -2, err = 0;
929
930 if (strbuf_read_file(&buf, path, 256) <= 0) {
931 strbuf_release(&buf);
932 if (errno == ENOENT && allow_missing)
933 return 0;
934 else
935 return error_errno(_("could not open '%s' for reading"),
936 path);
937 }
938
939 if (parse_key_value_squoted(buf.buf, &kv))
940 goto finish;
941
942 for (i = 0; i < kv.nr; i++) {
943 if (!strcmp(kv.items[i].string, "GIT_AUTHOR_NAME")) {
944 if (name_i != -2)
945 name_i = error(_("'GIT_AUTHOR_NAME' already given"));
946 else
947 name_i = i;
948 } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_EMAIL")) {
949 if (email_i != -2)
950 email_i = error(_("'GIT_AUTHOR_EMAIL' already given"));
951 else
952 email_i = i;
953 } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_DATE")) {
954 if (date_i != -2)
955 date_i = error(_("'GIT_AUTHOR_DATE' already given"));
956 else
957 date_i = i;
958 } else {
959 err = error(_("unknown variable '%s'"),
960 kv.items[i].string);
961 }
962 }
963 if (name_i == -2)
964 error(_("missing 'GIT_AUTHOR_NAME'"));
965 if (email_i == -2)
966 error(_("missing 'GIT_AUTHOR_EMAIL'"));
967 if (date_i == -2)
968 error(_("missing 'GIT_AUTHOR_DATE'"));
Jeff King45350ae2022-10-03 13:35:02 -0400969 if (name_i < 0 || email_i < 0 || date_i < 0 || err)
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000970 goto finish;
Junio C Hamano4d924522020-01-12 12:27:41 -0800971 *name = kv.items[name_i].util;
972 *email = kv.items[email_i].util;
973 *date = kv.items[date_i].util;
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000974 retval = 0;
975finish:
976 string_list_clear(&kv, !!retval);
977 strbuf_release(&buf);
978 return retval;
979}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530980
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530981/*
Phillip Wood4d010a72018-10-31 10:15:56 +0000982 * Read a GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL AND GIT_AUTHOR_DATE from a
Jeff Kingc972bf42020-07-28 16:25:12 -0400983 * file with shell quoting into struct strvec. Returns -1 on
Phillip Wood4d010a72018-10-31 10:15:56 +0000984 * error, 0 otherwise.
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200985 */
Jeff Kingc972bf42020-07-28 16:25:12 -0400986static int read_env_script(struct strvec *env)
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200987{
Phillip Wood4d010a72018-10-31 10:15:56 +0000988 char *name, *email, *date;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200989
Phillip Wood4d010a72018-10-31 10:15:56 +0000990 if (read_author_script(rebase_path_author_script(),
991 &name, &email, &date, 0))
Johannes Schindelina2a20b02017-01-02 16:35:25 +0100992 return -1;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200993
Jeff Kingc972bf42020-07-28 16:25:12 -0400994 strvec_pushf(env, "GIT_AUTHOR_NAME=%s", name);
995 strvec_pushf(env, "GIT_AUTHOR_EMAIL=%s", email);
996 strvec_pushf(env, "GIT_AUTHOR_DATE=%s", date);
Phillip Wood4d010a72018-10-31 10:15:56 +0000997 free(name);
998 free(email);
999 free(date);
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001000
Johannes Schindelina2a20b02017-01-02 16:35:25 +01001001 return 0;
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001002}
1003
Phillip Wood356ee462017-11-24 11:07:57 +00001004static char *get_author(const char *message)
1005{
1006 size_t len;
1007 const char *a;
1008
1009 a = find_commit_header(message, "author", &len);
1010 if (a)
1011 return xmemdupz(a, len);
1012
1013 return NULL;
1014}
1015
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +02001016static const char *author_date_from_env(const struct strvec *env)
Phillip Wood7573cec2020-08-17 18:40:02 +01001017{
1018 int i;
1019 const char *date;
1020
Junio C Hamano9c31b192020-09-03 12:37:01 -07001021 for (i = 0; i < env->nr; i++)
1022 if (skip_prefix(env->v[i],
Phillip Wood7573cec2020-08-17 18:40:02 +01001023 "GIT_AUTHOR_DATE=", &date))
1024 return date;
1025 /*
1026 * If GIT_AUTHOR_DATE is missing we should have already errored out when
1027 * reading the script
1028 */
1029 BUG("GIT_AUTHOR_DATE missing from author script");
1030}
1031
Johannes Schindelin791eb872016-10-21 14:26:32 +02001032static const char staged_changes_advice[] =
1033N_("you have staged changes in your working tree\n"
1034"If these changes are meant to be squashed into the previous commit, run:\n"
1035"\n"
1036" git commit --amend %s\n"
1037"\n"
1038"If they are meant to go into a new commit, run:\n"
1039"\n"
1040" git commit %s\n"
1041"\n"
1042"In both cases, once you're done, continue with:\n"
1043"\n"
1044" git rebase --continue\n");
1045
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001046#define ALLOW_EMPTY (1<<0)
1047#define EDIT_MSG (1<<1)
1048#define AMEND_MSG (1<<2)
1049#define CLEANUP_MSG (1<<3)
Johannes Schindelinb92ff6e2017-03-23 17:07:17 +01001050#define VERIFY_MSG (1<<4)
Johannes Schindelind87d48b2018-05-04 01:01:17 +02001051#define CREATE_ROOT_COMMIT (1<<5)
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001052#define VERBATIM_MSG (1<<6)
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001053
Alban Gruin34bec2c2018-08-10 18:51:32 +02001054static int run_command_silent_on_success(struct child_process *cmd)
1055{
1056 struct strbuf buf = STRBUF_INIT;
1057 int rc;
1058
1059 cmd->stdout_to_stderr = 1;
1060 rc = pipe_command(cmd,
1061 NULL, 0,
1062 NULL, 0,
1063 &buf, 0);
1064
1065 if (rc)
1066 fputs(buf.buf, stderr);
1067 strbuf_release(&buf);
1068 return rc;
1069}
1070
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001071/*
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301072 * If we are cherry-pick, and if the merge did not result in
1073 * hand-editing, we will hit this commit and inherit the original
1074 * author date and name.
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001075 *
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301076 * If we are revert, or if our cherry-pick results in a hand merge,
1077 * we had better say that the current user is responsible for that.
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001078 *
1079 * An exception is when run_git_commit() is called during an
1080 * interactive rebase: in that case, we will want to retain the
1081 * author metadata.
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301082 */
Jeff King20f4b042020-09-30 08:29:31 -04001083static int run_git_commit(const char *defmsg,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001084 struct replay_opts *opts,
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001085 unsigned int flags)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301086{
Johannes Schindelin07d968e2017-01-02 16:35:29 +01001087 struct child_process cmd = CHILD_PROCESS_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301088
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001089 if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
1090 BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive");
1091
Johannes Schindelin07d968e2017-01-02 16:35:29 +01001092 cmd.git_cmd = 1;
1093
Phillip Wood9d6b9df2021-11-02 21:30:51 +00001094 if (is_rebase_i(opts) &&
1095 ((opts->committer_date_is_author_date && !opts->ignore_date) ||
1096 !(!defmsg && (flags & AMEND_MSG))) &&
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001097 read_env_script(&cmd.env)) {
Alban Gruin34bec2c2018-08-10 18:51:32 +02001098 const char *gpg_opt = gpg_sign_opt_quoted(opts);
Johannes Schindelin9a757c42017-01-02 16:35:34 +01001099
Alban Gruin34bec2c2018-08-10 18:51:32 +02001100 return error(_(staged_changes_advice),
1101 gpg_opt, gpg_opt);
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001102 }
1103
Phillip Woodd188a602022-11-09 14:21:57 +00001104 strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", opts->reflog_message);
1105
Phillip Wood7573cec2020-08-17 18:40:02 +01001106 if (opts->committer_date_is_author_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001107 strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
Junio C Hamano9c31b192020-09-03 12:37:01 -07001108 opts->ignore_date ?
1109 "" :
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +02001110 author_date_from_env(&cmd.env));
Phillip Wooda3894aa2020-08-17 18:40:03 +01001111 if (opts->ignore_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001112 strvec_push(&cmd.env, "GIT_AUTHOR_DATE=");
Phillip Wood7573cec2020-08-17 18:40:02 +01001113
Jeff Kingc972bf42020-07-28 16:25:12 -04001114 strvec_push(&cmd.args, "commit");
Neil Hormanb27cfb02012-04-20 10:36:15 -04001115
Johannes Schindelinb92ff6e2017-03-23 17:07:17 +01001116 if (!(flags & VERIFY_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001117 strvec_push(&cmd.args, "-n");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001118 if ((flags & AMEND_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001119 strvec_push(&cmd.args, "--amend");
Jeff King3bdd5522014-06-19 17:28:20 -04001120 if (opts->gpg_sign)
Jeff Kingc972bf42020-07-28 16:25:12 -04001121 strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
Đoàn Trần Công Danhcf0ad4d2020-04-03 17:28:03 +07001122 else
Jeff Kingc972bf42020-07-28 16:25:12 -04001123 strvec_push(&cmd.args, "--no-gpg-sign");
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001124 if (defmsg)
Jeff Kingc972bf42020-07-28 16:25:12 -04001125 strvec_pushl(&cmd.args, "-F", defmsg, NULL);
Johannes Schindelindc4b5bc2018-04-27 22:48:28 +02001126 else if (!(flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001127 strvec_pushl(&cmd.args, "-C", "HEAD", NULL);
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001128 if ((flags & CLEANUP_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001129 strvec_push(&cmd.args, "--cleanup=strip");
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001130 if ((flags & VERBATIM_MSG))
1131 strvec_push(&cmd.args, "--cleanup=verbatim");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001132 if ((flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001133 strvec_push(&cmd.args, "-e");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001134 else if (!(flags & CLEANUP_MSG) &&
Johannes Schindelin00094262016-10-21 14:25:28 +02001135 !opts->signoff && !opts->record_origin &&
Denton Liu1a2b9852019-04-17 11:23:30 +01001136 !opts->explicit_cleanup)
Jeff Kingc972bf42020-07-28 16:25:12 -04001137 strvec_push(&cmd.args, "--cleanup=verbatim");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301138
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001139 if ((flags & ALLOW_EMPTY))
Jeff Kingc972bf42020-07-28 16:25:12 -04001140 strvec_push(&cmd.args, "--allow-empty");
Neil Hormandf478b72012-04-11 16:21:53 -04001141
Elijah Newrena3ec9ea2018-09-12 14:18:48 -07001142 if (!(flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001143 strvec_push(&cmd.args, "--allow-empty-message");
Chris Webb4bee9582012-08-02 11:38:51 +01001144
Alban Gruin34bec2c2018-08-10 18:51:32 +02001145 if (is_rebase_i(opts) && !(flags & EDIT_MSG))
1146 return run_command_silent_on_success(&cmd);
1147 else
1148 return run_command(&cmd);
Neil Hormanb27cfb02012-04-20 10:36:15 -04001149}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301150
Phillip Woodd0aaa462017-11-10 11:09:42 +00001151static int rest_is_empty(const struct strbuf *sb, int start)
1152{
1153 int i, eol;
1154 const char *nl;
1155
1156 /* Check if the rest is just whitespace and Signed-off-by's. */
1157 for (i = start; i < sb->len; i++) {
1158 nl = memchr(sb->buf + i, '\n', sb->len - i);
1159 if (nl)
1160 eol = nl - sb->buf;
1161 else
1162 eol = sb->len;
1163
1164 if (strlen(sign_off_header) <= eol - i &&
1165 starts_with(sb->buf + i, sign_off_header)) {
1166 i = eol;
1167 continue;
1168 }
1169 while (i < eol)
1170 if (!isspace(sb->buf[i++]))
1171 return 0;
1172 }
1173
1174 return 1;
1175}
1176
Denton Liuf29cd862019-04-17 11:23:25 +01001177void cleanup_message(struct strbuf *msgbuf,
1178 enum commit_msg_cleanup_mode cleanup_mode, int verbose)
1179{
1180 if (verbose || /* Truncate the message just before the diff, if any. */
1181 cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
1182 strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
1183 if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
Calvin Wan787cb8a2023-06-06 19:48:43 +00001184 strbuf_stripspace(msgbuf,
Jeff King2982b652024-03-12 05:17:27 -04001185 cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
Denton Liuf29cd862019-04-17 11:23:25 +01001186}
1187
Phillip Woodd0aaa462017-11-10 11:09:42 +00001188/*
1189 * Find out if the message in the strbuf contains only whitespace and
1190 * Signed-off-by lines.
1191 */
1192int message_is_empty(const struct strbuf *sb,
1193 enum commit_msg_cleanup_mode cleanup_mode)
1194{
1195 if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
1196 return 0;
1197 return rest_is_empty(sb, 0);
1198}
1199
1200/*
1201 * See if the user edited the message in the editor or left what
1202 * was in the template intact
1203 */
1204int template_untouched(const struct strbuf *sb, const char *template_file,
1205 enum commit_msg_cleanup_mode cleanup_mode)
1206{
1207 struct strbuf tmpl = STRBUF_INIT;
1208 const char *start;
1209
1210 if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
1211 return 0;
1212
1213 if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
1214 return 0;
1215
Calvin Wan787cb8a2023-06-06 19:48:43 +00001216 strbuf_stripspace(&tmpl,
Jeff King2982b652024-03-12 05:17:27 -04001217 cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
Phillip Woodd0aaa462017-11-10 11:09:42 +00001218 if (!skip_prefix(sb->buf, tmpl.buf, &start))
1219 start = sb->buf;
1220 strbuf_release(&tmpl);
1221 return rest_is_empty(sb, start - sb->buf);
1222}
1223
Phillip Wood0505d602017-11-17 11:34:47 +00001224int update_head_with_reflog(const struct commit *old_head,
1225 const struct object_id *new_head,
1226 const char *action, const struct strbuf *msg,
1227 struct strbuf *err)
1228{
1229 struct ref_transaction *transaction;
1230 struct strbuf sb = STRBUF_INIT;
1231 const char *nl;
1232 int ret = 0;
1233
1234 if (action) {
1235 strbuf_addstr(&sb, action);
1236 strbuf_addstr(&sb, ": ");
1237 }
1238
1239 nl = strchr(msg->buf, '\n');
1240 if (nl) {
1241 strbuf_add(&sb, msg->buf, nl + 1 - msg->buf);
1242 } else {
1243 strbuf_addbuf(&sb, msg);
1244 strbuf_addch(&sb, '\n');
1245 }
1246
1247 transaction = ref_transaction_begin(err);
1248 if (!transaction ||
1249 ref_transaction_update(transaction, "HEAD", new_head,
brian m. carlson14228442021-04-26 01:02:56 +00001250 old_head ? &old_head->object.oid : null_oid(),
Phillip Wood0505d602017-11-17 11:34:47 +00001251 0, sb.buf, err) ||
1252 ref_transaction_commit(transaction, err)) {
1253 ret = -1;
1254 }
1255 ref_transaction_free(transaction);
1256 strbuf_release(&sb);
1257
1258 return ret;
1259}
1260
Phillip Wooda87a6f32017-11-17 11:34:48 +00001261static int run_rewrite_hook(const struct object_id *oldoid,
1262 const struct object_id *newoid)
1263{
1264 struct child_process proc = CHILD_PROCESS_INIT;
Phillip Wooda87a6f32017-11-17 11:34:48 +00001265 int code;
1266 struct strbuf sb = STRBUF_INIT;
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001267 const char *hook_path = find_hook("post-rewrite");
Phillip Wooda87a6f32017-11-17 11:34:48 +00001268
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001269 if (!hook_path)
Phillip Wooda87a6f32017-11-17 11:34:48 +00001270 return 0;
1271
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001272 strvec_pushl(&proc.args, hook_path, "amend", NULL);
Phillip Wooda87a6f32017-11-17 11:34:48 +00001273 proc.in = -1;
1274 proc.stdout_to_stderr = 1;
Jeff Hostetler62062862019-02-22 14:25:06 -08001275 proc.trace2_hook_name = "post-rewrite";
Phillip Wooda87a6f32017-11-17 11:34:48 +00001276
1277 code = start_command(&proc);
1278 if (code)
1279 return code;
1280 strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
1281 sigchain_push(SIGPIPE, SIG_IGN);
1282 write_in_full(proc.in, sb.buf, sb.len);
1283 close(proc.in);
1284 strbuf_release(&sb);
1285 sigchain_pop(SIGPIPE);
1286 return finish_command(&proc);
1287}
1288
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001289void commit_post_rewrite(struct repository *r,
1290 const struct commit *old_head,
Phillip Wooda87a6f32017-11-17 11:34:48 +00001291 const struct object_id *new_head)
1292{
1293 struct notes_rewrite_cfg *cfg;
1294
1295 cfg = init_copy_notes_for_rewrite("amend");
1296 if (cfg) {
1297 /* we are amending, so old_head is not NULL */
1298 copy_note_for_rewrite(cfg, &old_head->object.oid, new_head);
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001299 finish_copy_notes_for_rewrite(r, cfg, "Notes added by 'git commit --amend'");
Phillip Wooda87a6f32017-11-17 11:34:48 +00001300 }
1301 run_rewrite_hook(&old_head->object.oid, new_head);
1302}
1303
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001304static int run_prepare_commit_msg_hook(struct repository *r,
1305 struct strbuf *msg,
1306 const char *commit)
Phillip Wood66618a52018-01-24 12:34:22 +00001307{
Phillip Wood49697cb2019-10-15 10:25:31 +00001308 int ret = 0;
1309 const char *name, *arg1 = NULL, *arg2 = NULL;
Phillip Wood66618a52018-01-24 12:34:22 +00001310
1311 name = git_path_commit_editmsg();
1312 if (write_message(msg->buf, msg->len, name, 0))
1313 return -1;
1314
Phillip Wood49697cb2019-10-15 10:25:31 +00001315 if (commit) {
1316 arg1 = "commit";
1317 arg2 = commit;
1318 } else {
1319 arg1 = "message";
1320 }
Ævar Arnfjörð Bjarmasona8cc5942022-03-07 13:33:46 +01001321 if (run_commit_hook(0, r->index_file, NULL, "prepare-commit-msg", name,
Phillip Wood49697cb2019-10-15 10:25:31 +00001322 arg1, arg2, NULL))
Phillip Wood66618a52018-01-24 12:34:22 +00001323 ret = error(_("'prepare-commit-msg' hook failed"));
Phillip Wood66618a52018-01-24 12:34:22 +00001324
1325 return ret;
1326}
1327
Phillip Woode47c6ca2017-11-24 11:07:54 +00001328static const char implicit_ident_advice_noconfig[] =
1329N_("Your name and email address were configured automatically based\n"
1330"on your username and hostname. Please check that they are accurate.\n"
1331"You can suppress this message by setting them explicitly. Run the\n"
1332"following command and follow the instructions in your editor to edit\n"
1333"your configuration file:\n"
1334"\n"
1335" git config --global --edit\n"
1336"\n"
1337"After doing this, you may fix the identity used for this commit with:\n"
1338"\n"
1339" git commit --amend --reset-author\n");
1340
1341static const char implicit_ident_advice_config[] =
1342N_("Your name and email address were configured automatically based\n"
1343"on your username and hostname. Please check that they are accurate.\n"
1344"You can suppress this message by setting them explicitly:\n"
1345"\n"
1346" git config --global user.name \"Your Name\"\n"
1347" git config --global user.email you@example.com\n"
1348"\n"
1349"After doing this, you may fix the identity used for this commit with:\n"
1350"\n"
1351" git commit --amend --reset-author\n");
1352
1353static const char *implicit_ident_advice(void)
1354{
Johannes Schindelina03b0972021-07-24 22:06:52 +00001355 char *user_config = interpolate_path("~/.gitconfig", 0);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001356 char *xdg_config = xdg_config_home("config");
1357 int config_exists = file_exists(user_config) || file_exists(xdg_config);
1358
1359 free(user_config);
1360 free(xdg_config);
1361
1362 if (config_exists)
1363 return _(implicit_ident_advice_config);
1364 else
1365 return _(implicit_ident_advice_noconfig);
1366
1367}
1368
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001369void print_commit_summary(struct repository *r,
1370 const char *prefix,
1371 const struct object_id *oid,
Phillip Woode47c6ca2017-11-24 11:07:54 +00001372 unsigned int flags)
1373{
1374 struct rev_info rev;
1375 struct commit *commit;
1376 struct strbuf format = STRBUF_INIT;
1377 const char *head;
1378 struct pretty_print_context pctx = {0};
1379 struct strbuf author_ident = STRBUF_INIT;
1380 struct strbuf committer_ident = STRBUF_INIT;
Ævar Arnfjörð Bjarmasoned90f042021-10-16 11:39:23 +02001381 struct ref_store *refs;
Phillip Woode47c6ca2017-11-24 11:07:54 +00001382
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001383 commit = lookup_commit(r, oid);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001384 if (!commit)
1385 die(_("couldn't look up newly created commit"));
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001386 if (repo_parse_commit(r, commit))
Phillip Woode47c6ca2017-11-24 11:07:54 +00001387 die(_("could not parse newly created commit"));
1388
1389 strbuf_addstr(&format, "format:%h] %s");
1390
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001391 repo_format_commit_message(r, commit, "%an <%ae>", &author_ident,
1392 &pctx);
1393 repo_format_commit_message(r, commit, "%cn <%ce>", &committer_ident,
1394 &pctx);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001395 if (strbuf_cmp(&author_ident, &committer_ident)) {
1396 strbuf_addstr(&format, "\n Author: ");
1397 strbuf_addbuf_percentquote(&format, &author_ident);
1398 }
1399 if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
1400 struct strbuf date = STRBUF_INIT;
1401
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001402 repo_format_commit_message(r, commit, "%ad", &date, &pctx);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001403 strbuf_addstr(&format, "\n Date: ");
1404 strbuf_addbuf_percentquote(&format, &date);
1405 strbuf_release(&date);
1406 }
1407 if (!committer_ident_sufficiently_given()) {
1408 strbuf_addstr(&format, "\n Committer: ");
1409 strbuf_addbuf_percentquote(&format, &committer_ident);
Ben Boeckeled9bff02021-08-23 12:44:00 +02001410 if (advice_enabled(ADVICE_IMPLICIT_IDENTITY)) {
Phillip Woode47c6ca2017-11-24 11:07:54 +00001411 strbuf_addch(&format, '\n');
1412 strbuf_addstr(&format, implicit_ident_advice());
1413 }
1414 }
1415 strbuf_release(&author_ident);
1416 strbuf_release(&committer_ident);
1417
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001418 repo_init_revisions(r, &rev, prefix);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001419 setup_revisions(0, NULL, &rev, NULL);
1420
1421 rev.diff = 1;
1422 rev.diffopt.output_format =
1423 DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
1424
1425 rev.verbose_header = 1;
1426 rev.show_root_diff = 1;
1427 get_commit_format(format.buf, &rev);
1428 rev.always_show_header = 0;
Junio C Hamano0f57f732018-02-13 13:39:15 -08001429 rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
Phillip Woode47c6ca2017-11-24 11:07:54 +00001430 diff_setup_done(&rev.diffopt);
1431
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001432 refs = get_main_ref_store(r);
Ævar Arnfjörð Bjarmasonce14de02022-01-26 15:37:01 +01001433 head = refs_resolve_ref_unsafe(refs, "HEAD", 0, NULL, NULL);
Ævar Arnfjörð Bjarmason09444e72022-01-26 15:37:00 +01001434 if (!head)
1435 die(_("unable to resolve HEAD after creating commit"));
Phillip Woode47c6ca2017-11-24 11:07:54 +00001436 if (!strcmp(head, "HEAD"))
1437 head = _("detached HEAD");
1438 else
1439 skip_prefix(head, "refs/heads/", &head);
1440 printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
1441 _(" (root-commit)") : "");
1442
1443 if (!log_tree_commit(&rev, commit)) {
1444 rev.always_show_header = 1;
1445 rev.use_terminator = 1;
1446 log_tree_commit(&rev, commit);
1447 }
1448
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02001449 release_revisions(&rev);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001450 strbuf_release(&format);
1451}
1452
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001453static int parse_head(struct repository *r, struct commit **head)
Phillip Wood356ee462017-11-24 11:07:57 +00001454{
1455 struct commit *current_head;
1456 struct object_id oid;
1457
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001458 if (repo_get_oid(r, "HEAD", &oid)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001459 current_head = NULL;
1460 } else {
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001461 current_head = lookup_commit_reference(r, &oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001462 if (!current_head)
1463 return error(_("could not parse HEAD"));
Jeff King9001dc22018-08-28 17:22:48 -04001464 if (!oideq(&oid, &current_head->object.oid)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001465 warning(_("HEAD %s is not a commit!"),
1466 oid_to_hex(&oid));
1467 }
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001468 if (repo_parse_commit(r, current_head))
Phillip Wood356ee462017-11-24 11:07:57 +00001469 return error(_("could not parse HEAD commit"));
1470 }
1471 *head = current_head;
1472
1473 return 0;
1474}
1475
1476/*
1477 * Try to commit without forking 'git commit'. In some cases we need
1478 * to run 'git commit' to display an error message
1479 *
1480 * Returns:
1481 * -1 - error unable to commit
1482 * 0 - success
1483 * 1 - run 'git commit'
1484 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001485static int try_to_commit(struct repository *r,
1486 struct strbuf *msg, const char *author,
Phillip Wood356ee462017-11-24 11:07:57 +00001487 struct replay_opts *opts, unsigned int flags,
1488 struct object_id *oid)
1489{
1490 struct object_id tree;
Phillip Woodb0a31862019-08-19 02:18:23 -07001491 struct commit *current_head = NULL;
Phillip Wood356ee462017-11-24 11:07:57 +00001492 struct commit_list *parents = NULL;
1493 struct commit_extra_header *extra = NULL;
1494 struct strbuf err = STRBUF_INIT;
Phillip Wood66618a52018-01-24 12:34:22 +00001495 struct strbuf commit_msg = STRBUF_INIT;
Junio C Hamano4d924522020-01-12 12:27:41 -08001496 char *amend_author = NULL;
Phillip Wood7573cec2020-08-17 18:40:02 +01001497 const char *committer = NULL;
Phillip Wood66618a52018-01-24 12:34:22 +00001498 const char *hook_commit = NULL;
Phillip Wood356ee462017-11-24 11:07:57 +00001499 enum commit_msg_cleanup_mode cleanup;
1500 int res = 0;
1501
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001502 if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
1503 BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive");
1504
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001505 if (parse_head(r, &current_head))
Phillip Wood356ee462017-11-24 11:07:57 +00001506 return -1;
Junio C Hamano4d924522020-01-12 12:27:41 -08001507
Phillip Wood356ee462017-11-24 11:07:57 +00001508 if (flags & AMEND_MSG) {
brian m. carlson42d4e1d2020-02-22 20:17:42 +00001509 const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
Phillip Wood356ee462017-11-24 11:07:57 +00001510 const char *out_enc = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001511 const char *message = repo_logmsg_reencode(r, current_head,
1512 NULL, out_enc);
Phillip Wood356ee462017-11-24 11:07:57 +00001513
1514 if (!msg) {
1515 const char *orig_message = NULL;
1516
1517 find_commit_subject(message, &orig_message);
Phillip Wood66618a52018-01-24 12:34:22 +00001518 msg = &commit_msg;
Phillip Wood356ee462017-11-24 11:07:57 +00001519 strbuf_addstr(msg, orig_message);
Phillip Wood66618a52018-01-24 12:34:22 +00001520 hook_commit = "HEAD";
Phillip Wood356ee462017-11-24 11:07:57 +00001521 }
Junio C Hamano4d924522020-01-12 12:27:41 -08001522 author = amend_author = get_author(message);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001523 repo_unuse_commit_buffer(r, current_head,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001524 message);
Phillip Wood356ee462017-11-24 11:07:57 +00001525 if (!author) {
1526 res = error(_("unable to parse commit author"));
1527 goto out;
1528 }
1529 parents = copy_commit_list(current_head->parents);
1530 extra = read_commit_extra_headers(current_head, exclude_gpgsig);
Phillip Woodb0a31862019-08-19 02:18:23 -07001531 } else if (current_head &&
1532 (!(flags & CREATE_ROOT_COMMIT) || (flags & AMEND_MSG))) {
Phillip Wood356ee462017-11-24 11:07:57 +00001533 commit_list_insert(current_head, &parents);
1534 }
1535
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001536 if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001537 res = error(_("git write-tree failed to write a tree"));
1538 goto out;
1539 }
1540
Phillip Wood2d05ef22019-11-22 19:43:03 +00001541 if (!(flags & ALLOW_EMPTY)) {
1542 struct commit *first_parent = current_head;
1543
1544 if (flags & AMEND_MSG) {
1545 if (current_head->parents) {
1546 first_parent = current_head->parents->item;
1547 if (repo_parse_commit(r, first_parent)) {
1548 res = error(_("could not parse HEAD commit"));
1549 goto out;
1550 }
1551 } else {
1552 first_parent = NULL;
1553 }
1554 }
1555 if (oideq(first_parent
1556 ? get_commit_tree_oid(first_parent)
1557 : the_hash_algo->empty_tree,
1558 &tree)) {
1559 res = 1; /* run 'git commit' to display error message */
1560 goto out;
1561 }
Phillip Wood356ee462017-11-24 11:07:57 +00001562 }
1563
Ævar Arnfjörð Bjarmason07a348e2021-09-26 21:03:28 +02001564 if (hook_exists("prepare-commit-msg")) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001565 res = run_prepare_commit_msg_hook(r, msg, hook_commit);
Phillip Wood66618a52018-01-24 12:34:22 +00001566 if (res)
1567 goto out;
1568 if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
1569 2048) < 0) {
1570 res = error_errno(_("unable to read commit message "
1571 "from '%s'"),
1572 git_path_commit_editmsg());
1573 goto out;
1574 }
1575 msg = &commit_msg;
1576 }
1577
Phillip Woodd74f3e52019-03-29 11:08:42 +00001578 if (flags & CLEANUP_MSG)
1579 cleanup = COMMIT_MSG_CLEANUP_ALL;
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001580 else if (flags & VERBATIM_MSG)
1581 cleanup = COMMIT_MSG_CLEANUP_NONE;
Phillip Woodd74f3e52019-03-29 11:08:42 +00001582 else if ((opts->signoff || opts->record_origin) &&
1583 !opts->explicit_cleanup)
1584 cleanup = COMMIT_MSG_CLEANUP_SPACE;
1585 else
1586 cleanup = opts->default_msg_cleanup;
Phillip Wood66618a52018-01-24 12:34:22 +00001587
1588 if (cleanup != COMMIT_MSG_CLEANUP_NONE)
Calvin Wan787cb8a2023-06-06 19:48:43 +00001589 strbuf_stripspace(msg,
Jeff King2982b652024-03-12 05:17:27 -04001590 cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
Elijah Newrena3ec9ea2018-09-12 14:18:48 -07001591 if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
Phillip Wood66618a52018-01-24 12:34:22 +00001592 res = 1; /* run 'git commit' to display error message */
1593 goto out;
1594 }
1595
Phillip Wood7573cec2020-08-17 18:40:02 +01001596 if (opts->committer_date_is_author_date) {
1597 struct ident_split id;
1598 struct strbuf date = STRBUF_INIT;
Johannes Sixt12f7bab2018-04-18 20:15:04 +02001599
Phillip Wooda3894aa2020-08-17 18:40:03 +01001600 if (!opts->ignore_date) {
1601 if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
1602 res = error(_("invalid author identity '%s'"),
1603 author);
1604 goto out;
1605 }
1606 if (!id.date_begin) {
1607 res = error(_(
1608 "corrupt author: missing date information"));
1609 goto out;
1610 }
1611 strbuf_addf(&date, "@%.*s %.*s",
1612 (int)(id.date_end - id.date_begin),
1613 id.date_begin,
1614 (int)(id.tz_end - id.tz_begin),
1615 id.tz_begin);
1616 } else {
1617 reset_ident_date();
Phillip Wood7573cec2020-08-17 18:40:02 +01001618 }
Jeff King20204512020-10-23 03:26:30 -04001619 committer = fmt_ident(getenv("GIT_COMMITTER_NAME"),
1620 getenv("GIT_COMMITTER_EMAIL"),
Phillip Wooda3894aa2020-08-17 18:40:03 +01001621 WANT_COMMITTER_IDENT,
1622 opts->ignore_date ? NULL : date.buf,
Phillip Wood7573cec2020-08-17 18:40:02 +01001623 IDENT_STRICT);
1624 strbuf_release(&date);
1625 } else {
1626 reset_ident_date();
1627 }
Junio C Hamano8be83422018-02-15 14:55:43 -08001628
Phillip Wooda3894aa2020-08-17 18:40:03 +01001629 if (opts->ignore_date) {
1630 struct ident_split id;
1631 char *name, *email;
1632
1633 if (split_ident_line(&id, author, strlen(author)) < 0) {
1634 error(_("invalid author identity '%s'"), author);
1635 goto out;
1636 }
1637 name = xmemdupz(id.name_begin, id.name_end - id.name_begin);
1638 email = xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
1639 author = fmt_ident(name, email, WANT_AUTHOR_IDENT, NULL,
1640 IDENT_STRICT);
1641 free(name);
1642 free(email);
1643 }
1644
Phillip Woode8cbe212020-08-17 18:40:01 +01001645 if (commit_tree_extended(msg->buf, msg->len, &tree, parents, oid,
Phillip Wood7573cec2020-08-17 18:40:02 +01001646 author, committer, opts->gpg_sign, extra)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001647 res = error(_("failed to write commit object"));
1648 goto out;
1649 }
1650
Phillip Woodd188a602022-11-09 14:21:57 +00001651 if (update_head_with_reflog(current_head, oid, opts->reflog_message,
1652 msg, &err)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001653 res = error("%s", err.buf);
1654 goto out;
1655 }
1656
Ævar Arnfjörð Bjarmasona8cc5942022-03-07 13:33:46 +01001657 run_commit_hook(0, r->index_file, NULL, "post-commit", NULL);
Phillip Wood356ee462017-11-24 11:07:57 +00001658 if (flags & AMEND_MSG)
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001659 commit_post_rewrite(r, current_head, oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001660
1661out:
1662 free_commit_extra_headers(extra);
1663 strbuf_release(&err);
Phillip Wood66618a52018-01-24 12:34:22 +00001664 strbuf_release(&commit_msg);
Junio C Hamano4d924522020-01-12 12:27:41 -08001665 free(amend_author);
Phillip Wood356ee462017-11-24 11:07:57 +00001666
1667 return res;
1668}
1669
Phillip Wood430b75f2019-12-06 16:06:12 +00001670static int write_rebase_head(struct object_id *oid)
1671{
1672 if (update_ref("rebase", "REBASE_HEAD", oid,
1673 NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
1674 return error(_("could not update %s"), "REBASE_HEAD");
1675
1676 return 0;
1677}
1678
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001679static int do_commit(struct repository *r,
1680 const char *msg_file, const char *author,
Phillip Wood430b75f2019-12-06 16:06:12 +00001681 struct replay_opts *opts, unsigned int flags,
1682 struct object_id *oid)
Phillip Wood356ee462017-11-24 11:07:57 +00001683{
1684 int res = 1;
1685
Phillip Woodb0a31862019-08-19 02:18:23 -07001686 if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001687 struct object_id oid;
1688 struct strbuf sb = STRBUF_INIT;
1689
1690 if (msg_file && strbuf_read_file(&sb, msg_file, 2048) < 0)
1691 return error_errno(_("unable to read commit message "
1692 "from '%s'"),
1693 msg_file);
1694
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001695 res = try_to_commit(r, msg_file ? &sb : NULL,
1696 author, opts, flags, &oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001697 strbuf_release(&sb);
1698 if (!res) {
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00001699 refs_delete_ref(get_main_ref_store(r), "",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01001700 "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001701 unlink(git_path_merge_msg(r));
Phillip Wood356ee462017-11-24 11:07:57 +00001702 if (!is_rebase_i(opts))
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001703 print_commit_summary(r, NULL, &oid,
Phillip Wood356ee462017-11-24 11:07:57 +00001704 SUMMARY_SHOW_AUTHOR_DATE);
1705 return res;
1706 }
1707 }
Phillip Wood430b75f2019-12-06 16:06:12 +00001708 if (res == 1) {
1709 if (is_rebase_i(opts) && oid)
1710 if (write_rebase_head(oid))
1711 return -1;
Jeff King20f4b042020-09-30 08:29:31 -04001712 return run_git_commit(msg_file, opts, flags);
Phillip Wood430b75f2019-12-06 16:06:12 +00001713 }
Phillip Wood356ee462017-11-24 11:07:57 +00001714
1715 return res;
1716}
1717
Neil Hormanb27cfb02012-04-20 10:36:15 -04001718static int is_original_commit_empty(struct commit *commit)
1719{
brian m. carlson092bbcd2017-07-13 23:49:22 +00001720 const struct object_id *ptree_oid;
Neil Hormanb27cfb02012-04-20 10:36:15 -04001721
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001722 if (repo_parse_commit(the_repository, commit))
Johannes Schindelinaee42e12017-12-23 00:55:43 +01001723 return error(_("could not parse commit %s"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00001724 oid_to_hex(&commit->object.oid));
Neil Hormanb27cfb02012-04-20 10:36:15 -04001725 if (commit->parents) {
1726 struct commit *parent = commit->parents->item;
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001727 if (repo_parse_commit(the_repository, parent))
Johannes Schindelinaee42e12017-12-23 00:55:43 +01001728 return error(_("could not parse parent commit %s"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00001729 oid_to_hex(&parent->object.oid));
Derrick Stolee2e27bd72018-04-06 19:09:38 +00001730 ptree_oid = get_commit_tree_oid(parent);
Neil Hormanb27cfb02012-04-20 10:36:15 -04001731 } else {
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +00001732 ptree_oid = the_hash_algo->empty_tree; /* commit is root */
Neil Hormanb27cfb02012-04-20 10:36:15 -04001733 }
1734
Jeff King4a7e27e2018-08-28 17:22:40 -04001735 return oideq(ptree_oid, get_commit_tree_oid(commit));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301736}
1737
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001738/*
Elijah Newrene98c4262020-02-15 21:36:25 +00001739 * Should empty commits be allowed? Return status:
1740 * <0: Error in is_index_unchanged(r) or is_original_commit_empty(commit)
1741 * 0: Halt on empty commit
1742 * 1: Allow empty commit
1743 * 2: Drop empty commit
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001744 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001745static int allow_empty(struct repository *r,
1746 struct replay_opts *opts,
1747 struct commit *commit)
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001748{
Elijah Newrend48e5e22020-02-15 21:36:24 +00001749 int index_unchanged, originally_empty;
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001750
1751 /*
Brian Lyles661b6712024-03-25 18:16:52 -05001752 * For a commit that is initially empty, allow_empty determines if it
1753 * should be kept or not
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001754 *
Brian Lyles661b6712024-03-25 18:16:52 -05001755 * For a commit that becomes empty, keep_redundant_commits and
1756 * drop_redundant_commits determine whether the commit should be kept or
1757 * dropped. If neither is specified, halt.
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001758 */
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001759 index_unchanged = is_index_unchanged(r);
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001760 if (index_unchanged < 0)
1761 return index_unchanged;
1762 if (!index_unchanged)
1763 return 0; /* we do not have to say --allow-empty */
1764
Elijah Newrend48e5e22020-02-15 21:36:24 +00001765 originally_empty = is_original_commit_empty(commit);
1766 if (originally_empty < 0)
1767 return originally_empty;
Elijah Newrene98c4262020-02-15 21:36:25 +00001768 if (originally_empty)
Brian Lyles661b6712024-03-25 18:16:52 -05001769 return opts->allow_empty;
1770 else if (opts->keep_redundant_commits)
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001771 return 1;
Elijah Newrene98c4262020-02-15 21:36:25 +00001772 else if (opts->drop_redundant_commits)
1773 return 2;
1774 else
1775 return 0;
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001776}
1777
Johannes Schindelin414697a2017-01-02 16:27:15 +01001778static struct {
1779 char c;
1780 const char *str;
1781} todo_command_info[] = {
Derrick Stoleed7ce9a22022-07-19 18:33:37 +00001782 [TODO_PICK] = { 'p', "pick" },
1783 [TODO_REVERT] = { 0, "revert" },
1784 [TODO_EDIT] = { 'e', "edit" },
1785 [TODO_REWORD] = { 'r', "reword" },
1786 [TODO_FIXUP] = { 'f', "fixup" },
1787 [TODO_SQUASH] = { 's', "squash" },
1788 [TODO_EXEC] = { 'x', "exec" },
1789 [TODO_BREAK] = { 'b', "break" },
1790 [TODO_LABEL] = { 'l', "label" },
1791 [TODO_RESET] = { 't', "reset" },
1792 [TODO_MERGE] = { 'm', "merge" },
Derrick Stoleea97d7912022-07-19 18:33:38 +00001793 [TODO_UPDATE_REF] = { 'u', "update-ref" },
Derrick Stoleed7ce9a22022-07-19 18:33:37 +00001794 [TODO_NOOP] = { 0, "noop" },
1795 [TODO_DROP] = { 'd', "drop" },
1796 [TODO_COMMENT] = { 0, NULL },
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001797};
1798
1799static const char *command_to_string(const enum todo_command command)
1800{
Johannes Schindelinac191472017-01-02 16:34:39 +01001801 if (command < TODO_COMMENT)
Johannes Schindelin414697a2017-01-02 16:27:15 +01001802 return todo_command_info[command].str;
Jeff King7eb35e02024-03-12 05:17:42 -04001803 if (command == TODO_COMMENT)
1804 return comment_line_str;
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02001805 die(_("unknown command: %d"), command);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001806}
1807
Junio C Hamanoee5462d2017-12-27 11:12:45 -08001808static char command_to_char(const enum todo_command command)
Liam Beguind8ae6c82017-12-05 12:52:34 -05001809{
Alban Gruin68e70902020-03-30 14:42:35 +02001810 if (command < TODO_COMMENT)
Liam Beguind8ae6c82017-12-05 12:52:34 -05001811 return todo_command_info[command].c;
Jeff King7eb35e02024-03-12 05:17:42 -04001812 return 0;
Liam Beguind8ae6c82017-12-05 12:52:34 -05001813}
1814
Johannes Schindelin25c43662017-01-02 16:26:38 +01001815static int is_noop(const enum todo_command command)
1816{
Johannes Schindelinb3fdd582017-01-02 16:34:34 +01001817 return TODO_NOOP <= command;
Johannes Schindelin25c43662017-01-02 16:26:38 +01001818}
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001819
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001820static int is_fixup(enum todo_command command)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301821{
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001822 return command == TODO_FIXUP || command == TODO_SQUASH;
1823}
1824
Johannes Schindelind87d48b2018-05-04 01:01:17 +02001825/* Does this command create a (non-merge) commit? */
1826static int is_pick_or_similar(enum todo_command command)
1827{
1828 switch (command) {
1829 case TODO_PICK:
1830 case TODO_REVERT:
1831 case TODO_EDIT:
1832 case TODO_REWORD:
1833 case TODO_FIXUP:
1834 case TODO_SQUASH:
1835 return 1;
1836 default:
1837 return 0;
1838 }
1839}
1840
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301841enum todo_item_flags {
1842 TODO_EDIT_MERGE_MSG = (1 << 0),
1843 TODO_REPLACE_FIXUP_MSG = (1 << 1),
1844 TODO_EDIT_FIXUP_MSG = (1 << 2),
1845};
1846
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301847static const char first_commit_msg_str[] = N_("This is the 1st commit message:");
1848static const char nth_commit_msg_fmt[] = N_("This is the commit message #%d:");
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301849static const char skip_first_commit_msg_str[] = N_("The 1st commit message will be skipped:");
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301850static const char skip_nth_commit_msg_fmt[] = N_("The commit message #%d will be skipped:");
1851static const char combined_commit_msg_fmt[] = N_("This is a combination of %d commits.");
1852
Charvi Mendiratta1f969602021-02-09 00:55:20 +05301853static int is_fixup_flag(enum todo_command command, unsigned flag)
Phillip Wood498bb5b2021-01-19 13:10:57 +05301854{
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301855 return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||
1856 (flag & TODO_EDIT_FIXUP_MSG));
1857}
Phillip Wood7cdb9682021-01-29 23:50:44 +05301858
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301859/*
1860 * Wrapper around strbuf_add_commented_lines() which avoids double
1861 * commenting commit subjects.
1862 */
1863static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
1864{
1865 const char *s = str;
Jeff King2ec225d2024-03-12 05:17:39 -04001866 while (starts_with_mem(s, len, comment_line_str)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301867 size_t count;
1868 const char *n = memchr(s, '\n', len);
1869 if (!n)
1870 count = len;
1871 else
1872 count = n - s + 1;
1873 strbuf_add(buf, s, count);
1874 s += count;
1875 len -= count;
1876 }
Jeff Kinga1bb1462024-03-12 05:17:32 -04001877 strbuf_add_commented_lines(buf, s, len, comment_line_str);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301878}
1879
1880/* Does the current fixup chain contain a squash command? */
1881static int seen_squash(struct replay_opts *opts)
1882{
1883 return starts_with(opts->current_fixups.buf, "squash") ||
1884 strstr(opts->current_fixups.buf, "\nsquash");
1885}
1886
1887static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)
1888{
1889 strbuf_setlen(buf1, 2);
1890 strbuf_addf(buf1, _(nth_commit_msg_fmt), n);
1891 strbuf_addch(buf1, '\n');
1892 strbuf_setlen(buf2, 2);
1893 strbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);
1894 strbuf_addch(buf2, '\n');
1895}
1896
1897/*
1898 * Comment out any un-commented commit messages, updating the message comments
1899 * to say they will be skipped but do not comment out the empty lines that
1900 * surround commit messages and their comments.
1901 */
1902static void update_squash_message_for_fixup(struct strbuf *msg)
1903{
1904 void (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;
1905 struct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;
1906 const char *s, *start;
1907 char *orig_msg;
1908 size_t orig_msg_len;
1909 int i = 1;
1910
1911 strbuf_addf(&buf1, "# %s\n", _(first_commit_msg_str));
1912 strbuf_addf(&buf2, "# %s\n", _(skip_first_commit_msg_str));
1913 s = start = orig_msg = strbuf_detach(msg, &orig_msg_len);
1914 while (s) {
1915 const char *next;
1916 size_t off;
1917 if (skip_prefix(s, buf1.buf, &next)) {
1918 /*
1919 * Copy the last message, preserving the blank line
1920 * preceding the current line
1921 */
1922 off = (s > start + 1 && s[-2] == '\n') ? 1 : 0;
1923 copy_lines(msg, start, s - start - off);
1924 if (off)
1925 strbuf_addch(msg, '\n');
1926 /*
1927 * The next message needs to be commented out but the
1928 * message header is already commented out so just copy
1929 * it and the blank line that follows it.
1930 */
1931 strbuf_addbuf(msg, &buf2);
1932 if (*next == '\n')
1933 strbuf_addch(msg, *next++);
1934 start = s = next;
1935 copy_lines = add_commented_lines;
1936 update_comment_bufs(&buf1, &buf2, ++i);
1937 } else if (skip_prefix(s, buf2.buf, &next)) {
1938 off = (s > start + 1 && s[-2] == '\n') ? 1 : 0;
1939 copy_lines(msg, start, s - start - off);
1940 start = s - off;
1941 s = next;
1942 copy_lines = strbuf_add;
1943 update_comment_bufs(&buf1, &buf2, ++i);
1944 } else {
1945 s = strchr(s, '\n');
1946 if (s)
1947 s++;
1948 }
1949 }
1950 copy_lines(msg, start, orig_msg_len - (start - orig_msg));
1951 free(orig_msg);
1952 strbuf_release(&buf1);
1953 strbuf_release(&buf2);
1954}
1955
1956static int append_squash_message(struct strbuf *buf, const char *body,
1957 enum todo_command command, struct replay_opts *opts,
Charvi Mendirattaa25314c2021-02-09 00:55:19 +05301958 unsigned flag)
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301959{
1960 const char *fixup_msg;
1961 size_t commented_len = 0, fixup_off;
1962 /*
1963 * amend is non-interactive and not normally used with fixup!
1964 * or squash! commits, so only comment out those subjects when
1965 * squashing commit messages.
1966 */
1967 if (starts_with(body, "amend!") ||
1968 ((command == TODO_SQUASH || seen_squash(opts)) &&
1969 (starts_with(body, "squash!") || starts_with(body, "fixup!"))))
Charvi Mendiratta6e0e2882021-03-15 13:24:31 +05301970 commented_len = commit_subject_length(body);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301971
Jeff Kingf99e1d92024-03-12 05:17:34 -04001972 strbuf_addf(buf, "\n%s ", comment_line_str);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301973 strbuf_addf(buf, _(nth_commit_msg_fmt),
Phillip Wood498bb5b2021-01-19 13:10:57 +05301974 ++opts->current_fixup_count + 1);
1975 strbuf_addstr(buf, "\n\n");
Jeff Kinga1bb1462024-03-12 05:17:32 -04001976 strbuf_add_commented_lines(buf, body, commented_len, comment_line_str);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301977 /* buf->buf may be reallocated so store an offset into the buffer */
1978 fixup_off = buf->len;
Phillip Wood7cdb9682021-01-29 23:50:44 +05301979 strbuf_addstr(buf, body + commented_len);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301980
1981 /* fixup -C after squash behaves like squash */
Charvi Mendiratta1f969602021-02-09 00:55:20 +05301982 if (is_fixup_flag(command, flag) && !seen_squash(opts)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301983 /*
1984 * We're replacing the commit message so we need to
1985 * append the Signed-off-by: trailer if the user
1986 * requested '--signoff'.
1987 */
1988 if (opts->signoff)
1989 append_signoff(buf, 0, 0);
1990
1991 if ((command == TODO_FIXUP) &&
1992 (flag & TODO_REPLACE_FIXUP_MSG) &&
1993 (file_exists(rebase_path_fixup_msg()) ||
1994 !file_exists(rebase_path_squash_msg()))) {
1995 fixup_msg = skip_blank_lines(buf->buf + fixup_off);
1996 if (write_message(fixup_msg, strlen(fixup_msg),
1997 rebase_path_fixup_msg(), 0) < 0)
1998 return error(_("cannot write '%s'"),
1999 rebase_path_fixup_msg());
2000 } else {
2001 unlink(rebase_path_fixup_msg());
2002 }
2003 } else {
2004 unlink(rebase_path_fixup_msg());
2005 }
2006
2007 return 0;
Phillip Wood498bb5b2021-01-19 13:10:57 +05302008}
2009
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002010static int update_squash_messages(struct repository *r,
2011 enum todo_command command,
2012 struct commit *commit,
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302013 struct replay_opts *opts,
Charvi Mendirattaa25314c2021-02-09 00:55:19 +05302014 unsigned flag)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002015{
2016 struct strbuf buf = STRBUF_INIT;
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302017 int res = 0;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002018 const char *message, *body;
Doan Tran Cong Danhb3757442019-11-08 16:43:48 +07002019 const char *encoding = get_commit_output_encoding();
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002020
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002021 if (opts->current_fixup_count > 0) {
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002022 struct strbuf header = STRBUF_INIT;
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002023 char *eol;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002024
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002025 if (strbuf_read_file(&buf, rebase_path_squash_msg(), 9) <= 0)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002026 return error(_("could not read '%s'"),
2027 rebase_path_squash_msg());
2028
Jeff King600559b2024-03-12 05:17:37 -04002029 eol = !starts_with(buf.buf, comment_line_str) ?
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002030 buf.buf : strchrnul(buf.buf, '\n');
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002031
Jeff Kingf99e1d92024-03-12 05:17:34 -04002032 strbuf_addf(&header, "%s ", comment_line_str);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302033 strbuf_addf(&header, _(combined_commit_msg_fmt),
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002034 opts->current_fixup_count + 2);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002035 strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
2036 strbuf_release(&header);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302037 if (is_fixup_flag(command, flag) && !seen_squash(opts))
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302038 update_squash_message_for_fixup(&buf);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002039 } else {
brian m. carlson33d66df2017-05-06 22:10:07 +00002040 struct object_id head;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002041 struct commit *head_commit;
2042 const char *head_message, *body;
2043
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002044 if (repo_get_oid(r, "HEAD", &head))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002045 return error(_("need a HEAD to fixup"));
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002046 if (!(head_commit = lookup_commit_reference(r, &head)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002047 return error(_("could not read HEAD"));
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002048 if (!(head_message = repo_logmsg_reencode(r, head_commit, NULL,
2049 encoding)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002050 return error(_("could not read HEAD's commit message"));
2051
2052 find_commit_subject(head_message, &body);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302053 if (command == TODO_FIXUP && !flag && write_message(body, strlen(body),
Phillip Woodeab0df02021-01-19 13:10:56 +05302054 rebase_path_fixup_msg(), 0) < 0) {
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002055 repo_unuse_commit_buffer(r, head_commit, head_message);
Phillip Woodeab0df02021-01-19 13:10:56 +05302056 return error(_("cannot write '%s'"), rebase_path_fixup_msg());
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002057 }
Jeff Kingf99e1d92024-03-12 05:17:34 -04002058 strbuf_addf(&buf, "%s ", comment_line_str);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302059 strbuf_addf(&buf, _(combined_commit_msg_fmt), 2);
Jeff Kingf99e1d92024-03-12 05:17:34 -04002060 strbuf_addf(&buf, "\n%s ", comment_line_str);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302061 strbuf_addstr(&buf, is_fixup_flag(command, flag) ?
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302062 _(skip_first_commit_msg_str) :
2063 _(first_commit_msg_str));
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002064 strbuf_addstr(&buf, "\n\n");
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302065 if (is_fixup_flag(command, flag))
Calvin Wan787cb8a2023-06-06 19:48:43 +00002066 strbuf_add_commented_lines(&buf, body, strlen(body),
Jeff Kinga1bb1462024-03-12 05:17:32 -04002067 comment_line_str);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302068 else
2069 strbuf_addstr(&buf, body);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002070
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002071 repo_unuse_commit_buffer(r, head_commit, head_message);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002072 }
2073
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002074 if (!(message = repo_logmsg_reencode(r, commit, NULL, encoding)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002075 return error(_("could not read commit message of %s"),
2076 oid_to_hex(&commit->object.oid));
2077 find_commit_subject(message, &body);
2078
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302079 if (command == TODO_SQUASH || is_fixup_flag(command, flag)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302080 res = append_squash_message(&buf, body, command, opts, flag);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002081 } else if (command == TODO_FIXUP) {
Jeff Kingf99e1d92024-03-12 05:17:34 -04002082 strbuf_addf(&buf, "\n%s ", comment_line_str);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302083 strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
Phillip Wooddd2e36e2018-08-15 10:41:25 +01002084 ++opts->current_fixup_count + 1);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002085 strbuf_addstr(&buf, "\n\n");
Calvin Wan787cb8a2023-06-06 19:48:43 +00002086 strbuf_add_commented_lines(&buf, body, strlen(body),
Jeff Kinga1bb1462024-03-12 05:17:32 -04002087 comment_line_str);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002088 } else
2089 return error(_("unknown command: %d"), command);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002090 repo_unuse_commit_buffer(r, commit, message);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002091
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302092 if (!res)
2093 res = write_message(buf.buf, buf.len, rebase_path_squash_msg(),
2094 0);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002095 strbuf_release(&buf);
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002096
2097 if (!res) {
2098 strbuf_addf(&opts->current_fixups, "%s%s %s",
2099 opts->current_fixups.len ? "\n" : "",
2100 command_to_string(command),
2101 oid_to_hex(&commit->object.oid));
2102 res = write_message(opts->current_fixups.buf,
2103 opts->current_fixups.len,
2104 rebase_path_current_fixups(), 0);
2105 }
2106
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002107 return res;
2108}
2109
Nguyễn Thái Ngọc Duy3b335762018-12-09 11:25:21 +01002110static void flush_rewritten_pending(void)
2111{
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002112 struct strbuf buf = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00002113 struct object_id newoid;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002114 FILE *out;
2115
brian m. carlson092bbcd2017-07-13 23:49:22 +00002116 if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02002117 !repo_get_oid(the_repository, "HEAD", &newoid) &&
Nguyễn Thái Ngọc Duye9d983f2017-05-03 17:16:50 +07002118 (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002119 char *bol = buf.buf, *eol;
2120
2121 while (*bol) {
2122 eol = strchrnul(bol, '\n');
2123 fprintf(out, "%.*s %s\n", (int)(eol - bol),
brian m. carlson092bbcd2017-07-13 23:49:22 +00002124 bol, oid_to_hex(&newoid));
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002125 if (!*eol)
2126 break;
2127 bol = eol + 1;
2128 }
2129 fclose(out);
2130 unlink(rebase_path_rewritten_pending());
2131 }
2132 strbuf_release(&buf);
2133}
2134
2135static void record_in_rewritten(struct object_id *oid,
Nguyễn Thái Ngọc Duy3b335762018-12-09 11:25:21 +01002136 enum todo_command next_command)
2137{
Nguyễn Thái Ngọc Duye9d983f2017-05-03 17:16:50 +07002138 FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a");
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002139
2140 if (!out)
2141 return;
2142
2143 fprintf(out, "%s\n", oid_to_hex(oid));
2144 fclose(out);
2145
2146 if (!is_fixup(next_command))
2147 flush_rewritten_pending();
2148}
2149
Elijah Newren39edfd52021-03-31 06:52:20 +00002150static int should_edit(struct replay_opts *opts) {
2151 if (opts->edit < 0)
2152 /*
2153 * Note that we only handle the case of non-conflicted
2154 * commits; continue_single_pick() handles the conflicted
2155 * commits itself instead of calling this function.
2156 */
2157 return (opts->action == REPLAY_REVERT && isatty(0)) ? 1 : 0;
2158 return opts->edit;
2159}
2160
Junio C Hamano43966ab2022-05-26 23:01:39 -07002161static void refer_to_commit(struct replay_opts *opts,
2162 struct strbuf *msgbuf, struct commit *commit)
2163{
2164 if (opts->commit_use_reference) {
2165 struct pretty_print_context ctx = {
2166 .abbrev = DEFAULT_ABBREV,
2167 .date_mode.type = DATE_SHORT,
2168 };
Ævar Arnfjörð Bjarmasonbab82162023-03-28 15:58:51 +02002169 repo_format_commit_message(the_repository, commit,
2170 "%h (%s, %ad)", msgbuf, &ctx);
Junio C Hamano43966ab2022-05-26 23:01:39 -07002171 } else {
2172 strbuf_addstr(msgbuf, oid_to_hex(&commit->object.oid));
2173 }
2174}
2175
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002176static int do_pick_commit(struct repository *r,
Charvi Mendirattaae70e342021-01-29 23:50:45 +05302177 struct todo_item *item,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002178 struct replay_opts *opts,
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002179 int final_fixup, int *check_todo)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002180{
Elijah Newren39edfd52021-03-31 06:52:20 +00002181 unsigned int flags = should_edit(opts) ? EDIT_MSG : 0;
2182 const char *msg_file = should_edit(opts) ? NULL : git_path_merge_msg(r);
brian m. carlsonace976b2017-05-06 22:10:32 +00002183 struct object_id head;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302184 struct commit *base, *next, *parent;
2185 const char *base_label, *next_label;
Phillip Wood356ee462017-11-24 11:07:57 +00002186 char *author = NULL;
Jeff Kingd74a4e52014-06-10 17:39:35 -04002187 struct commit_message msg = { NULL, NULL, NULL, NULL };
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302188 struct strbuf msgbuf = STRBUF_INIT;
Elijah Newrene98c4262020-02-15 21:36:25 +00002189 int res, unborn = 0, reword = 0, allow, drop_commit;
Charvi Mendirattaae70e342021-01-29 23:50:45 +05302190 enum todo_command command = item->command;
2191 struct commit *commit = item->commit;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302192
2193 if (opts->no_commit) {
2194 /*
2195 * We do not intend to commit immediately. We just want to
2196 * merge the differences in, so let's compute the tree
Elijah Newren81483fe2021-08-04 23:50:54 +00002197 * that represents the "current" state for the merge machinery
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302198 * to work on.
2199 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002200 if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002201 return error(_("your index file is unmerged."));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302202 } else {
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002203 unborn = repo_get_oid(r, "HEAD", &head);
Johannes Schindelind87d48b2018-05-04 01:01:17 +02002204 /* Do we want to generate a root commit? */
2205 if (is_pick_or_similar(command) && opts->have_squash_onto &&
Jeff King4a7e27e2018-08-28 17:22:40 -04002206 oideq(&head, &opts->squash_onto)) {
Johannes Schindelind87d48b2018-05-04 01:01:17 +02002207 if (is_fixup(command))
2208 return error(_("cannot fixup root commit"));
2209 flags |= CREATE_ROOT_COMMIT;
2210 unborn = 1;
2211 } else if (unborn)
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +00002212 oidcpy(&head, the_hash_algo->empty_tree);
Nguyễn Thái Ngọc Duyffc00a42018-11-10 06:49:04 +01002213 if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
Brandon Williams02f2f562017-10-31 11:19:05 -07002214 NULL, 0))
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07002215 return error_dirty_index(r, opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302216 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002217 discard_index(r->index);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302218
Johannes Schindelin637666c2017-01-02 16:26:08 +01002219 if (!commit->parents)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302220 parent = NULL;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302221 else if (commit->parents->next) {
2222 /* Reverting or cherry-picking a merge commit */
2223 int cnt;
2224 struct commit_list *p;
2225
2226 if (!opts->mainline)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002227 return error(_("commit %s is a merge but no -m option was given."),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002228 oid_to_hex(&commit->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302229
2230 for (cnt = 1, p = commit->parents;
2231 cnt != opts->mainline && p;
2232 cnt++)
2233 p = p->next;
2234 if (cnt != opts->mainline || !p)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002235 return error(_("commit %s does not have parent %d"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002236 oid_to_hex(&commit->object.oid), opts->mainline);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302237 parent = p->item;
Sergey Organov37897bf2018-12-14 07:53:51 +03002238 } else if (1 < opts->mainline)
2239 /*
2240 * Non-first parent explicitly specified as mainline for
2241 * non-merge commit
2242 */
2243 return error(_("commit %s does not have parent %d"),
2244 oid_to_hex(&commit->object.oid), opts->mainline);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302245 else
2246 parent = commit->parents->item;
2247
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002248 if (get_message(commit, &msg) != 0)
2249 return error(_("cannot get commit message for %s"),
2250 oid_to_hex(&commit->object.oid));
2251
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002252 if (opts->allow_ff && !is_fixup(command) &&
Jeff King4a7e27e2018-08-28 17:22:40 -04002253 ((parent && oideq(&parent->object.oid, &head)) ||
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002254 (!parent && unborn))) {
2255 if (is_rebase_i(opts))
2256 write_author_script(msg.message);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002257 res = fast_forward_to(r, &commit->object.oid, &head, unborn,
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002258 opts);
2259 if (res || command != TODO_REWORD)
2260 goto leave;
Phillip Wood450efe22019-08-19 02:18:21 -07002261 reword = 1;
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002262 msg_file = NULL;
2263 goto fast_forward_edit;
2264 }
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002265 if (parent && repo_parse_commit(r, parent) < 0)
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002266 /* TRANSLATORS: The first %s will be a "todo" command like
2267 "revert" or "pick", the second %s a SHA1. */
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302268 return error(_("%s: cannot parse parent commit %s"),
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002269 command_to_string(command),
2270 oid_to_hex(&parent->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302271
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302272 /*
2273 * "commit" is an existing commit. We would want to apply
2274 * the difference it introduces since its first parent "prev"
2275 * on top of the current HEAD if we are cherry-pick. Or the
2276 * reverse of it if we are revert.
2277 */
2278
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002279 if (command == TODO_REVERT) {
Oswald Buddenhagen883cb1b2023-09-02 09:20:35 +02002280 const char *orig_subject;
2281
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302282 base = commit;
2283 base_label = msg.label;
2284 next = parent;
2285 next_label = msg.parent_label;
Junio C Hamano43966ab2022-05-26 23:01:39 -07002286 if (opts->commit_use_reference) {
2287 strbuf_addstr(&msgbuf,
2288 "# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
Oswald Buddenhagen883cb1b2023-09-02 09:20:35 +02002289 } else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
2290 /*
2291 * We don't touch pre-existing repeated reverts, because
2292 * theoretically these can be nested arbitrarily deeply,
2293 * thus requiring excessive complexity to deal with.
2294 */
2295 !starts_with(orig_subject, "Revert \"")) {
2296 strbuf_addstr(&msgbuf, "Reapply \"");
2297 strbuf_addstr(&msgbuf, orig_subject);
Junio C Hamano43966ab2022-05-26 23:01:39 -07002298 } else {
2299 strbuf_addstr(&msgbuf, "Revert \"");
2300 strbuf_addstr(&msgbuf, msg.subject);
2301 strbuf_addstr(&msgbuf, "\"");
2302 }
2303 strbuf_addstr(&msgbuf, "\n\nThis reverts commit ");
2304 refer_to_commit(opts, &msgbuf, commit);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302305
2306 if (commit->parents && commit->parents->next) {
2307 strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
Junio C Hamano43966ab2022-05-26 23:01:39 -07002308 refer_to_commit(opts, &msgbuf, parent);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302309 }
2310 strbuf_addstr(&msgbuf, ".\n");
2311 } else {
2312 const char *p;
2313
2314 base = parent;
2315 base_label = msg.parent_label;
2316 next = commit;
2317 next_label = msg.label;
2318
Johannes Schindelin23aa5142017-01-02 16:26:20 +01002319 /* Append the commit log message to msgbuf. */
2320 if (find_commit_subject(msg.message, &p))
2321 strbuf_addstr(&msgbuf, p);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302322
2323 if (opts->record_origin) {
Jonathan Tan44dc7382017-04-26 13:50:03 -07002324 strbuf_complete_line(&msgbuf);
Brandon Caseybab4d102013-02-12 02:17:35 -08002325 if (!has_conforming_footer(&msgbuf, NULL, 0))
Brandon Caseyb971e042013-02-12 02:17:34 -08002326 strbuf_addch(&msgbuf, '\n');
Brandon Caseycd650a42013-02-12 02:17:32 -08002327 strbuf_addstr(&msgbuf, cherry_picked_prefix);
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002328 strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302329 strbuf_addstr(&msgbuf, ")\n");
2330 }
Phillip Wood356ee462017-11-24 11:07:57 +00002331 if (!is_fixup(command))
2332 author = get_author(msg.message);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302333 }
2334
Johannes Schindelin04efc8b2017-01-02 16:28:00 +01002335 if (command == TODO_REWORD)
Phillip Wood450efe22019-08-19 02:18:21 -07002336 reword = 1;
Johannes Schindelin04efc8b2017-01-02 16:28:00 +01002337 else if (is_fixup(command)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302338 if (update_squash_messages(r, command, commit,
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002339 opts, item->flags)) {
2340 res = -1;
2341 goto leave;
2342 }
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002343 flags |= AMEND_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002344 if (!final_fixup)
2345 msg_file = rebase_path_squash_msg();
2346 else if (file_exists(rebase_path_fixup_msg())) {
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00002347 flags |= VERBATIM_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002348 msg_file = rebase_path_fixup_msg();
2349 } else {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002350 const char *dest = git_path_squash_msg(r);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002351 unlink(dest);
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002352 if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
Oswald Buddenhagen82af2c62023-09-03 17:11:32 +02002353 res = error(_("could not copy '%s' to '%s'"),
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002354 rebase_path_squash_msg(), dest);
2355 goto leave;
2356 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002357 unlink(git_path_merge_msg(r));
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002358 msg_file = dest;
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002359 flags |= EDIT_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002360 }
2361 }
2362
Phillip Wooda852ec72018-03-20 11:10:55 +00002363 if (opts->signoff && !is_fixup(command))
Phillip Woodb34eeea2017-11-24 11:07:55 +00002364 append_signoff(&msgbuf, 0, 0);
2365
Johannes Schindelin0473f282017-01-02 16:27:18 +01002366 if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
2367 res = -1;
Elijah Newren14c45862020-11-02 23:45:34 +00002368 else if (!opts->strategy ||
2369 !strcmp(opts->strategy, "recursive") ||
2370 !strcmp(opts->strategy, "ort") ||
2371 command == TODO_REVERT) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002372 res = do_recursive_merge(r, base, next, base_label, next_label,
brian m. carlson48be4c62017-05-06 22:10:36 +00002373 &head, &msgbuf, opts);
Johannes Schindelinf241ff02016-07-26 18:06:02 +02002374 if (res < 0)
Stefan Beller19517fb2018-06-01 13:01:45 -07002375 goto leave;
2376
Johannes Schindelin75871492016-10-21 14:26:05 +02002377 res |= write_message(msgbuf.buf, msgbuf.len,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002378 git_path_merge_msg(r), 0);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302379 } else {
2380 struct commit_list *common = NULL;
2381 struct commit_list *remotes = NULL;
2382
Johannes Schindelin75871492016-10-21 14:26:05 +02002383 res = write_message(msgbuf.buf, msgbuf.len,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002384 git_path_merge_msg(r), 0);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302385
2386 commit_list_insert(base, &common);
2387 commit_list_insert(next, &remotes);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002388 res |= try_merge_command(r, opts->strategy,
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002389 opts->xopts.nr, opts->xopts.v,
brian m. carlsonace976b2017-05-06 22:10:32 +00002390 common, oid_to_hex(&head), remotes);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302391 free_commit_list(common);
2392 free_commit_list(remotes);
2393 }
2394
2395 /*
2396 * If the merge was clean or if it failed due to conflict, we write
2397 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
2398 * However, if the merge did not even start, then we don't want to
2399 * write it at all.
2400 */
Phillip Wood21b11c62019-12-06 16:06:09 +00002401 if ((command == TODO_PICK || command == TODO_REWORD ||
2402 command == TODO_EDIT) && !opts->no_commit &&
2403 (res == 0 || res == 1) &&
brian m. carlsonae077772017-10-15 22:06:51 +00002404 update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
Michael Haggerty91774af2017-11-05 09:42:06 +01002405 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
Johannes Schindelindbfad032016-08-26 15:47:14 +02002406 res = -1;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002407 if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
brian m. carlsonae077772017-10-15 22:06:51 +00002408 update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
Michael Haggerty91774af2017-11-05 09:42:06 +01002409 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
Johannes Schindelindbfad032016-08-26 15:47:14 +02002410 res = -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302411
2412 if (res) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002413 error(command == TODO_REVERT
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302414 ? _("could not revert %s... %s")
2415 : _("could not apply %s... %s"),
Jeff Kingcb646ff2023-08-29 19:43:39 -04002416 short_commit_name(r, commit), msg.subject);
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002417 print_advice(r, res == 1, opts);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002418 repo_rerere(r, opts->allow_rerere_auto);
Felipe Contrerasc8d13512013-05-28 22:56:21 -05002419 goto leave;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302420 }
2421
Elijah Newrene98c4262020-02-15 21:36:25 +00002422 drop_commit = 0;
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002423 allow = allow_empty(r, opts, commit);
Felipe Contreras706728a2013-06-06 03:58:57 -05002424 if (allow < 0) {
2425 res = allow;
2426 goto leave;
Elijah Newrene98c4262020-02-15 21:36:25 +00002427 } else if (allow == 1) {
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002428 flags |= ALLOW_EMPTY;
Elijah Newrene98c4262020-02-15 21:36:25 +00002429 } else if (allow == 2) {
2430 drop_commit = 1;
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00002431 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01002432 NULL, REF_NO_DEREF);
Elijah Newren9a1b7472020-03-11 15:30:22 +00002433 unlink(git_path_merge_msg(r));
Patrick Steinhardtfd7c6ff2024-01-19 11:40:09 +01002434 refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
2435 NULL, REF_NO_DEREF);
Elijah Newrene98c4262020-02-15 21:36:25 +00002436 fprintf(stderr,
2437 _("dropping %s %s -- patch contents already upstream\n"),
2438 oid_to_hex(&commit->object.oid), msg.subject);
2439 } /* else allow == 0 and there's nothing special to do */
2440 if (!opts->no_commit && !drop_commit) {
Phillip Wood356ee462017-11-24 11:07:57 +00002441 if (author || command == TODO_REVERT || (flags & AMEND_MSG))
Phillip Wood430b75f2019-12-06 16:06:12 +00002442 res = do_commit(r, msg_file, author, opts, flags,
2443 commit? &commit->object.oid : NULL);
Phillip Wood356ee462017-11-24 11:07:57 +00002444 else
2445 res = error(_("unable to parse commit author"));
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002446 *check_todo = !!(flags & EDIT_MSG);
2447 if (!res && reword) {
Phillip Wood450efe22019-08-19 02:18:21 -07002448fast_forward_edit:
Jeff King20f4b042020-09-30 08:29:31 -04002449 res = run_git_commit(NULL, opts, EDIT_MSG |
Phillip Wood450efe22019-08-19 02:18:21 -07002450 VERIFY_MSG | AMEND_MSG |
2451 (flags & ALLOW_EMPTY));
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002452 *check_todo = 1;
2453 }
Phillip Wood356ee462017-11-24 11:07:57 +00002454 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002455
Phillip Wood450efe22019-08-19 02:18:21 -07002456
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002457 if (!res && final_fixup) {
2458 unlink(rebase_path_fixup_msg());
2459 unlink(rebase_path_squash_msg());
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002460 unlink(rebase_path_current_fixups());
2461 strbuf_reset(&opts->current_fixups);
2462 opts->current_fixup_count = 0;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002463 }
Felipe Contrerasc8d13512013-05-28 22:56:21 -05002464
2465leave:
Jeff Kingd74a4e52014-06-10 17:39:35 -04002466 free_message(commit, &msg);
Phillip Wood356ee462017-11-24 11:07:57 +00002467 free(author);
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002468 strbuf_release(&msgbuf);
Stephan Beyer1e412292016-12-07 22:51:32 +01002469 update_abort_safety_file();
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302470
2471 return res;
2472}
2473
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002474static int prepare_revs(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302475{
Martin von Zweigbergka73e22e2012-08-28 23:15:56 -07002476 /*
2477 * picking (but not reverting) ranges (but not individual revisions)
2478 * should be done in reverse
2479 */
2480 if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302481 opts->revs->reverse ^= 1;
2482
2483 if (prepare_revision_walk(opts->revs))
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002484 return error(_("revision walk setup failed"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302485
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002486 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302487}
2488
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002489static int read_and_refresh_cache(struct repository *r,
2490 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302491{
Martin Ågren14bca6c2018-02-27 22:30:09 +01002492 struct lock_file index_lock = LOCK_INIT;
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07002493 int index_fd = repo_hold_locked_index(r, &index_lock, 0);
2494 if (repo_read_index(r) < 0) {
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002495 rollback_lock_file(&index_lock);
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002496 return error(_("git %s: failed to read the index"),
Michael J Gruber629444a2022-08-18 15:13:28 +02002497 action_name(opts));
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002498 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002499 refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
Derrick Stolee5d9c9342021-09-08 11:24:00 +00002500
Martin Ågren61000812018-03-01 21:40:20 +01002501 if (index_fd >= 0) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002502 if (write_locked_index(r->index, &index_lock,
Martin Ågren61000812018-03-01 21:40:20 +01002503 COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002504 return error(_("git %s: failed to refresh the index"),
Michael J Gruber629444a2022-08-18 15:13:28 +02002505 action_name(opts));
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002506 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302507 }
Derrick Stolee5d9c9342021-09-08 11:24:00 +00002508
2509 /*
2510 * If we are resolving merges in any way other than "ort", then
2511 * expand the sparse index.
2512 */
2513 if (opts->strategy && strcmp(opts->strategy, "ort"))
2514 ensure_full_index(r->index);
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002515 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302516}
2517
Alban Gruin5d94d542018-12-29 17:03:59 +01002518void todo_list_release(struct todo_list *todo_list)
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002519{
2520 strbuf_release(&todo_list->buf);
Ævar Arnfjörð Bjarmason6a83d902017-06-15 23:15:46 +00002521 FREE_AND_NULL(todo_list->items);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002522 todo_list->nr = todo_list->alloc = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302523}
2524
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002525static struct todo_item *append_new_todo(struct todo_list *todo_list)
2526{
2527 ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);
2528 return todo_list->items + todo_list->nr++;
2529}
2530
Alban Gruin6ad656d2019-01-29 16:01:46 +01002531const char *todo_item_get_arg(struct todo_list *todo_list,
2532 struct todo_item *item)
2533{
2534 return todo_list->buf.buf + item->arg_offset;
2535}
2536
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002537static int is_command(enum todo_command command, const char **bol)
2538{
2539 const char *str = todo_command_info[command].str;
2540 const char nick = todo_command_info[command].c;
Phillip Wood7aed2c02023-02-23 20:55:00 +00002541 const char *p = *bol;
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002542
Phillip Wood7aed2c02023-02-23 20:55:00 +00002543 return (skip_prefix(p, str, &p) || (nick && *p++ == nick)) &&
2544 (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
2545 (*bol = p);
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002546}
2547
Phillip Wood16b38802023-02-20 14:19:34 +00002548static int check_label_or_ref_arg(enum todo_command command, const char *arg)
2549{
2550 switch (command) {
2551 case TODO_LABEL:
2552 /*
2553 * '#' is not a valid label as the merge command uses it to
2554 * separate merge parents from the commit subject.
2555 */
2556 if (!strcmp(arg, "#") ||
2557 check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
2558 return error(_("'%s' is not a valid label"), arg);
2559 break;
2560
2561 case TODO_UPDATE_REF:
2562 if (check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
2563 return error(_("'%s' is not a valid refname"), arg);
2564 if (check_refname_format(arg, 0))
2565 return error(_("update-ref requires a fully qualified "
2566 "refname e.g. refs/heads/%s"), arg);
2567 break;
2568
2569 default:
2570 BUG("unexpected todo_command");
2571 }
2572
2573 return 0;
2574}
2575
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002576static int parse_insn_line(struct repository *r, struct todo_item *item,
Alban Gruin6ad656d2019-01-29 16:01:46 +01002577 const char *buf, const char *bol, char *eol)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302578{
brian m. carlson1e43ed92017-05-06 22:10:09 +00002579 struct object_id commit_oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302580 char *end_of_object_name;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002581 int i, saved, status, padding;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302582
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002583 item->flags = 0;
2584
Johannes Schindelin8f8550b2016-10-21 14:25:36 +02002585 /* left-trim */
2586 bol += strspn(bol, " \t");
2587
Jeff King2ec225d2024-03-12 05:17:39 -04002588 if (bol == eol || *bol == '\r' || starts_with_mem(bol, eol - bol, comment_line_str)) {
Johannes Schindelinac191472017-01-02 16:34:39 +01002589 item->command = TODO_COMMENT;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002590 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002591 item->arg_offset = bol - buf;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002592 item->arg_len = eol - bol;
2593 return 0;
2594 }
2595
Johannes Schindelinac191472017-01-02 16:34:39 +01002596 for (i = 0; i < TODO_COMMENT; i++)
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002597 if (is_command(i, &bol)) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002598 item->command = i;
2599 break;
2600 }
Johannes Schindelinac191472017-01-02 16:34:39 +01002601 if (i >= TODO_COMMENT)
Phillip Wood7aed2c02023-02-23 20:55:00 +00002602 return error(_("invalid command '%.*s'"),
2603 (int)strcspn(bol, " \t\r\n"), bol);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302604
Johannes Schindelin66afa242017-12-23 00:55:57 +01002605 /* Eat up extra spaces/ tabs before object name */
2606 padding = strspn(bol, " \t");
2607 bol += padding;
2608
Johannes Schindelin71f82462018-10-12 06:14:26 -07002609 if (item->command == TODO_NOOP || item->command == TODO_BREAK) {
Johannes Schindelin66afa242017-12-23 00:55:57 +01002610 if (bol != eol)
2611 return error(_("%s does not accept arguments: '%s'"),
2612 command_to_string(item->command), bol);
Johannes Schindelin25c43662017-01-02 16:26:38 +01002613 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002614 item->arg_offset = bol - buf;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002615 item->arg_len = eol - bol;
2616 return 0;
2617 }
2618
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302619 if (!padding)
Johannes Schindelin66afa242017-12-23 00:55:57 +01002620 return error(_("missing arguments for %s"),
2621 command_to_string(item->command));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302622
Johannes Schindelin9055e402018-04-25 14:28:47 +02002623 if (item->command == TODO_EXEC || item->command == TODO_LABEL ||
Derrick Stoleea97d7912022-07-19 18:33:38 +00002624 item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {
Phillip Wood16b38802023-02-20 14:19:34 +00002625 int ret = 0;
2626
Liam Beguin7dcbb3c2017-12-03 17:17:15 -05002627 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002628 item->arg_offset = bol - buf;
Johannes Schindelin311af522017-01-02 16:26:47 +01002629 item->arg_len = (int)(eol - bol);
Phillip Wood16b38802023-02-20 14:19:34 +00002630 if (item->command == TODO_LABEL ||
2631 item->command == TODO_UPDATE_REF) {
2632 saved = *eol;
2633 *eol = '\0';
2634 ret = check_label_or_ref_arg(item->command, bol);
2635 *eol = saved;
2636 }
2637 return ret;
Johannes Schindelin311af522017-01-02 16:26:47 +01002638 }
2639
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302640 if (item->command == TODO_FIXUP) {
Phillip Wood666b6e12023-02-23 20:55:01 +00002641 if (skip_prefix(bol, "-C", &bol)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302642 bol += strspn(bol, " \t");
2643 item->flags |= TODO_REPLACE_FIXUP_MSG;
Phillip Wood666b6e12023-02-23 20:55:01 +00002644 } else if (skip_prefix(bol, "-c", &bol)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302645 bol += strspn(bol, " \t");
2646 item->flags |= TODO_EDIT_FIXUP_MSG;
2647 }
2648 }
2649
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002650 if (item->command == TODO_MERGE) {
2651 if (skip_prefix(bol, "-C", &bol))
2652 bol += strspn(bol, " \t");
2653 else if (skip_prefix(bol, "-c", &bol)) {
2654 bol += strspn(bol, " \t");
2655 item->flags |= TODO_EDIT_MERGE_MSG;
2656 } else {
2657 item->flags |= TODO_EDIT_MERGE_MSG;
2658 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002659 item->arg_offset = bol - buf;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002660 item->arg_len = (int)(eol - bol);
2661 return 0;
2662 }
2663 }
2664
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002665 end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302666 saved = *end_of_object_name;
2667 *end_of_object_name = '\0';
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002668 status = repo_get_oid(r, bol, &commit_oid);
Johannes Schindelind859dca2020-01-23 12:28:17 +00002669 if (status < 0)
2670 error(_("could not parse '%s'"), bol); /* return later */
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302671 *end_of_object_name = saved;
2672
Alban Gruin6ad656d2019-01-29 16:01:46 +01002673 bol = end_of_object_name + strspn(end_of_object_name, " \t");
2674 item->arg_offset = bol - buf;
2675 item->arg_len = (int)(eol - bol);
Johannes Schindelinc22f7df2016-10-21 14:25:00 +02002676
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302677 if (status < 0)
Johannes Schindelind859dca2020-01-23 12:28:17 +00002678 return status;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302679
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002680 item->commit = lookup_commit_reference(r, &commit_oid);
Johannes Schindelind859dca2020-01-23 12:28:17 +00002681 return item->commit ? 0 : -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302682}
2683
Jeff Kingc9f7b1e2023-08-29 19:44:23 -04002684int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action)
Phillip Wood4a724862019-04-16 11:18:42 +01002685{
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002686 const char *todo_file, *bol;
Phillip Wood4a724862019-04-16 11:18:42 +01002687 struct strbuf buf = STRBUF_INIT;
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002688 int ret = 0;
Phillip Wood4a724862019-04-16 11:18:42 +01002689
2690 todo_file = git_path_todo_file();
2691 if (strbuf_read_file(&buf, todo_file, 0) < 0) {
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002692 if (errno == ENOENT || errno == ENOTDIR)
Phillip Wood4a724862019-04-16 11:18:42 +01002693 return -1;
2694 else
2695 return error_errno("unable to open '%s'", todo_file);
2696 }
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002697 bol = buf.buf + strspn(buf.buf, " \t\r\n");
2698 if (is_command(TODO_PICK, &bol) && (*bol == ' ' || *bol == '\t'))
Phillip Wood4a724862019-04-16 11:18:42 +01002699 *action = REPLAY_PICK;
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002700 else if (is_command(TODO_REVERT, &bol) &&
2701 (*bol == ' ' || *bol == '\t'))
Phillip Wood4a724862019-04-16 11:18:42 +01002702 *action = REPLAY_REVERT;
2703 else
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002704 ret = -1;
Phillip Wood4a724862019-04-16 11:18:42 +01002705
Phillip Wood4a724862019-04-16 11:18:42 +01002706 strbuf_release(&buf);
2707
2708 return ret;
2709}
2710
Alban Gruin5d94d542018-12-29 17:03:59 +01002711int todo_list_parse_insn_buffer(struct repository *r, char *buf,
2712 struct todo_list *todo_list)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302713{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002714 struct todo_item *item;
2715 char *p = buf, *next_p;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002716 int i, res = 0, fixup_okay = file_exists(rebase_path_done());
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302717
Johannes Schindelin170eea92023-05-13 08:11:26 +00002718 todo_list->current = todo_list->nr = todo_list->total_nr = 0;
Alban Gruin2b715952018-12-29 17:03:58 +01002719
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002720 for (i = 1; *p; i++, p = next_p) {
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302721 char *eol = strchrnul(p, '\n');
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002722
2723 next_p = *eol ? eol + 1 /* skip LF */ : eol;
2724
Johannes Schindelin63070412016-10-21 14:24:46 +02002725 if (p != eol && eol[-1] == '\r')
2726 eol--; /* strip Carriage Return */
2727
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002728 item = append_new_todo(todo_list);
2729 item->offset_in_buf = p - todo_list->buf.buf;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002730 if (parse_insn_line(r, item, buf, p, eol)) {
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002731 res = error(_("invalid line %d: %.*s"),
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002732 i, (int)(eol - p), p);
Alban Gruin2b715952018-12-29 17:03:58 +01002733 item->command = TODO_COMMENT + 1;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002734 item->arg_offset = p - buf;
Alban Gruin2b715952018-12-29 17:03:58 +01002735 item->arg_len = (int)(eol - p);
2736 item->commit = NULL;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002737 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002738
Johannes Schindelin170eea92023-05-13 08:11:26 +00002739 if (item->command != TODO_COMMENT)
2740 todo_list->total_nr++;
2741
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002742 if (fixup_okay)
2743 ; /* do nothing */
2744 else if (is_fixup(item->command))
Alex Henrie9645a082023-07-22 15:28:25 -06002745 res = error(_("cannot '%s' without a previous commit"),
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002746 command_to_string(item->command));
2747 else if (!is_noop(item->command))
2748 fixup_okay = 1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302749 }
Johannes Schindelin52865272017-01-02 16:27:34 +01002750
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002751 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302752}
2753
Johannes Schindelin968492e2017-01-02 16:35:46 +01002754static int count_commands(struct todo_list *todo_list)
2755{
2756 int count = 0, i;
2757
2758 for (i = 0; i < todo_list->nr; i++)
2759 if (todo_list->items[i].command != TODO_COMMENT)
2760 count++;
2761
2762 return count;
2763}
2764
Johannes Schindelina01c2a52018-04-25 14:28:29 +02002765static int get_item_line_offset(struct todo_list *todo_list, int index)
2766{
2767 return index < todo_list->nr ?
2768 todo_list->items[index].offset_in_buf : todo_list->buf.len;
2769}
2770
2771static const char *get_item_line(struct todo_list *todo_list, int index)
2772{
2773 return todo_list->buf.buf + get_item_line_offset(todo_list, index);
2774}
2775
2776static int get_item_line_length(struct todo_list *todo_list, int index)
2777{
2778 return get_item_line_offset(todo_list, index + 1)
2779 - get_item_line_offset(todo_list, index);
2780}
2781
René Scharfe87805602018-02-22 20:29:25 +01002782static ssize_t strbuf_read_file_or_whine(struct strbuf *sb, const char *path)
2783{
2784 int fd;
2785 ssize_t len;
2786
2787 fd = open(path, O_RDONLY);
2788 if (fd < 0)
2789 return error_errno(_("could not open '%s'"), path);
2790 len = strbuf_read(sb, fd, 0);
2791 close(fd);
2792 if (len < 0)
2793 return error(_("could not read '%s'."), path);
2794 return len;
2795}
2796
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002797static int have_finished_the_last_pick(void)
2798{
2799 struct strbuf buf = STRBUF_INIT;
2800 const char *eol;
2801 const char *todo_path = git_path_todo_file();
2802 int ret = 0;
2803
2804 if (strbuf_read_file(&buf, todo_path, 0) < 0) {
2805 if (errno == ENOENT) {
2806 return 0;
2807 } else {
2808 error_errno("unable to open '%s'", todo_path);
2809 return 0;
2810 }
2811 }
2812 /* If there is only one line then we are done */
2813 eol = strchr(buf.buf, '\n');
2814 if (!eol || !eol[1])
2815 ret = 1;
2816
2817 strbuf_release(&buf);
2818
2819 return ret;
2820}
2821
Junio C Hamanof496b062019-07-09 15:25:44 -07002822void sequencer_post_commit_cleanup(struct repository *r, int verbose)
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002823{
2824 struct replay_opts opts = REPLAY_OPTS_INIT;
2825 int need_cleanup = 0;
2826
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00002827 if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
2828 if (!refs_delete_ref(get_main_ref_store(r), "",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01002829 "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF) &&
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00002830 verbose)
Junio C Hamanof496b062019-07-09 15:25:44 -07002831 warning(_("cancelling a cherry picking in progress"));
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002832 opts.action = REPLAY_PICK;
2833 need_cleanup = 1;
2834 }
2835
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00002836 if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
2837 if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01002838 NULL, REF_NO_DEREF) &&
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00002839 verbose)
Junio C Hamanof496b062019-07-09 15:25:44 -07002840 warning(_("cancelling a revert in progress"));
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002841 opts.action = REPLAY_REVERT;
2842 need_cleanup = 1;
2843 }
2844
Patrick Steinhardtfd7c6ff2024-01-19 11:40:09 +01002845 refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
2846 NULL, REF_NO_DEREF);
Elijah Newren52918282021-03-20 00:03:52 +00002847
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002848 if (!need_cleanup)
2849 return;
2850
2851 if (!have_finished_the_last_pick())
2852 return;
2853
2854 sequencer_remove_state(&opts);
2855}
2856
Alban Gruin3f34f2d2019-11-24 18:43:30 +01002857static void todo_list_write_total_nr(struct todo_list *todo_list)
2858{
2859 FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
2860
2861 if (f) {
2862 fprintf(f, "%d\n", todo_list->total_nr);
2863 fclose(f);
2864 }
2865}
2866
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002867static int read_populate_todo(struct repository *r,
2868 struct todo_list *todo_list,
2869 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302870{
Johannes Schindelinc0246502016-10-21 14:24:32 +02002871 const char *todo_file = get_todo_path(opts);
René Scharfe87805602018-02-22 20:29:25 +01002872 int res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302873
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002874 strbuf_reset(&todo_list->buf);
René Scharfe87805602018-02-22 20:29:25 +01002875 if (strbuf_read_file_or_whine(&todo_list->buf, todo_file) < 0)
2876 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302877
Alban Gruin5d94d542018-12-29 17:03:59 +01002878 res = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list);
Johannes Schindelin27fdbb92017-01-02 16:35:42 +01002879 if (res) {
2880 if (is_rebase_i(opts))
2881 return error(_("please fix this using "
2882 "'git rebase --edit-todo'."));
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002883 return error(_("unusable instruction sheet: '%s'"), todo_file);
Johannes Schindelin27fdbb92017-01-02 16:35:42 +01002884 }
Johannes Schindelin2eeaf1b2016-10-21 14:26:13 +02002885
Johannes Schindelin52865272017-01-02 16:27:34 +01002886 if (!todo_list->nr &&
2887 (!is_rebase_i(opts) || !file_exists(rebase_path_done())))
2888 return error(_("no commits parsed."));
2889
Johannes Schindelin2eeaf1b2016-10-21 14:26:13 +02002890 if (!is_rebase_i(opts)) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002891 enum todo_command valid =
2892 opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;
2893 int i;
2894
2895 for (i = 0; i < todo_list->nr; i++)
2896 if (valid == todo_list->items[i].command)
2897 continue;
2898 else if (valid == TODO_PICK)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002899 return error(_("cannot cherry-pick during a revert."));
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002900 else
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002901 return error(_("cannot revert during a cherry-pick."));
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002902 }
2903
Johannes Schindelin968492e2017-01-02 16:35:46 +01002904 if (is_rebase_i(opts)) {
2905 struct todo_list done = TODO_LIST_INIT;
2906
2907 if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
Alban Gruin5d94d542018-12-29 17:03:59 +01002908 !todo_list_parse_insn_buffer(r, done.buf.buf, &done))
Johannes Schindelin968492e2017-01-02 16:35:46 +01002909 todo_list->done_nr = count_commands(&done);
2910 else
2911 todo_list->done_nr = 0;
2912
2913 todo_list->total_nr = todo_list->done_nr
2914 + count_commands(todo_list);
Johannes Schindelin968492e2017-01-02 16:35:46 +01002915 todo_list_release(&done);
Johannes Schindelinef800692017-01-02 16:36:20 +01002916
Alban Gruin3f34f2d2019-11-24 18:43:30 +01002917 todo_list_write_total_nr(todo_list);
Johannes Schindelin968492e2017-01-02 16:35:46 +01002918 }
2919
Johannes Schindelin0ae42a02016-09-09 16:37:24 +02002920 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302921}
2922
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002923static int git_config_string_dup(char **dest,
2924 const char *var, const char *value)
2925{
2926 if (!value)
2927 return config_error_nonbool(var);
2928 free(*dest);
2929 *dest = xstrdup(value);
2930 return 0;
2931}
2932
Glen Chooa4e7e312023-06-28 19:26:22 +00002933static int populate_opts_cb(const char *key, const char *value,
Glen Choo8868b1e2023-06-28 19:26:27 +00002934 const struct config_context *ctx,
Glen Chooa4e7e312023-06-28 19:26:22 +00002935 void *data)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302936{
2937 struct replay_opts *opts = data;
2938 int error_flag = 1;
2939
2940 if (!value)
2941 error_flag = 0;
2942 else if (!strcmp(key, "options.no-commit"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002943 opts->no_commit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302944 else if (!strcmp(key, "options.edit"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002945 opts->edit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002946 else if (!strcmp(key, "options.allow-empty"))
2947 opts->allow_empty =
Glen Choo8868b1e2023-06-28 19:26:27 +00002948 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002949 else if (!strcmp(key, "options.allow-empty-message"))
2950 opts->allow_empty_message =
Glen Choo8868b1e2023-06-28 19:26:27 +00002951 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Brian Lylesec79d762024-03-25 18:16:54 -05002952 else if (!strcmp(key, "options.drop-redundant-commits"))
2953 opts->drop_redundant_commits =
2954 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002955 else if (!strcmp(key, "options.keep-redundant-commits"))
2956 opts->keep_redundant_commits =
Glen Choo8868b1e2023-06-28 19:26:27 +00002957 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302958 else if (!strcmp(key, "options.signoff"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002959 opts->signoff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302960 else if (!strcmp(key, "options.record-origin"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002961 opts->record_origin = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302962 else if (!strcmp(key, "options.allow-ff"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002963 opts->allow_ff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302964 else if (!strcmp(key, "options.mainline"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002965 opts->mainline = git_config_int(key, value, ctx->kvi);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302966 else if (!strcmp(key, "options.strategy"))
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002967 git_config_string_dup(&opts->strategy, key, value);
Nicolas Vigier32535532014-01-24 00:50:58 +00002968 else if (!strcmp(key, "options.gpg-sign"))
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002969 git_config_string_dup(&opts->gpg_sign, key, value);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302970 else if (!strcmp(key, "options.strategy-option")) {
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002971 strvec_push(&opts->xopts, value);
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01002972 } else if (!strcmp(key, "options.allow-rerere-auto"))
2973 opts->allow_rerere_auto =
Glen Choo8868b1e2023-06-28 19:26:27 +00002974 git_config_bool_or_int(key, value, ctx->kvi, &error_flag) ?
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01002975 RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
Phillip Wooddc42e9a2019-04-17 11:23:29 +01002976 else if (!strcmp(key, "options.default-msg-cleanup")) {
2977 opts->explicit_cleanup = 1;
2978 opts->default_msg_cleanup = get_cleanup_mode(value, 1);
2979 } else
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002980 return error(_("invalid key: %s"), key);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302981
2982 if (!error_flag)
Jean-Noël Avila1a8aea82022-01-31 22:07:47 +00002983 return error(_("invalid value for '%s': '%s'"), key, value);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302984
2985 return 0;
2986}
2987
Phillip Wood4a8bc982023-04-10 10:08:29 +01002988static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002989{
2990 int i;
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01002991 int count;
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002992 const char **argv;
Alban Gruin65850682018-08-28 14:10:40 +02002993 char *strategy_opts_string = raw_opts;
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002994
Elijah Newren00600412018-06-27 08:48:04 -07002995 if (*strategy_opts_string == ' ')
2996 strategy_opts_string++;
Alban Gruin65850682018-08-28 14:10:40 +02002997
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002998 count = split_cmdline(strategy_opts_string, &argv);
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01002999 if (count < 0)
Phillip Wood4960e5c2023-04-10 10:08:30 +01003000 BUG("could not split '%s': %s", strategy_opts_string,
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01003001 split_cmdline_strerror(count));
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003002 for (i = 0; i < count; i++) {
3003 const char *arg = argv[i];
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003004
3005 skip_prefix(arg, "--", &arg);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003006 strvec_push(&opts->xopts, arg);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003007 }
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003008 free(argv);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003009}
3010
Alban Gruin65850682018-08-28 14:10:40 +02003011static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
3012{
3013 strbuf_reset(buf);
3014 if (!read_oneliner(buf, rebase_path_strategy(), 0))
3015 return;
3016 opts->strategy = strbuf_detach(buf, NULL);
3017 if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
3018 return;
3019
3020 parse_strategy_opts(opts, buf->buf);
3021}
3022
Johannes Schindelin5adf9bd2016-10-14 15:17:16 +02003023static int read_populate_opts(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303024{
Johannes Schindelina1c75762016-10-21 14:25:12 +02003025 if (is_rebase_i(opts)) {
3026 struct strbuf buf = STRBUF_INIT;
Denton Liu65c425a2020-04-03 21:11:16 -04003027 int ret = 0;
Johannes Schindelina1c75762016-10-21 14:25:12 +02003028
Denton Liu3442c3d2020-04-07 10:27:52 -04003029 if (read_oneliner(&buf, rebase_path_gpg_sign_opt(),
3030 READ_ONELINER_SKIP_IF_EMPTY)) {
Johannes Schindelina1c75762016-10-21 14:25:12 +02003031 if (!starts_with(buf.buf, "-S"))
3032 strbuf_reset(&buf);
3033 else {
3034 free(opts->gpg_sign);
3035 opts->gpg_sign = xstrdup(buf.buf + 2);
3036 }
Phillip Wood9b6d7a62017-08-02 11:44:17 +01003037 strbuf_reset(&buf);
3038 }
3039
Denton Liu3442c3d2020-04-07 10:27:52 -04003040 if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(),
3041 READ_ONELINER_SKIP_IF_EMPTY)) {
Phillip Wood9b6d7a62017-08-02 11:44:17 +01003042 if (!strcmp(buf.buf, "--rerere-autoupdate"))
3043 opts->allow_rerere_auto = RERERE_AUTOUPDATE;
3044 else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
3045 opts->allow_rerere_auto = RERERE_NOAUTOUPDATE;
3046 strbuf_reset(&buf);
Johannes Schindelina1c75762016-10-21 14:25:12 +02003047 }
Johannes Schindelina1c75762016-10-21 14:25:12 +02003048
Johannes Schindelin556907f2017-01-02 16:26:53 +01003049 if (file_exists(rebase_path_verbose()))
3050 opts->verbose = 1;
3051
Elijah Newren899b49c2018-12-11 08:11:36 -08003052 if (file_exists(rebase_path_quiet()))
3053 opts->quiet = 1;
3054
Phillip Wooda852ec72018-03-20 11:10:55 +00003055 if (file_exists(rebase_path_signoff())) {
3056 opts->allow_ff = 0;
3057 opts->signoff = 1;
3058 }
3059
Phillip Wood7573cec2020-08-17 18:40:02 +01003060 if (file_exists(rebase_path_cdate_is_adate())) {
3061 opts->allow_ff = 0;
3062 opts->committer_date_is_author_date = 1;
3063 }
3064
Phillip Wooda3894aa2020-08-17 18:40:03 +01003065 if (file_exists(rebase_path_ignore_date())) {
3066 opts->allow_ff = 0;
3067 opts->ignore_date = 1;
3068 }
3069
Johannes Schindelind421afa2018-12-10 11:04:58 -08003070 if (file_exists(rebase_path_reschedule_failed_exec()))
3071 opts->reschedule_failed_exec = 1;
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +02003072 else if (file_exists(rebase_path_no_reschedule_failed_exec()))
3073 opts->reschedule_failed_exec = 0;
Johannes Schindelind421afa2018-12-10 11:04:58 -08003074
Elijah Newrene98c4262020-02-15 21:36:25 +00003075 if (file_exists(rebase_path_drop_redundant_commits()))
3076 opts->drop_redundant_commits = 1;
3077
3078 if (file_exists(rebase_path_keep_redundant_commits()))
3079 opts->keep_redundant_commits = 1;
3080
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003081 read_strategy_opts(opts, &buf);
Denton Liu65c425a2020-04-03 21:11:16 -04003082 strbuf_reset(&buf);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003083
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003084 if (read_oneliner(&opts->current_fixups,
Denton Liu3442c3d2020-04-07 10:27:52 -04003085 rebase_path_current_fixups(),
3086 READ_ONELINER_SKIP_IF_EMPTY)) {
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003087 const char *p = opts->current_fixups.buf;
3088 opts->current_fixup_count = 1;
3089 while ((p = strchr(p, '\n'))) {
3090 opts->current_fixup_count++;
3091 p++;
3092 }
3093 }
3094
Johannes Schindelind87d48b2018-05-04 01:01:17 +02003095 if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003096 if (repo_get_oid_committish(the_repository, buf.buf, &opts->squash_onto) < 0) {
Denton Liu65c425a2020-04-03 21:11:16 -04003097 ret = error(_("unusable squash-onto"));
3098 goto done_rebase_i;
3099 }
Johannes Schindelind87d48b2018-05-04 01:01:17 +02003100 opts->have_squash_onto = 1;
3101 }
3102
Denton Liu65c425a2020-04-03 21:11:16 -04003103done_rebase_i:
3104 strbuf_release(&buf);
3105 return ret;
Johannes Schindelina1c75762016-10-21 14:25:12 +02003106 }
Johannes Schindelinb5a67042016-10-21 14:25:04 +02003107
Jeff Kingf9327292015-08-10 05:38:57 -04003108 if (!file_exists(git_path_opts_file()))
Johannes Schindelin0d00da72016-09-09 16:37:27 +02003109 return 0;
3110 /*
3111 * The function git_parse_source(), called from git_config_from_file(),
3112 * may die() in case of a syntactically incorrect file. We do not care
3113 * about this case, though, because we wrote that file ourselves, so we
3114 * are pretty certain that it is syntactically correct.
3115 */
Johannes Schindelin5adf9bd2016-10-14 15:17:16 +02003116 if (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003117 return error(_("malformed options sheet: '%s'"),
Johannes Schindelin0d00da72016-09-09 16:37:27 +02003118 git_path_opts_file());
3119 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303120}
3121
Alban Gruin65850682018-08-28 14:10:40 +02003122static void write_strategy_opts(struct replay_opts *opts)
3123{
Alban Gruin65850682018-08-28 14:10:40 +02003124 struct strbuf buf = STRBUF_INIT;
3125
Phillip Wood4960e5c2023-04-10 10:08:30 +01003126 /*
3127 * Quote strategy options so that they can be read correctly
3128 * by split_cmdline().
3129 */
3130 quote_cmdline(&buf, opts->xopts.v);
Alban Gruin65850682018-08-28 14:10:40 +02003131 write_file(rebase_path_strategy_opts(), "%s\n", buf.buf);
3132 strbuf_release(&buf);
3133}
3134
3135int write_basic_state(struct replay_opts *opts, const char *head_name,
Phillip Wooda2bb10d2020-11-04 15:29:39 +00003136 struct commit *onto, const struct object_id *orig_head)
Alban Gruin65850682018-08-28 14:10:40 +02003137{
Alban Gruin65850682018-08-28 14:10:40 +02003138 if (head_name)
3139 write_file(rebase_path_head_name(), "%s\n", head_name);
3140 if (onto)
Phillip Wood7d3488e2019-04-17 15:30:39 +01003141 write_file(rebase_path_onto(), "%s\n",
3142 oid_to_hex(&onto->object.oid));
Alban Gruin65850682018-08-28 14:10:40 +02003143 if (orig_head)
Phillip Wooda2bb10d2020-11-04 15:29:39 +00003144 write_file(rebase_path_orig_head(), "%s\n",
3145 oid_to_hex(orig_head));
Alban Gruin65850682018-08-28 14:10:40 +02003146
Elijah Newren8a997ed2020-02-15 21:36:27 +00003147 if (opts->quiet)
3148 write_file(rebase_path_quiet(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003149 if (opts->verbose)
Carlo Marcelo Arenas Belón4af51742018-10-25 02:38:54 -07003150 write_file(rebase_path_verbose(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003151 if (opts->strategy)
3152 write_file(rebase_path_strategy(), "%s\n", opts->strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003153 if (opts->xopts.nr > 0)
Alban Gruin65850682018-08-28 14:10:40 +02003154 write_strategy_opts(opts);
3155
3156 if (opts->allow_rerere_auto == RERERE_AUTOUPDATE)
3157 write_file(rebase_path_allow_rerere_autoupdate(), "--rerere-autoupdate\n");
3158 else if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)
3159 write_file(rebase_path_allow_rerere_autoupdate(), "--no-rerere-autoupdate\n");
3160
3161 if (opts->gpg_sign)
3162 write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
3163 if (opts->signoff)
3164 write_file(rebase_path_signoff(), "--signoff\n");
Elijah Newrene98c4262020-02-15 21:36:25 +00003165 if (opts->drop_redundant_commits)
3166 write_file(rebase_path_drop_redundant_commits(), "%s", "");
3167 if (opts->keep_redundant_commits)
3168 write_file(rebase_path_keep_redundant_commits(), "%s", "");
Phillip Wood7573cec2020-08-17 18:40:02 +01003169 if (opts->committer_date_is_author_date)
3170 write_file(rebase_path_cdate_is_adate(), "%s", "");
Phillip Wooda3894aa2020-08-17 18:40:03 +01003171 if (opts->ignore_date)
3172 write_file(rebase_path_ignore_date(), "%s", "");
Johannes Schindelind421afa2018-12-10 11:04:58 -08003173 if (opts->reschedule_failed_exec)
3174 write_file(rebase_path_reschedule_failed_exec(), "%s", "");
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +02003175 else
3176 write_file(rebase_path_no_reschedule_failed_exec(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003177
3178 return 0;
3179}
3180
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003181static int walk_revs_populate_todo(struct todo_list *todo_list,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303182 struct replay_opts *opts)
3183{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003184 enum todo_command command = opts->action == REPLAY_PICK ?
3185 TODO_PICK : TODO_REVERT;
Johannes Schindelin414697a2017-01-02 16:27:15 +01003186 const char *command_string = todo_command_info[command].str;
Doan Tran Cong Danh019a9d82019-11-08 16:43:47 +07003187 const char *encoding;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303188 struct commit *commit;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303189
Johannes Schindelin34b05282016-09-09 16:37:15 +02003190 if (prepare_revs(opts))
3191 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303192
Doan Tran Cong Danh019a9d82019-11-08 16:43:47 +07003193 encoding = get_log_output_encoding();
3194
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003195 while ((commit = get_revision(opts->revs))) {
3196 struct todo_item *item = append_new_todo(todo_list);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003197 const char *commit_buffer = repo_logmsg_reencode(the_repository,
3198 commit, NULL,
3199 encoding);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003200 const char *subject;
3201 int subject_len;
3202
3203 item->command = command;
3204 item->commit = commit;
Alban Gruin6ad656d2019-01-29 16:01:46 +01003205 item->arg_offset = 0;
Johannes Schindelinc22f7df2016-10-21 14:25:00 +02003206 item->arg_len = 0;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003207 item->offset_in_buf = todo_list->buf.len;
3208 subject_len = find_commit_subject(commit_buffer, &subject);
3209 strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
Jeff Kingcb646ff2023-08-29 19:43:39 -04003210 short_commit_name(the_repository, commit),
3211 subject_len, subject);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003212 repo_unuse_commit_buffer(the_repository, commit,
3213 commit_buffer);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003214 }
Jeff King8530c732018-07-09 15:48:19 -04003215
3216 if (!todo_list->nr)
3217 return error(_("empty commit set passed"));
3218
Johannes Schindelin34b05282016-09-09 16:37:15 +02003219 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303220}
3221
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303222static int create_seq_dir(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303223{
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303224 enum replay_action action;
3225 const char *in_progress_error = NULL;
3226 const char *in_progress_advice = NULL;
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003227 unsigned int advise_skip =
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003228 refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003229 refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303230
3231 if (!sequencer_get_last_command(r, &action)) {
3232 switch (action) {
3233 case REPLAY_REVERT:
3234 in_progress_error = _("revert is already in progress");
3235 in_progress_advice =
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303236 _("try \"git revert (--continue | %s--abort | --quit)\"");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303237 break;
3238 case REPLAY_PICK:
3239 in_progress_error = _("cherry-pick is already in progress");
3240 in_progress_advice =
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303241 _("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303242 break;
3243 default:
3244 BUG("unexpected action in create_seq_dir");
3245 }
3246 }
3247 if (in_progress_error) {
3248 error("%s", in_progress_error);
Ben Boeckeled9bff02021-08-23 12:44:00 +02003249 if (advice_enabled(ADVICE_SEQUENCER_IN_USE))
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303250 advise(in_progress_advice,
3251 advise_skip ? "--skip | " : "");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303252 return -1;
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303253 }
3254 if (mkdir(git_path_seq_dir(), 0777) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003255 return error_errno(_("could not create sequencer directory '%s'"),
Johannes Schindelinf6e82b02016-09-09 16:37:44 +02003256 git_path_seq_dir());
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303257
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303258 return 0;
3259}
3260
Johannes Schindelin311fd392016-09-09 16:37:47 +02003261static int save_head(const char *head)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303262{
Oswald Buddenhagen54dbd092023-03-23 17:22:35 +01003263 return write_message(head, strlen(head), git_path_head_file(), 1);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303264}
3265
Stephan Beyer1e412292016-12-07 22:51:32 +01003266static int rollback_is_safe(void)
3267{
3268 struct strbuf sb = STRBUF_INIT;
3269 struct object_id expected_head, actual_head;
3270
3271 if (strbuf_read_file(&sb, git_path_abort_safety_file(), 0) >= 0) {
3272 strbuf_trim(&sb);
3273 if (get_oid_hex(sb.buf, &expected_head)) {
3274 strbuf_release(&sb);
3275 die(_("could not parse %s"), git_path_abort_safety_file());
3276 }
3277 strbuf_release(&sb);
3278 }
3279 else if (errno == ENOENT)
3280 oidclr(&expected_head);
3281 else
3282 die_errno(_("could not read '%s'"), git_path_abort_safety_file());
3283
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003284 if (repo_get_oid(the_repository, "HEAD", &actual_head))
Stephan Beyer1e412292016-12-07 22:51:32 +01003285 oidclr(&actual_head);
3286
Jeff King4a7e27e2018-08-28 17:22:40 -04003287 return oideq(&actual_head, &expected_head);
Stephan Beyer1e412292016-12-07 22:51:32 +01003288}
3289
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303290static int reset_merge(const struct object_id *oid)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303291{
René Scharfe0e906732022-10-30 12:51:14 +01003292 struct child_process cmd = CHILD_PROCESS_INIT;
Stephan Beyer1e412292016-12-07 22:51:32 +01003293
René Scharfe0e906732022-10-30 12:51:14 +01003294 cmd.git_cmd = 1;
3295 strvec_pushl(&cmd.args, "reset", "--merge", NULL);
Rohit Ashiwal265ab482019-07-02 14:41:27 +05303296
3297 if (!is_null_oid(oid))
René Scharfe0e906732022-10-30 12:51:14 +01003298 strvec_push(&cmd.args, oid_to_hex(oid));
Rohit Ashiwal265ab482019-07-02 14:41:27 +05303299
René Scharfe0e906732022-10-30 12:51:14 +01003300 return run_command(&cmd);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303301}
3302
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003303static int rollback_single_pick(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303304{
brian m. carlson092bbcd2017-07-13 23:49:22 +00003305 struct object_id head_oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303306
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003307 if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003308 !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303309 return error(_("no cherry-pick or revert in progress"));
brian m. carlson34c290a2017-10-15 22:06:56 +00003310 if (read_ref_full("HEAD", 0, &head_oid, NULL))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303311 return error(_("cannot resolve HEAD"));
brian m. carlson092bbcd2017-07-13 23:49:22 +00003312 if (is_null_oid(&head_oid))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303313 return error(_("cannot abort from a branch yet to be born"));
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303314 return reset_merge(&head_oid);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303315}
3316
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303317static int skip_single_pick(void)
3318{
3319 struct object_id head;
3320
3321 if (read_ref_full("HEAD", 0, &head, NULL))
3322 return error(_("cannot resolve HEAD"));
3323 return reset_merge(&head);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303324}
3325
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003326int sequencer_rollback(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303327{
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303328 FILE *f;
brian m. carlson092bbcd2017-07-13 23:49:22 +00003329 struct object_id oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303330 struct strbuf buf = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00003331 const char *p;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303332
Jeff Kingf9327292015-08-10 05:38:57 -04003333 f = fopen(git_path_head_file(), "r");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303334 if (!f && errno == ENOENT) {
3335 /*
3336 * There is no multiple-cherry-pick in progress.
3337 * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
3338 * a single-cherry-pick in progress, abort that.
3339 */
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003340 return rollback_single_pick(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303341 }
3342 if (!f)
Johannes Schindelinf7ed1952016-10-21 14:26:21 +02003343 return error_errno(_("cannot open '%s'"), git_path_head_file());
Junio C Hamano8f309ae2016-01-13 15:31:17 -08003344 if (strbuf_getline_lf(&buf, f)) {
Johannes Schindelinf7ed1952016-10-21 14:26:21 +02003345 error(_("cannot read '%s': %s"), git_path_head_file(),
Jeff Kingf9327292015-08-10 05:38:57 -04003346 ferror(f) ? strerror(errno) : _("unexpected end of file"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303347 fclose(f);
3348 goto fail;
3349 }
3350 fclose(f);
brian m. carlson092bbcd2017-07-13 23:49:22 +00003351 if (parse_oid_hex(buf.buf, &oid, &p) || *p != '\0') {
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303352 error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
Jeff Kingf9327292015-08-10 05:38:57 -04003353 git_path_head_file());
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303354 goto fail;
3355 }
brian m. carlson092bbcd2017-07-13 23:49:22 +00003356 if (is_null_oid(&oid)) {
Michael J Gruber0f974e22016-06-06 15:23:54 +02003357 error(_("cannot abort from a branch yet to be born"));
3358 goto fail;
3359 }
Stephan Beyer1e412292016-12-07 22:51:32 +01003360
3361 if (!rollback_is_safe()) {
3362 /* Do not error, just do not rollback */
3363 warning(_("You seem to have moved HEAD. "
3364 "Not rewinding, check your HEAD!"));
3365 } else
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303366 if (reset_merge(&oid))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303367 goto fail;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303368 strbuf_release(&buf);
Johannes Schindelin28635842016-10-21 14:24:55 +02003369 return sequencer_remove_state(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303370fail:
3371 strbuf_release(&buf);
3372 return -1;
3373}
3374
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303375int sequencer_skip(struct repository *r, struct replay_opts *opts)
3376{
3377 enum replay_action action = -1;
3378 sequencer_get_last_command(r, &action);
3379
3380 /*
3381 * Check whether the subcommand requested to skip the commit is actually
3382 * in progress and that it's safe to skip the commit.
3383 *
3384 * opts->action tells us which subcommand requested to skip the commit.
3385 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
3386 * action is in progress and we can skip the commit.
3387 *
3388 * Otherwise we check that the last instruction was related to the
3389 * particular subcommand we're trying to execute and barf if that's not
3390 * the case.
3391 *
3392 * Finally we check that the rollback is "safe", i.e., has the HEAD
3393 * moved? In this case, it doesn't make sense to "reset the merge" and
3394 * "skip the commit" as the user already handled this by committing. But
3395 * we'd not want to barf here, instead give advice on how to proceed. We
3396 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
3397 * it gets removed when the user commits, so if it still exists we're
3398 * sure the user can't have committed before.
3399 */
3400 switch (opts->action) {
3401 case REPLAY_REVERT:
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003402 if (!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303403 if (action != REPLAY_REVERT)
3404 return error(_("no revert in progress"));
3405 if (!rollback_is_safe())
3406 goto give_advice;
3407 }
3408 break;
3409 case REPLAY_PICK:
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003410 if (!refs_ref_exists(get_main_ref_store(r),
3411 "CHERRY_PICK_HEAD")) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303412 if (action != REPLAY_PICK)
3413 return error(_("no cherry-pick in progress"));
3414 if (!rollback_is_safe())
3415 goto give_advice;
3416 }
3417 break;
3418 default:
3419 BUG("unexpected action in sequencer_skip");
3420 }
3421
3422 if (skip_single_pick())
3423 return error(_("failed to skip the commit"));
3424 if (!is_directory(git_path_seq_dir()))
3425 return 0;
3426
3427 return sequencer_continue(r, opts);
3428
3429give_advice:
3430 error(_("there is nothing to skip"));
3431
Ben Boeckeled9bff02021-08-23 12:44:00 +02003432 if (advice_enabled(ADVICE_RESOLVE_CONFLICT)) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303433 advise(_("have you committed already?\n"
3434 "try \"git %s --continue\""),
3435 action == REPLAY_REVERT ? "revert" : "cherry-pick");
3436 }
3437 return -1;
3438}
3439
Phillip Wood203573b2023-09-06 15:22:51 +00003440static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
3441 int reschedule)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303442{
Martin Ågren14bca6c2018-02-27 22:30:09 +01003443 struct lock_file todo_lock = LOCK_INIT;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003444 const char *todo_path = get_todo_path(opts);
3445 int next = todo_list->current, offset, fd;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303446
Johannes Schindelin84583952017-01-02 16:26:28 +01003447 /*
3448 * rebase -i writes "git-rebase-todo" without the currently executing
3449 * command, appending it to "done" instead.
3450 */
Phillip Wood203573b2023-09-06 15:22:51 +00003451 if (is_rebase_i(opts) && !reschedule)
Johannes Schindelin84583952017-01-02 16:26:28 +01003452 next++;
3453
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003454 fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
Johannes Schindelin221675d2016-09-09 16:37:50 +02003455 if (fd < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003456 return error_errno(_("could not lock '%s'"), todo_path);
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003457 offset = get_item_line_offset(todo_list, next);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003458 if (write_in_full(fd, todo_list->buf.buf + offset,
3459 todo_list->buf.len - offset) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003460 return error_errno(_("could not write to '%s'"), todo_path);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003461 if (commit_lock_file(&todo_lock) < 0)
Martin Ågren350292a2018-02-28 20:07:58 +01003462 return error(_("failed to finalize '%s'"), todo_path);
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003463
Phillip Wood203573b2023-09-06 15:22:51 +00003464 if (is_rebase_i(opts) && !reschedule && next > 0) {
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003465 const char *done = rebase_path_done();
3466 int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
3467 int ret = 0;
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003468
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003469 if (fd < 0)
3470 return 0;
3471 if (write_in_full(fd, get_item_line(todo_list, next - 1),
3472 get_item_line_length(todo_list, next - 1))
3473 < 0)
3474 ret = error_errno(_("could not write to '%s'"), done);
3475 if (close(fd) < 0)
3476 ret = error_errno(_("failed to finalize '%s'"), done);
3477 return ret;
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003478 }
Johannes Schindelin221675d2016-09-09 16:37:50 +02003479 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303480}
3481
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003482static int save_opts(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303483{
Jeff Kingf9327292015-08-10 05:38:57 -04003484 const char *opts_file = git_path_opts_file();
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003485 int res = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303486
3487 if (opts->no_commit)
Phillip Woodf59199d2019-03-13 18:26:13 +00003488 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003489 "options.no-commit", NULL, "true");
Elijah Newren39edfd52021-03-31 06:52:20 +00003490 if (opts->edit >= 0)
Ralph Seichter42d5c032024-03-12 21:47:00 +00003491 res |= git_config_set_in_file_gently(opts_file, "options.edit", NULL,
Elijah Newren39edfd52021-03-31 06:52:20 +00003492 opts->edit ? "true" : "false");
Phillip Wood6860ce52019-03-13 18:26:15 +00003493 if (opts->allow_empty)
3494 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003495 "options.allow-empty", NULL, "true");
Phillip Wood6860ce52019-03-13 18:26:15 +00003496 if (opts->allow_empty_message)
3497 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003498 "options.allow-empty-message", NULL, "true");
Brian Lylesec79d762024-03-25 18:16:54 -05003499 if (opts->drop_redundant_commits)
3500 res |= git_config_set_in_file_gently(opts_file,
Junio C Hamano32565842024-04-05 10:49:49 -07003501 "options.drop-redundant-commits", NULL, "true");
Phillip Wood6860ce52019-03-13 18:26:15 +00003502 if (opts->keep_redundant_commits)
3503 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003504 "options.keep-redundant-commits", NULL, "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303505 if (opts->signoff)
Phillip Woodf59199d2019-03-13 18:26:13 +00003506 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003507 "options.signoff", NULL, "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303508 if (opts->record_origin)
Phillip Woodf59199d2019-03-13 18:26:13 +00003509 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003510 "options.record-origin", NULL, "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303511 if (opts->allow_ff)
Phillip Woodf59199d2019-03-13 18:26:13 +00003512 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003513 "options.allow-ff", NULL, "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303514 if (opts->mainline) {
3515 struct strbuf buf = STRBUF_INIT;
3516 strbuf_addf(&buf, "%d", opts->mainline);
Phillip Woodf59199d2019-03-13 18:26:13 +00003517 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003518 "options.mainline", NULL, buf.buf);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303519 strbuf_release(&buf);
3520 }
3521 if (opts->strategy)
Phillip Woodf59199d2019-03-13 18:26:13 +00003522 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003523 "options.strategy", NULL, opts->strategy);
Nicolas Vigier32535532014-01-24 00:50:58 +00003524 if (opts->gpg_sign)
Phillip Woodf59199d2019-03-13 18:26:13 +00003525 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003526 "options.gpg-sign", NULL, opts->gpg_sign);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003527 for (size_t i = 0; i < opts->xopts.nr; i++)
3528 res |= git_config_set_multivar_in_file_gently(opts_file,
3529 "options.strategy-option",
Ralph Seichter42d5c032024-03-12 21:47:00 +00003530 opts->xopts.v[i], "^$", NULL, 0);
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01003531 if (opts->allow_rerere_auto)
Phillip Woodf59199d2019-03-13 18:26:13 +00003532 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003533 "options.allow-rerere-auto", NULL,
Phillip Woodf59199d2019-03-13 18:26:13 +00003534 opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
3535 "true" : "false");
Phillip Wooddc42e9a2019-04-17 11:23:29 +01003536
3537 if (opts->explicit_cleanup)
3538 res |= git_config_set_in_file_gently(opts_file,
Ralph Seichter42d5c032024-03-12 21:47:00 +00003539 "options.default-msg-cleanup", NULL,
Phillip Wooddc42e9a2019-04-17 11:23:29 +01003540 describe_cleanup_mode(opts->default_msg_cleanup));
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003541 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303542}
3543
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003544static int make_patch(struct repository *r,
3545 struct commit *commit,
3546 struct replay_opts *opts)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003547{
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003548 struct rev_info log_tree_opt;
Junio C Hamano0512eab2020-09-24 22:49:12 -07003549 const char *subject;
3550 char hex[GIT_MAX_HEXSZ + 1];
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003551 int res = 0;
3552
Phillip Wood206a78d2023-09-06 15:22:46 +00003553 if (!is_rebase_i(opts))
3554 BUG("make_patch should only be called when rebasing");
3555
Junio C Hamano0512eab2020-09-24 22:49:12 -07003556 oid_to_hex_r(hex, &commit->object.oid);
3557 if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003558 return -1;
Phillip Wood430b75f2019-12-06 16:06:12 +00003559 res |= write_rebase_head(&commit->object.oid);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003560
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003561 memset(&log_tree_opt, 0, sizeof(log_tree_opt));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003562 repo_init_revisions(r, &log_tree_opt, NULL);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003563 log_tree_opt.abbrev = 0;
3564 log_tree_opt.diff = 1;
3565 log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
3566 log_tree_opt.disable_stdin = 1;
3567 log_tree_opt.no_commit_id = 1;
Phillip Wood206a78d2023-09-06 15:22:46 +00003568 log_tree_opt.diffopt.file = fopen(rebase_path_patch(), "w");
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003569 log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
3570 if (!log_tree_opt.diffopt.file)
Phillip Wood206a78d2023-09-06 15:22:46 +00003571 res |= error_errno(_("could not open '%s'"),
3572 rebase_path_patch());
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003573 else {
3574 res |= log_tree_commit(&log_tree_opt, commit);
3575 fclose(log_tree_opt.diffopt.file);
3576 }
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003577
Phillip Wood9f678992023-09-06 15:22:47 +00003578 if (!file_exists(rebase_path_message())) {
Doan Tran Cong Danh52f52e52019-11-11 13:03:41 +07003579 const char *encoding = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003580 const char *commit_buffer = repo_logmsg_reencode(r,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003581 commit, NULL,
3582 encoding);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003583 find_commit_subject(commit_buffer, &subject);
Phillip Wood9f678992023-09-06 15:22:47 +00003584 res |= write_message(subject, strlen(subject), rebase_path_message(), 1);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003585 repo_unuse_commit_buffer(r, commit,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003586 commit_buffer);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003587 }
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02003588 release_revisions(&log_tree_opt);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003589
3590 return res;
3591}
3592
3593static int intend_to_amend(void)
3594{
brian m. carlson092bbcd2017-07-13 23:49:22 +00003595 struct object_id head;
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003596 char *p;
3597
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003598 if (repo_get_oid(the_repository, "HEAD", &head))
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003599 return error(_("cannot read HEAD"));
3600
brian m. carlson092bbcd2017-07-13 23:49:22 +00003601 p = oid_to_hex(&head);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003602 return write_message(p, strlen(p), rebase_path_amend(), 1);
3603}
3604
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003605static int error_with_patch(struct repository *r,
3606 struct commit *commit,
3607 const char *subject, int subject_len,
3608 struct replay_opts *opts,
3609 int exit_code, int to_amend)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003610{
Phillip Woodbc9238b2018-08-15 10:39:35 +01003611 if (commit) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003612 if (make_patch(r, commit, opts))
Phillip Woodbc9238b2018-08-15 10:39:35 +01003613 return -1;
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003614 } else if (copy_file(rebase_path_message(),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003615 git_path_merge_msg(r), 0666))
Phillip Woodbc9238b2018-08-15 10:39:35 +01003616 return error(_("unable to copy '%s' to '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003617 git_path_merge_msg(r), rebase_path_message());
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003618
3619 if (to_amend) {
3620 if (intend_to_amend())
3621 return -1;
3622
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02003623 fprintf(stderr,
3624 _("You can amend the commit now, with\n"
3625 "\n"
3626 " git commit --amend %s\n"
3627 "\n"
3628 "Once you are satisfied with your changes, run\n"
3629 "\n"
3630 " git rebase --continue\n"),
3631 gpg_sign_opt_quoted(opts));
Phillip Woodbc9238b2018-08-15 10:39:35 +01003632 } else if (exit_code) {
3633 if (commit)
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003634 fprintf_ln(stderr, _("Could not apply %s... %.*s"),
Jeff Kingcb646ff2023-08-29 19:43:39 -04003635 short_commit_name(r, commit), subject_len, subject);
Phillip Woodbc9238b2018-08-15 10:39:35 +01003636 else
3637 /*
3638 * We don't have the hash of the parent so
3639 * just print the line from the todo file.
3640 */
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003641 fprintf_ln(stderr, _("Could not merge %.*s"),
3642 subject_len, subject);
Phillip Woodbc9238b2018-08-15 10:39:35 +01003643 }
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003644
3645 return exit_code;
3646}
3647
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003648static int error_failed_squash(struct repository *r,
3649 struct commit *commit,
3650 struct replay_opts *opts,
3651 int subject_len,
3652 const char *subject)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003653{
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003654 if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
3655 return error(_("could not copy '%s' to '%s'"),
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003656 rebase_path_squash_msg(), rebase_path_message());
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003657 unlink(git_path_merge_msg(r));
3658 if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003659 return error(_("could not copy '%s' to '%s'"),
Stefan Beller102de882018-05-17 15:51:51 -07003660 rebase_path_message(),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003661 git_path_merge_msg(r));
3662 return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003663}
3664
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003665static int do_exec(struct repository *r, const char *command_line)
Johannes Schindelin311af522017-01-02 16:26:47 +01003666{
René Scharfeddbb47f2022-10-30 12:55:06 +01003667 struct child_process cmd = CHILD_PROCESS_INIT;
Johannes Schindelin311af522017-01-02 16:26:47 +01003668 int dirty, status;
3669
Alban Gruin4d55d632020-03-28 14:05:15 +01003670 fprintf(stderr, _("Executing: %s\n"), command_line);
René Scharfeddbb47f2022-10-30 12:55:06 +01003671 cmd.use_shell = 1;
3672 strvec_push(&cmd.args, command_line);
Vegard Nossume4301f72024-02-02 10:18:50 +01003673 strvec_push(&cmd.env, "GIT_CHERRY_PICK_HELP");
René Scharfeddbb47f2022-10-30 12:55:06 +01003674 status = run_command(&cmd);
Johannes Schindelin311af522017-01-02 16:26:47 +01003675
3676 /* force re-reading of the cache */
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01003677 discard_index(r->index);
3678 if (repo_read_index(r) < 0)
Johannes Schindelin311af522017-01-02 16:26:47 +01003679 return error(_("could not read index"));
3680
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003681 dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1);
Johannes Schindelin311af522017-01-02 16:26:47 +01003682
3683 if (status) {
3684 warning(_("execution failed: %s\n%s"
3685 "You can fix the problem, and then run\n"
3686 "\n"
3687 " git rebase --continue\n"
3688 "\n"),
3689 command_line,
Oswald Buddenhagend45cbe32023-04-28 14:56:48 +02003690 dirty ? _("and made changes to the index and/or the "
Oswald Buddenhagenb734fe42023-04-28 14:56:49 +02003691 "working tree.\n") : "");
Johannes Schindelin311af522017-01-02 16:26:47 +01003692 if (status == 127)
3693 /* command not found */
3694 status = 1;
3695 } else if (dirty) {
3696 warning(_("execution succeeded: %s\nbut "
Oswald Buddenhagenb734fe42023-04-28 14:56:49 +02003697 "left changes to the index and/or the working tree.\n"
Johannes Schindelin311af522017-01-02 16:26:47 +01003698 "Commit or stash your changes, and then run\n"
3699 "\n"
3700 " git rebase --continue\n"
3701 "\n"), command_line);
3702 status = 1;
3703 }
3704
3705 return status;
3706}
3707
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +02003708__attribute__((format (printf, 2, 3)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02003709static int safe_append(const char *filename, const char *fmt, ...)
3710{
3711 va_list ap;
3712 struct lock_file lock = LOCK_INIT;
3713 int fd = hold_lock_file_for_update(&lock, filename,
3714 LOCK_REPORT_ON_ERROR);
3715 struct strbuf buf = STRBUF_INIT;
3716
3717 if (fd < 0)
3718 return -1;
3719
3720 if (strbuf_read_file(&buf, filename, 0) < 0 && errno != ENOENT) {
3721 error_errno(_("could not read '%s'"), filename);
3722 rollback_lock_file(&lock);
3723 return -1;
3724 }
3725 strbuf_complete(&buf, '\n');
3726 va_start(ap, fmt);
3727 strbuf_vaddf(&buf, fmt, ap);
3728 va_end(ap);
3729
3730 if (write_in_full(fd, buf.buf, buf.len) < 0) {
3731 error_errno(_("could not write to '%s'"), filename);
3732 strbuf_release(&buf);
3733 rollback_lock_file(&lock);
3734 return -1;
3735 }
3736 if (commit_lock_file(&lock) < 0) {
3737 strbuf_release(&buf);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003738 return error(_("failed to finalize '%s'"), filename);
3739 }
3740
3741 strbuf_release(&buf);
3742 return 0;
3743}
3744
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003745static int do_label(struct repository *r, const char *name, int len)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003746{
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003747 struct ref_store *refs = get_main_ref_store(r);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003748 struct ref_transaction *transaction;
3749 struct strbuf ref_name = STRBUF_INIT, err = STRBUF_INIT;
3750 struct strbuf msg = STRBUF_INIT;
3751 int ret = 0;
3752 struct object_id head_oid;
3753
3754 if (len == 1 && *name == '#')
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02003755 return error(_("illegal label name: '%.*s'"), len, name);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003756
3757 strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
Elijah Newrenc2417d32020-02-15 21:36:36 +00003758 strbuf_addf(&msg, "rebase (label) '%.*s'", len, name);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003759
Junio C Hamanoc6da34a2022-04-13 15:51:33 -07003760 transaction = ref_store_transaction_begin(refs, &err);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003761 if (!transaction) {
3762 error("%s", err.buf);
3763 ret = -1;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003764 } else if (repo_get_oid(r, "HEAD", &head_oid)) {
Johannes Schindelin9055e402018-04-25 14:28:47 +02003765 error(_("could not read HEAD"));
3766 ret = -1;
3767 } else if (ref_transaction_update(transaction, ref_name.buf, &head_oid,
3768 NULL, 0, msg.buf, &err) < 0 ||
3769 ref_transaction_commit(transaction, &err)) {
3770 error("%s", err.buf);
3771 ret = -1;
3772 }
3773 ref_transaction_free(transaction);
3774 strbuf_release(&err);
3775 strbuf_release(&msg);
3776
3777 if (!ret)
3778 ret = safe_append(rebase_path_refs_to_delete(),
3779 "%s\n", ref_name.buf);
3780 strbuf_release(&ref_name);
3781
3782 return ret;
3783}
3784
Phillip Woodd188a602022-11-09 14:21:57 +00003785static const char *sequencer_reflog_action(struct replay_opts *opts)
3786{
3787 if (!opts->reflog_action) {
3788 opts->reflog_action = getenv(GIT_REFLOG_ACTION);
3789 opts->reflog_action =
3790 xstrdup(opts->reflog_action ? opts->reflog_action
3791 : action_name(opts));
3792 }
3793
3794 return opts->reflog_action;
3795}
3796
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +02003797__attribute__((format (printf, 3, 4)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02003798static const char *reflog_message(struct replay_opts *opts,
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003799 const char *sub_action, const char *fmt, ...)
3800{
3801 va_list ap;
3802 static struct strbuf buf = STRBUF_INIT;
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003803
3804 va_start(ap, fmt);
3805 strbuf_reset(&buf);
Phillip Woodd188a602022-11-09 14:21:57 +00003806 strbuf_addstr(&buf, sequencer_reflog_action(opts));
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003807 if (sub_action)
3808 strbuf_addf(&buf, " (%s)", sub_action);
3809 if (fmt) {
3810 strbuf_addstr(&buf, ": ");
3811 strbuf_vaddf(&buf, fmt, ap);
3812 }
3813 va_end(ap);
3814
3815 return buf.buf;
3816}
Johannes Schindelin9055e402018-04-25 14:28:47 +02003817
Phillip Wood688d82f2022-11-10 16:43:41 +00003818static struct commit *lookup_label(struct repository *r, const char *label,
3819 int len, struct strbuf *buf)
Phillip Wood82766b22022-11-10 16:43:40 +00003820{
3821 struct commit *commit;
Phillip Wood688d82f2022-11-10 16:43:41 +00003822 struct object_id oid;
Phillip Wood82766b22022-11-10 16:43:40 +00003823
3824 strbuf_reset(buf);
3825 strbuf_addf(buf, "refs/rewritten/%.*s", len, label);
Phillip Wood688d82f2022-11-10 16:43:41 +00003826 if (!read_ref(buf->buf, &oid)) {
3827 commit = lookup_commit_object(r, &oid);
3828 } else {
Phillip Wood82766b22022-11-10 16:43:40 +00003829 /* fall back to non-rewritten ref or commit */
3830 strbuf_splice(buf, 0, strlen("refs/rewritten/"), "", 0);
3831 commit = lookup_commit_reference_by_name(buf->buf);
3832 }
3833
3834 if (!commit)
3835 error(_("could not resolve '%s'"), buf->buf);
3836
3837 return commit;
3838}
3839
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003840static int do_reset(struct repository *r,
3841 const char *name, int len,
3842 struct replay_opts *opts)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003843{
3844 struct strbuf ref_name = STRBUF_INIT;
3845 struct object_id oid;
3846 struct lock_file lock = LOCK_INIT;
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003847 struct tree_desc desc = { 0 };
Johannes Schindelin9055e402018-04-25 14:28:47 +02003848 struct tree *tree;
Ævar Arnfjörð Bjarmason6e658542021-10-13 15:23:55 +02003849 struct unpack_trees_options unpack_tree_opts = { 0 };
Martin Ågren71571cd2018-10-30 09:09:37 +01003850 int ret = 0;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003851
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07003852 if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003853 return -1;
3854
Johannes Schindelinebddf392018-05-04 01:01:23 +02003855 if (len == 10 && !strncmp("[new root]", name, len)) {
3856 if (!opts->have_squash_onto) {
3857 const char *hex;
3858 if (commit_tree("", 0, the_hash_algo->empty_tree,
3859 NULL, &opts->squash_onto,
3860 NULL, NULL))
3861 return error(_("writing fake root commit"));
3862 opts->have_squash_onto = 1;
3863 hex = oid_to_hex(&opts->squash_onto);
3864 if (write_message(hex, strlen(hex),
3865 rebase_path_squash_onto(), 0))
3866 return error(_("writing squash-onto"));
3867 }
3868 oidcpy(&oid, &opts->squash_onto);
3869 } else {
Martin Ågren71571cd2018-10-30 09:09:37 +01003870 int i;
Phillip Wood82766b22022-11-10 16:43:40 +00003871 struct commit *commit;
Martin Ågren71571cd2018-10-30 09:09:37 +01003872
Johannes Schindelinebddf392018-05-04 01:01:23 +02003873 /* Determine the length of the label */
3874 for (i = 0; i < len; i++)
3875 if (isspace(name[i]))
Martin Ågren71571cd2018-10-30 09:09:37 +01003876 break;
3877 len = i;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003878
Phillip Wood688d82f2022-11-10 16:43:41 +00003879 commit = lookup_label(r, name, len, &ref_name);
Phillip Wood82766b22022-11-10 16:43:40 +00003880 if (!commit) {
3881 ret = -1;
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003882 goto cleanup;
Johannes Schindelinebddf392018-05-04 01:01:23 +02003883 }
Phillip Wood82766b22022-11-10 16:43:40 +00003884 oid = commit->object.oid;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003885 }
3886
Johannes Schindelin9055e402018-04-25 14:28:47 +02003887 setup_unpack_trees_porcelain(&unpack_tree_opts, "reset");
3888 unpack_tree_opts.head_idx = 1;
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003889 unpack_tree_opts.src_index = r->index;
3890 unpack_tree_opts.dst_index = r->index;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003891 unpack_tree_opts.fn = oneway_merge;
3892 unpack_tree_opts.merge = 1;
3893 unpack_tree_opts.update = 1;
Elijah Newren1b5f3732021-09-27 16:33:43 +00003894 unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
Victoria Dye652bd022022-11-10 19:06:05 +00003895 unpack_tree_opts.skip_cache_tree_update = 1;
brian m. carlson3f267852020-03-16 18:05:06 +00003896 init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003897
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07003898 if (repo_read_index_unmerged(r)) {
Michael J Gruber1c8dfc32022-08-18 15:13:27 +02003899 ret = error_resolve_conflict(action_name(opts));
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003900 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003901 }
3902
Nguyễn Thái Ngọc Duy5e575802019-06-27 16:28:48 +07003903 if (!fill_tree_descriptor(r, &desc, &oid)) {
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003904 ret = error(_("failed to find tree of %s"), oid_to_hex(&oid));
3905 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003906 }
3907
3908 if (unpack_trees(1, &desc, &unpack_tree_opts)) {
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003909 ret = -1;
3910 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003911 }
3912
3913 tree = parse_tree_indirect(&oid);
Johannes Schindelinaa9f6182024-02-23 08:34:23 +00003914 if (!tree)
3915 return error(_("unable to read tree (%s)"), oid_to_hex(&oid));
Nguyễn Thái Ngọc Duyc207e9e2018-11-10 06:49:02 +01003916 prime_cache_tree(r, r->index, tree);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003917
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003918 if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003919 ret = error(_("could not write index"));
Johannes Schindelin9055e402018-04-25 14:28:47 +02003920
3921 if (!ret)
3922 ret = update_ref(reflog_message(opts, "reset", "'%.*s'",
3923 len, name), "HEAD", &oid,
3924 NULL, 0, UPDATE_REFS_MSG_ON_ERR);
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003925cleanup:
3926 free((void *)desc.buffer);
3927 if (ret < 0)
3928 rollback_lock_file(&lock);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003929 strbuf_release(&ref_name);
Ævar Arnfjörð Bjarmason6e658542021-10-13 15:23:55 +02003930 clear_unpack_trees_porcelain(&unpack_tree_opts);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003931 return ret;
3932}
3933
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003934static int do_merge(struct repository *r,
3935 struct commit *commit,
3936 const char *arg, int arg_len,
Phillip Wood2be6b6f2021-08-20 15:40:35 +00003937 int flags, int *check_todo, struct replay_opts *opts)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003938{
Phillip Wood2be6b6f2021-08-20 15:40:35 +00003939 int run_commit_flags = 0;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003940 struct strbuf ref_name = STRBUF_INIT;
3941 struct commit *head_commit, *merge_commit, *i;
Johannes Schindelin76e2a092024-02-28 09:44:14 +00003942 struct commit_list *bases = NULL, *j;
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003943 struct commit_list *to_merge = NULL, **tail = &to_merge;
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003944 const char *strategy = !opts->xopts.nr &&
Elijah Newren14c45862020-11-02 23:45:34 +00003945 (!opts->strategy ||
3946 !strcmp(opts->strategy, "recursive") ||
3947 !strcmp(opts->strategy, "ort")) ?
Johannes Schindeline145d992019-07-31 08:18:47 -07003948 NULL : opts->strategy;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003949 struct merge_options o;
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003950 int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003951 static struct lock_file lock;
3952 const char *p;
3953
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07003954 if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003955 ret = -1;
3956 goto leave_merge;
3957 }
3958
3959 head_commit = lookup_commit_reference_by_name("HEAD");
3960 if (!head_commit) {
3961 ret = error(_("cannot merge without a current revision"));
3962 goto leave_merge;
3963 }
3964
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003965 /*
3966 * For octopus merges, the arg starts with the list of revisions to be
3967 * merged. The list is optionally followed by '#' and the oneline.
3968 */
3969 merge_arg_len = oneline_offset = arg_len;
3970 for (p = arg; p - arg < arg_len; p += strspn(p, " \t\n")) {
3971 if (!*p)
3972 break;
3973 if (*p == '#' && (!p[1] || isspace(p[1]))) {
3974 p += 1 + strspn(p + 1, " \t\n");
3975 oneline_offset = p - arg;
3976 break;
3977 }
3978 k = strcspn(p, " \t\n");
3979 if (!k)
3980 continue;
Phillip Wood688d82f2022-11-10 16:43:41 +00003981 merge_commit = lookup_label(r, p, k, &ref_name);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003982 if (!merge_commit) {
3983 ret = error(_("unable to parse '%.*s'"), k, p);
3984 goto leave_merge;
3985 }
3986 tail = &commit_list_insert(merge_commit, tail)->next;
3987 p += k;
3988 merge_arg_len = p - arg;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003989 }
3990
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003991 if (!to_merge) {
3992 ret = error(_("nothing to merge: '%.*s'"), arg_len, arg);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003993 goto leave_merge;
3994 }
3995
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02003996 if (opts->have_squash_onto &&
Jeff King4a7e27e2018-08-28 17:22:40 -04003997 oideq(&head_commit->object.oid, &opts->squash_onto)) {
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02003998 /*
3999 * When the user tells us to "merge" something into a
4000 * "[new root]", let's simply fast-forward to the merge head.
4001 */
4002 rollback_lock_file(&lock);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004003 if (to_merge->next)
4004 ret = error(_("octopus merge cannot be executed on "
4005 "top of a [new root]"));
4006 else
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004007 ret = fast_forward_to(r, &to_merge->item->object.oid,
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004008 &head_commit->object.oid, 0,
4009 opts);
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02004010 goto leave_merge;
4011 }
4012
Phillip Woodbaf8ec82021-08-20 15:40:37 +00004013 /*
4014 * If HEAD is not identical to the first parent of the original merge
4015 * commit, we cannot fast-forward.
4016 */
4017 can_fast_forward = opts->allow_ff && commit && commit->parents &&
4018 oideq(&commit->parents->item->object.oid,
4019 &head_commit->object.oid);
4020
4021 /*
4022 * If any merge head is different from the original one, we cannot
4023 * fast-forward.
4024 */
4025 if (can_fast_forward) {
4026 struct commit_list *p = commit->parents->next;
4027
4028 for (j = to_merge; j && p; j = j->next, p = p->next)
4029 if (!oideq(&j->item->object.oid,
4030 &p->item->object.oid)) {
4031 can_fast_forward = 0;
4032 break;
4033 }
4034 /*
4035 * If the number of merge heads differs from the original merge
4036 * commit, we cannot fast-forward.
4037 */
4038 if (j || p)
4039 can_fast_forward = 0;
4040 }
4041
4042 if (can_fast_forward) {
4043 rollback_lock_file(&lock);
4044 ret = fast_forward_to(r, &commit->object.oid,
4045 &head_commit->object.oid, 0, opts);
4046 if (flags & TODO_EDIT_MERGE_MSG)
4047 goto fast_forward_edit;
4048
4049 goto leave_merge;
4050 }
4051
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004052 if (commit) {
Doan Tran Cong Danh5772b0c2019-11-11 13:03:40 +07004053 const char *encoding = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004054 const char *message = repo_logmsg_reencode(r, commit, NULL,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02004055 encoding);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004056 const char *body;
4057 int len;
4058
4059 if (!message) {
4060 ret = error(_("could not get commit message of '%s'"),
4061 oid_to_hex(&commit->object.oid));
4062 goto leave_merge;
4063 }
4064 write_author_script(message);
4065 find_commit_subject(message, &body);
4066 len = strlen(body);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004067 ret = write_message(body, len, git_path_merge_msg(r), 0);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004068 repo_unuse_commit_buffer(r, commit, message);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004069 if (ret) {
4070 error_errno(_("could not write '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004071 git_path_merge_msg(r));
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004072 goto leave_merge;
4073 }
4074 } else {
4075 struct strbuf buf = STRBUF_INIT;
4076 int len;
4077
4078 strbuf_addf(&buf, "author %s", git_author_info(0));
4079 write_author_script(buf.buf);
4080 strbuf_reset(&buf);
4081
4082 if (oneline_offset < arg_len) {
4083 p = arg + oneline_offset;
4084 len = arg_len - oneline_offset;
4085 } else {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004086 strbuf_addf(&buf, "Merge %s '%.*s'",
4087 to_merge->next ? "branches" : "branch",
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004088 merge_arg_len, arg);
4089 p = buf.buf;
4090 len = buf.len;
4091 }
4092
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004093 ret = write_message(p, len, git_path_merge_msg(r), 0);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004094 strbuf_release(&buf);
4095 if (ret) {
4096 error_errno(_("could not write '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004097 git_path_merge_msg(r));
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004098 goto leave_merge;
4099 }
4100 }
4101
Johannes Schindeline145d992019-07-31 08:18:47 -07004102 if (strategy || to_merge->next) {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004103 /* Octopus merge */
4104 struct child_process cmd = CHILD_PROCESS_INIT;
4105
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004106 if (read_env_script(&cmd.env)) {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004107 const char *gpg_opt = gpg_sign_opt_quoted(opts);
4108
4109 ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
4110 goto leave_merge;
4111 }
4112
Phillip Wood7573cec2020-08-17 18:40:02 +01004113 if (opts->committer_date_is_author_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004114 strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
Junio C Hamano9c31b192020-09-03 12:37:01 -07004115 opts->ignore_date ?
4116 "" :
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +02004117 author_date_from_env(&cmd.env));
Phillip Wooda3894aa2020-08-17 18:40:03 +01004118 if (opts->ignore_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004119 strvec_push(&cmd.env, "GIT_AUTHOR_DATE=");
Phillip Wood7573cec2020-08-17 18:40:02 +01004120
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004121 cmd.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004122 strvec_push(&cmd.args, "merge");
4123 strvec_push(&cmd.args, "-s");
Johannes Schindeline145d992019-07-31 08:18:47 -07004124 if (!strategy)
Jeff Kingc972bf42020-07-28 16:25:12 -04004125 strvec_push(&cmd.args, "octopus");
Johannes Schindeline145d992019-07-31 08:18:47 -07004126 else {
Jeff Kingc972bf42020-07-28 16:25:12 -04004127 strvec_push(&cmd.args, strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01004128 for (k = 0; k < opts->xopts.nr; k++)
Jeff Kingc972bf42020-07-28 16:25:12 -04004129 strvec_pushf(&cmd.args,
Phillip Woodfb60b9f2023-04-10 10:08:28 +01004130 "-X%s", opts->xopts.v[k]);
Johannes Schindeline145d992019-07-31 08:18:47 -07004131 }
Phillip Woodf2563c92021-08-20 15:40:38 +00004132 if (!(flags & TODO_EDIT_MERGE_MSG))
4133 strvec_push(&cmd.args, "--no-edit");
4134 else
4135 strvec_push(&cmd.args, "--edit");
Jeff Kingc972bf42020-07-28 16:25:12 -04004136 strvec_push(&cmd.args, "--no-ff");
4137 strvec_push(&cmd.args, "--no-log");
4138 strvec_push(&cmd.args, "--no-stat");
4139 strvec_push(&cmd.args, "-F");
4140 strvec_push(&cmd.args, git_path_merge_msg(r));
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004141 if (opts->gpg_sign)
Samuel Čavojae03c972020-10-18 01:15:55 +02004142 strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
Samuel Čavoj19dad042020-10-18 01:15:56 +02004143 else
4144 strvec_push(&cmd.args, "--no-gpg-sign");
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004145
4146 /* Add the tips to be merged */
4147 for (j = to_merge; j; j = j->next)
Jeff Kingc972bf42020-07-28 16:25:12 -04004148 strvec_push(&cmd.args,
Jeff Kingf6d89422020-07-28 16:26:31 -04004149 oid_to_hex(&j->item->object.oid));
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004150
4151 strbuf_release(&ref_name);
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00004152 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01004153 NULL, REF_NO_DEREF);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004154 rollback_lock_file(&lock);
4155
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004156 ret = run_command(&cmd);
4157
4158 /* force re-reading of the cache */
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01004159 if (!ret) {
4160 discard_index(r->index);
4161 if (repo_read_index(r) < 0)
4162 ret = error(_("could not read index"));
4163 }
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004164 goto leave_merge;
4165 }
4166
4167 merge_commit = to_merge->item;
Johannes Schindelin76e2a092024-02-28 09:44:14 +00004168 if (repo_get_merge_bases(r, head_commit, merge_commit, &bases) < 0) {
4169 ret = -1;
4170 goto leave_merge;
4171 }
4172
Jeff King4a7e27e2018-08-28 17:22:40 -04004173 if (bases && oideq(&merge_commit->object.oid,
4174 &bases->item->object.oid)) {
Johannes Schindelin7ccdf652018-04-25 14:29:31 +02004175 ret = 0;
4176 /* skip merging an ancestor of HEAD */
4177 goto leave_merge;
4178 }
4179
brian m. carlson4439c7a2019-08-18 20:04:16 +00004180 write_message(oid_to_hex(&merge_commit->object.oid), the_hash_algo->hexsz,
Junio C Hamanocde55542019-01-04 13:33:33 -08004181 git_path_merge_head(r), 0);
4182 write_message("no-ff", 5, git_path_merge_mode(r), 0);
Johannes Schindelin85f8d9d2018-11-12 15:25:58 -08004183
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004184 bases = reverse_commit_list(bases);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004185
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07004186 repo_read_index(r);
Nguyễn Thái Ngọc Duy0d6caa22019-01-12 09:13:29 +07004187 init_merge_options(&o, r);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004188 o.branch1 = "HEAD";
4189 o.branch2 = ref_name.buf;
4190 o.buffer_output = 2;
4191
Elijah Newren6a5fb962021-08-04 05:38:01 +00004192 if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
Elijah Newren14c45862020-11-02 23:45:34 +00004193 /*
4194 * TODO: Should use merge_incore_recursive() and
4195 * merge_switch_to_result(), skipping the call to
4196 * merge_switch_to_result() when we don't actually need to
4197 * update the index and working copy immediately.
4198 */
4199 ret = merge_ort_recursive(&o,
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004200 head_commit, merge_commit, bases,
Elijah Newren14c45862020-11-02 23:45:34 +00004201 &i);
4202 } else {
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004203 ret = merge_recursive(&o, head_commit, merge_commit, bases,
Elijah Newren14c45862020-11-02 23:45:34 +00004204 &i);
4205 }
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004206 if (ret <= 0)
4207 fputs(o.obuf.buf, stdout);
4208 strbuf_release(&o.obuf);
4209 if (ret < 0) {
4210 error(_("could not even attempt to merge '%.*s'"),
4211 merge_arg_len, arg);
Phillip Woode032abd2023-09-06 15:22:49 +00004212 unlink(git_path_merge_msg(r));
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004213 goto leave_merge;
4214 }
4215 /*
4216 * The return value of merge_recursive() is 1 on clean, and 0 on
4217 * unclean merge.
4218 *
4219 * Let's reverse that, so that do_merge() returns 0 upon success and
4220 * 1 upon failed merge (keeping the return value -1 for the cases where
4221 * we will want to reschedule the `merge` command).
4222 */
4223 ret = !ret;
4224
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004225 if (r->index->cache_changed &&
4226 write_locked_index(r->index, &lock, COMMIT_LOCK)) {
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004227 ret = error(_("merge: Unable to write new index file"));
4228 goto leave_merge;
4229 }
4230
4231 rollback_lock_file(&lock);
4232 if (ret)
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004233 repo_rerere(r, opts->allow_rerere_auto);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004234 else
4235 /*
4236 * In case of problems, we now want to return a positive
4237 * value (a negative one would indicate that the `merge`
4238 * command needs to be rescheduled).
4239 */
Jeff King20f4b042020-09-30 08:29:31 -04004240 ret = !!run_git_commit(git_path_merge_msg(r), opts,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004241 run_commit_flags);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004242
Phillip Wood2be6b6f2021-08-20 15:40:35 +00004243 if (!ret && flags & TODO_EDIT_MERGE_MSG) {
4244 fast_forward_edit:
4245 *check_todo = 1;
4246 run_commit_flags |= AMEND_MSG | EDIT_MSG | VERIFY_MSG;
4247 ret = !!run_git_commit(NULL, opts, run_commit_flags);
4248 }
4249
4250
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004251leave_merge:
4252 strbuf_release(&ref_name);
4253 rollback_lock_file(&lock);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004254 free_commit_list(to_merge);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004255 return ret;
4256}
4257
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004258static int write_update_refs_state(struct string_list *refs_to_oids)
Derrick Stoleea97d7912022-07-19 18:33:38 +00004259{
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004260 int result = 0;
4261 struct lock_file lock = LOCK_INIT;
4262 FILE *fp = NULL;
4263 struct string_list_item *item;
4264 char *path;
4265
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004266 path = rebase_path_update_refs(the_repository->gitdir);
4267
Victoria Dye44da9e02022-11-07 09:47:52 -08004268 if (!refs_to_oids->nr) {
4269 if (unlink(path) && errno != ENOENT)
4270 result = error_errno(_("could not unlink: %s"), path);
4271 goto cleanup;
4272 }
4273
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004274 if (safe_create_leading_directories(path)) {
4275 result = error(_("unable to create leading directories of %s"),
4276 path);
4277 goto cleanup;
4278 }
4279
4280 if (hold_lock_file_for_update(&lock, path, 0) < 0) {
4281 result = error(_("another 'rebase' process appears to be running; "
4282 "'%s.lock' already exists"),
4283 path);
4284 goto cleanup;
4285 }
4286
4287 fp = fdopen_lock_file(&lock, "w");
4288 if (!fp) {
4289 result = error_errno(_("could not open '%s' for writing"), path);
4290 rollback_lock_file(&lock);
4291 goto cleanup;
4292 }
4293
4294 for_each_string_list_item(item, refs_to_oids) {
4295 struct update_ref_record *rec = item->util;
4296 fprintf(fp, "%s\n%s\n%s\n", item->string,
4297 oid_to_hex(&rec->before), oid_to_hex(&rec->after));
4298 }
4299
4300 result = commit_lock_file(&lock);
4301
4302cleanup:
4303 free(path);
4304 return result;
4305}
4306
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004307/*
4308 * Parse the update-refs file for the current rebase, then remove the
4309 * refs that do not appear in the todo_list (and have not had updated
4310 * values stored) and add refs that are in the todo_list but not
4311 * represented in the update-refs file.
4312 *
4313 * If there are changes to the update-refs list, then write the new state
4314 * to disk.
4315 */
4316void todo_list_filter_update_refs(struct repository *r,
4317 struct todo_list *todo_list)
4318{
4319 int i;
4320 int updated = 0;
4321 struct string_list update_refs = STRING_LIST_INIT_DUP;
4322
4323 sequencer_get_update_refs_state(r->gitdir, &update_refs);
4324
4325 /*
4326 * For each item in the update_refs list, if it has no updated
4327 * value and does not appear in the todo_list, then remove it
4328 * from the update_refs list.
4329 */
4330 for (i = 0; i < update_refs.nr; i++) {
4331 int j;
4332 int found = 0;
4333 const char *ref = update_refs.items[i].string;
4334 size_t reflen = strlen(ref);
4335 struct update_ref_record *rec = update_refs.items[i].util;
4336
4337 /* OID already stored as updated. */
4338 if (!is_null_oid(&rec->after))
4339 continue;
4340
Johannes Schindelinfa5103d2023-05-13 08:11:25 +00004341 for (j = 0; !found && j < todo_list->nr; j++) {
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004342 struct todo_item *item = &todo_list->items[j];
4343 const char *arg = todo_list->buf.buf + item->arg_offset;
4344
4345 if (item->command != TODO_UPDATE_REF)
4346 continue;
4347
4348 if (item->arg_len != reflen ||
4349 strncmp(arg, ref, reflen))
4350 continue;
4351
4352 found = 1;
4353 }
4354
4355 if (!found) {
4356 free(update_refs.items[i].string);
4357 free(update_refs.items[i].util);
4358
4359 update_refs.nr--;
4360 MOVE_ARRAY(update_refs.items + i, update_refs.items + i + 1, update_refs.nr - i);
4361
4362 updated = 1;
4363 i--;
4364 }
4365 }
4366
4367 /*
4368 * For each todo_item, check if its ref is in the update_refs list.
4369 * If not, then add it as an un-updated ref.
4370 */
Johannes Schindelinfa5103d2023-05-13 08:11:25 +00004371 for (i = 0; i < todo_list->nr; i++) {
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004372 struct todo_item *item = &todo_list->items[i];
4373 const char *arg = todo_list->buf.buf + item->arg_offset;
4374 int j, found = 0;
4375
4376 if (item->command != TODO_UPDATE_REF)
4377 continue;
4378
4379 for (j = 0; !found && j < update_refs.nr; j++) {
4380 const char *ref = update_refs.items[j].string;
4381
4382 found = strlen(ref) == item->arg_len &&
4383 !strncmp(ref, arg, item->arg_len);
4384 }
4385
4386 if (!found) {
4387 struct string_list_item *inserted;
4388 struct strbuf argref = STRBUF_INIT;
4389
4390 strbuf_add(&argref, arg, item->arg_len);
4391 inserted = string_list_insert(&update_refs, argref.buf);
4392 inserted->util = init_update_ref_record(argref.buf);
4393 strbuf_release(&argref);
4394 updated = 1;
4395 }
4396 }
4397
4398 if (updated)
4399 write_update_refs_state(&update_refs);
4400 string_list_clear(&update_refs, 1);
4401}
4402
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004403static int do_update_ref(struct repository *r, const char *refname)
4404{
4405 struct string_list_item *item;
4406 struct string_list list = STRING_LIST_INIT_DUP;
4407
4408 if (sequencer_get_update_refs_state(r->gitdir, &list))
4409 return -1;
4410
4411 for_each_string_list_item(item, &list) {
4412 if (!strcmp(item->string, refname)) {
4413 struct update_ref_record *rec = item->util;
4414 if (read_ref("HEAD", &rec->after))
4415 return -1;
4416 break;
4417 }
4418 }
4419
4420 write_update_refs_state(&list);
4421 string_list_clear(&list, 1);
Derrick Stoleea97d7912022-07-19 18:33:38 +00004422 return 0;
4423}
4424
Derrick Stolee46118842022-07-19 18:33:44 +00004425static int do_update_refs(struct repository *r, int quiet)
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004426{
4427 int res = 0;
4428 struct string_list_item *item;
4429 struct string_list refs_to_oids = STRING_LIST_INIT_DUP;
4430 struct ref_store *refs = get_main_ref_store(r);
Derrick Stolee46118842022-07-19 18:33:44 +00004431 struct strbuf update_msg = STRBUF_INIT;
4432 struct strbuf error_msg = STRBUF_INIT;
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004433
4434 if ((res = sequencer_get_update_refs_state(r->gitdir, &refs_to_oids)))
4435 return res;
4436
4437 for_each_string_list_item(item, &refs_to_oids) {
4438 struct update_ref_record *rec = item->util;
Derrick Stolee46118842022-07-19 18:33:44 +00004439 int loop_res;
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004440
Derrick Stolee46118842022-07-19 18:33:44 +00004441 loop_res = refs_update_ref(refs, "rewritten during rebase",
4442 item->string,
4443 &rec->after, &rec->before,
4444 0, UPDATE_REFS_MSG_ON_ERR);
4445 res |= loop_res;
4446
4447 if (quiet)
4448 continue;
4449
4450 if (loop_res)
4451 strbuf_addf(&error_msg, "\t%s\n", item->string);
4452 else
4453 strbuf_addf(&update_msg, "\t%s\n", item->string);
4454 }
4455
4456 if (!quiet &&
4457 (update_msg.len || error_msg.len)) {
4458 fprintf(stderr,
4459 _("Updated the following refs with %s:\n%s"),
4460 "--update-refs",
4461 update_msg.buf);
4462
4463 if (res)
4464 fprintf(stderr,
4465 _("Failed to update the following refs with %s:\n%s"),
4466 "--update-refs",
4467 error_msg.buf);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004468 }
4469
4470 string_list_clear(&refs_to_oids, 1);
Derrick Stolee46118842022-07-19 18:33:44 +00004471 strbuf_release(&update_msg);
4472 strbuf_release(&error_msg);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004473 return res;
4474}
4475
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004476static int is_final_fixup(struct todo_list *todo_list)
4477{
4478 int i = todo_list->current;
4479
4480 if (!is_fixup(todo_list->items[i].command))
4481 return 0;
4482
4483 while (++i < todo_list->nr)
4484 if (is_fixup(todo_list->items[i].command))
4485 return 0;
4486 else if (!is_noop(todo_list->items[i].command))
4487 break;
4488 return 1;
4489}
4490
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004491static enum todo_command peek_command(struct todo_list *todo_list, int offset)
4492{
4493 int i;
4494
4495 for (i = todo_list->current + offset; i < todo_list->nr; i++)
4496 if (!is_noop(todo_list->items[i].command))
4497 return todo_list->items[i].command;
4498
4499 return -1;
4500}
4501
Patrick Steinhardt35122da2024-01-19 11:40:15 +01004502static void create_autostash_internal(struct repository *r,
4503 const char *path,
4504 const char *refname)
Johannes Schindelin796c7972017-01-02 16:28:27 +01004505{
Denton Liu0816f1d2020-04-07 10:28:03 -04004506 struct strbuf buf = STRBUF_INIT;
4507 struct lock_file lock_file = LOCK_INIT;
4508 int fd;
4509
Patrick Steinhardt35122da2024-01-19 11:40:15 +01004510 if (path && refname)
4511 BUG("can only pass path or refname");
4512
Denton Liu0816f1d2020-04-07 10:28:03 -04004513 fd = repo_hold_locked_index(r, &lock_file, 0);
4514 refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
4515 if (0 <= fd)
4516 repo_update_index_if_able(r, &lock_file);
4517 rollback_lock_file(&lock_file);
4518
4519 if (has_unstaged_changes(r, 1) ||
4520 has_uncommitted_changes(r, 1)) {
4521 struct child_process stash = CHILD_PROCESS_INIT;
Phillip Wood6ae80862022-01-26 13:05:46 +00004522 struct reset_head_opts ropts = { .flags = RESET_HEAD_HARD };
Denton Liu0816f1d2020-04-07 10:28:03 -04004523 struct object_id oid;
4524
Jeff Kingc972bf42020-07-28 16:25:12 -04004525 strvec_pushl(&stash.args,
Jeff Kingf6d89422020-07-28 16:26:31 -04004526 "stash", "create", "autostash", NULL);
Denton Liu0816f1d2020-04-07 10:28:03 -04004527 stash.git_cmd = 1;
4528 stash.no_stdin = 1;
4529 strbuf_reset(&buf);
4530 if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
4531 die(_("Cannot autostash"));
4532 strbuf_trim_trailing_newline(&buf);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004533 if (repo_get_oid(r, buf.buf, &oid))
Denton Liu0816f1d2020-04-07 10:28:03 -04004534 die(_("Unexpected stash response: '%s'"),
4535 buf.buf);
4536 strbuf_reset(&buf);
4537 strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
4538
Patrick Steinhardt35122da2024-01-19 11:40:15 +01004539 if (path) {
4540 if (safe_create_leading_directories_const(path))
4541 die(_("Could not create directory for '%s'"),
4542 path);
4543 write_file(path, "%s", oid_to_hex(&oid));
4544 } else {
4545 refs_update_ref(get_main_ref_store(r), "", refname,
4546 &oid, null_oid(), 0, UPDATE_REFS_DIE_ON_ERR);
4547 }
4548
Denton Liu0816f1d2020-04-07 10:28:03 -04004549 printf(_("Created autostash: %s\n"), buf.buf);
Phillip Wood6ae80862022-01-26 13:05:46 +00004550 if (reset_head(r, &ropts) < 0)
Denton Liu0816f1d2020-04-07 10:28:03 -04004551 die(_("could not reset --hard"));
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01004552 discard_index(r->index);
4553 if (repo_read_index(r) < 0)
Denton Liu0816f1d2020-04-07 10:28:03 -04004554 die(_("could not read index"));
4555 }
4556 strbuf_release(&buf);
4557}
4558
Patrick Steinhardt35122da2024-01-19 11:40:15 +01004559void create_autostash(struct repository *r, const char *path)
4560{
4561 create_autostash_internal(r, path, NULL);
4562}
4563
4564void create_autostash_ref(struct repository *r, const char *refname)
4565{
4566 create_autostash_internal(r, NULL, refname);
4567}
4568
Denton Liu804fe312020-04-07 10:28:06 -04004569static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply)
Johannes Schindelin796c7972017-01-02 16:28:27 +01004570{
Johannes Schindelin796c7972017-01-02 16:28:27 +01004571 struct child_process child = CHILD_PROCESS_INIT;
4572 int ret = 0;
4573
Denton Liu12b6e132020-04-07 10:28:05 -04004574 if (attempt_apply) {
4575 child.git_cmd = 1;
4576 child.no_stdout = 1;
4577 child.no_stderr = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004578 strvec_push(&child.args, "stash");
4579 strvec_push(&child.args, "apply");
4580 strvec_push(&child.args, stash_oid);
Denton Liu12b6e132020-04-07 10:28:05 -04004581 ret = run_command(&child);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004582 }
Johannes Schindelin796c7972017-01-02 16:28:27 +01004583
Denton Liu12b6e132020-04-07 10:28:05 -04004584 if (attempt_apply && !ret)
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004585 fprintf(stderr, _("Applied autostash.\n"));
Johannes Schindelin796c7972017-01-02 16:28:27 +01004586 else {
4587 struct child_process store = CHILD_PROCESS_INIT;
4588
4589 store.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004590 strvec_push(&store.args, "stash");
4591 strvec_push(&store.args, "store");
4592 strvec_push(&store.args, "-m");
4593 strvec_push(&store.args, "autostash");
4594 strvec_push(&store.args, "-q");
4595 strvec_push(&store.args, stash_oid);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004596 if (run_command(&store))
Denton Liu804fe312020-04-07 10:28:06 -04004597 ret = error(_("cannot store %s"), stash_oid);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004598 else
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004599 fprintf(stderr,
Denton Liu12b6e132020-04-07 10:28:05 -04004600 _("%s\n"
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004601 "Your changes are safe in the stash.\n"
4602 "You can run \"git stash pop\" or"
Denton Liu12b6e132020-04-07 10:28:05 -04004603 " \"git stash drop\" at any time.\n"),
4604 attempt_apply ?
4605 _("Applying autostash resulted in conflicts.") :
4606 _("Autostash exists; creating a new stash entry."));
Johannes Schindelin796c7972017-01-02 16:28:27 +01004607 }
4608
Johannes Schindelin796c7972017-01-02 16:28:27 +01004609 return ret;
4610}
4611
Denton Liu804fe312020-04-07 10:28:06 -04004612static int apply_save_autostash(const char *path, int attempt_apply)
4613{
4614 struct strbuf stash_oid = STRBUF_INIT;
4615 int ret = 0;
4616
4617 if (!read_oneliner(&stash_oid, path,
4618 READ_ONELINER_SKIP_IF_EMPTY)) {
4619 strbuf_release(&stash_oid);
4620 return 0;
4621 }
4622 strbuf_trim(&stash_oid);
4623
4624 ret = apply_save_autostash_oid(stash_oid.buf, attempt_apply);
4625
Denton Liu0dd562e2020-04-07 10:28:04 -04004626 unlink(path);
Denton Liufacca7f2020-04-07 10:27:57 -04004627 strbuf_release(&stash_oid);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304628 return ret;
4629}
4630
Denton Liu12b6e132020-04-07 10:28:05 -04004631int save_autostash(const char *path)
4632{
4633 return apply_save_autostash(path, 0);
4634}
4635
4636int apply_autostash(const char *path)
4637{
4638 return apply_save_autostash(path, 1);
4639}
4640
Denton Liu804fe312020-04-07 10:28:06 -04004641int apply_autostash_oid(const char *stash_oid)
4642{
4643 return apply_save_autostash_oid(stash_oid, 1);
4644}
4645
Patrick Steinhardt35122da2024-01-19 11:40:15 +01004646static int apply_save_autostash_ref(struct repository *r, const char *refname,
4647 int attempt_apply)
4648{
4649 struct object_id stash_oid;
4650 char stash_oid_hex[GIT_MAX_HEXSZ + 1];
4651 int flag, ret;
4652
4653 if (!refs_ref_exists(get_main_ref_store(r), refname))
4654 return 0;
4655
4656 if (!refs_resolve_ref_unsafe(get_main_ref_store(r), refname,
4657 RESOLVE_REF_READING, &stash_oid, &flag))
4658 return -1;
4659 if (flag & REF_ISSYMREF)
4660 return error(_("autostash reference is a symref"));
4661
4662 oid_to_hex_r(stash_oid_hex, &stash_oid);
4663 ret = apply_save_autostash_oid(stash_oid_hex, attempt_apply);
4664
4665 refs_delete_ref(get_main_ref_store(r), "", refname,
4666 &stash_oid, REF_NO_DEREF);
4667
4668 return ret;
4669}
4670
4671int save_autostash_ref(struct repository *r, const char *refname)
4672{
4673 return apply_save_autostash_ref(r, refname, 0);
4674}
4675
4676int apply_autostash_ref(struct repository *r, const char *refname)
4677{
4678 return apply_save_autostash_ref(r, refname, 1);
4679}
4680
Phillip Woodfc4a6732019-03-19 19:03:07 +00004681static int checkout_onto(struct repository *r, struct replay_opts *opts,
Phillip Wood7d3488e2019-04-17 15:30:39 +01004682 const char *onto_name, const struct object_id *onto,
Phillip Woodf3e27a02020-11-04 15:29:38 +00004683 const struct object_id *orig_head)
Alban Gruin4df66c42018-08-10 18:51:34 +02004684{
Phillip Wood38c541c2022-01-26 13:05:49 +00004685 struct reset_head_opts ropts = {
4686 .oid = onto,
4687 .orig_head = orig_head,
4688 .flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
4689 RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
4690 .head_msg = reflog_message(opts, "start", "checkout %s",
4691 onto_name),
Phillip Woodd188a602022-11-09 14:21:57 +00004692 .default_reflog_action = sequencer_reflog_action(opts)
Phillip Wood38c541c2022-01-26 13:05:49 +00004693 };
4694 if (reset_head(r, &ropts)) {
Denton Liube1bb602020-04-07 10:27:56 -04004695 apply_autostash(rebase_path_autostash());
Alban Gruin4df66c42018-08-10 18:51:34 +02004696 sequencer_remove_state(opts);
4697 return error(_("could not detach HEAD"));
4698 }
4699
Phillip Wood38c541c2022-01-26 13:05:49 +00004700 return 0;
Alban Gruin4df66c42018-08-10 18:51:34 +02004701}
4702
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004703static int stopped_at_head(struct repository *r)
Johannes Schindelin71f82462018-10-12 06:14:26 -07004704{
4705 struct object_id head;
4706 struct commit *commit;
4707 struct commit_message message;
4708
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004709 if (repo_get_oid(r, "HEAD", &head) ||
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004710 !(commit = lookup_commit(r, &head)) ||
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004711 repo_parse_commit(r, commit) || get_message(commit, &message))
Johannes Schindelin71f82462018-10-12 06:14:26 -07004712 fprintf(stderr, _("Stopped at HEAD\n"));
4713 else {
4714 fprintf(stderr, _("Stopped at %s\n"), message.label);
4715 free_message(commit, &message);
4716 }
4717 return 0;
4718
4719}
4720
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004721static int reread_todo_if_changed(struct repository *r,
4722 struct todo_list *todo_list,
4723 struct replay_opts *opts)
4724{
Phillip Wood2b88fe02021-09-23 15:26:21 +00004725 int offset;
4726 struct strbuf buf = STRBUF_INIT;
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004727
Phillip Wood2b88fe02021-09-23 15:26:21 +00004728 if (strbuf_read_file_or_whine(&buf, get_todo_path(opts)) < 0)
4729 return -1;
4730 offset = get_item_line_offset(todo_list, todo_list->current + 1);
4731 if (buf.len != todo_list->buf.len - offset ||
4732 memcmp(buf.buf, todo_list->buf.buf + offset, buf.len)) {
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004733 /* Reread the todo file if it has changed. */
4734 todo_list_release(todo_list);
4735 if (read_populate_todo(r, todo_list, opts))
4736 return -1; /* message was printed */
4737 /* `current` will be incremented on return */
4738 todo_list->current = -1;
4739 }
Phillip Wood2b88fe02021-09-23 15:26:21 +00004740 strbuf_release(&buf);
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004741
4742 return 0;
4743}
4744
Johannes Schindelincb5206e2018-04-25 14:28:33 +02004745static const char rescheduled_advice[] =
4746N_("Could not execute the todo command\n"
4747"\n"
4748" %.*s"
4749"\n"
4750"It has been rescheduled; To edit the command before continuing, please\n"
4751"edit the todo list first:\n"
4752"\n"
4753" git rebase --edit-todo\n"
4754" git rebase --continue\n");
4755
Phillip Woodf2b5f412023-09-06 15:22:48 +00004756static int pick_one_commit(struct repository *r,
4757 struct todo_list *todo_list,
4758 struct replay_opts *opts,
Phillip Woode032abd2023-09-06 15:22:49 +00004759 int *check_todo, int* reschedule)
Phillip Woodf2b5f412023-09-06 15:22:48 +00004760{
4761 int res;
4762 struct todo_item *item = todo_list->items + todo_list->current;
4763 const char *arg = todo_item_get_arg(todo_list, item);
4764 if (is_rebase_i(opts))
4765 opts->reflog_message = reflog_message(
4766 opts, command_to_string(item->command), NULL);
4767
4768 res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
4769 check_todo);
4770 if (is_rebase_i(opts) && res < 0) {
4771 /* Reschedule */
Phillip Woode032abd2023-09-06 15:22:49 +00004772 *reschedule = 1;
4773 return -1;
Phillip Woodf2b5f412023-09-06 15:22:48 +00004774 }
4775 if (item->command == TODO_EDIT) {
4776 struct commit *commit = item->commit;
4777 if (!res) {
4778 if (!opts->verbose)
4779 term_clear_line();
4780 fprintf(stderr, _("Stopped at %s... %.*s\n"),
Junio C Hamanob995e782023-09-14 11:17:00 -07004781 short_commit_name(r, commit), item->arg_len, arg);
Phillip Woodf2b5f412023-09-06 15:22:48 +00004782 }
4783 return error_with_patch(r, commit,
4784 arg, item->arg_len, opts, res, !res);
4785 }
4786 if (is_rebase_i(opts) && !res)
4787 record_in_rewritten(&item->commit->object.oid,
4788 peek_command(todo_list, 1));
4789 if (res && is_fixup(item->command)) {
4790 if (res == 1)
4791 intend_to_amend();
4792 return error_failed_squash(r, item->commit, opts,
4793 item->arg_len, arg);
4794 } else if (res && is_rebase_i(opts) && item->commit) {
4795 int to_amend = 0;
4796 struct object_id oid;
4797
4798 /*
4799 * If we are rewording and have either
4800 * fast-forwarded already, or are about to
4801 * create a new root commit, we want to amend,
4802 * otherwise we do not.
4803 */
4804 if (item->command == TODO_REWORD &&
4805 !repo_get_oid(r, "HEAD", &oid) &&
4806 (oideq(&item->commit->object.oid, &oid) ||
4807 (opts->have_squash_onto &&
4808 oideq(&opts->squash_onto, &oid))))
4809 to_amend = 1;
4810
4811 return res | error_with_patch(r, item->commit,
4812 arg, item->arg_len, opts,
4813 res, to_amend);
4814 }
4815 return res;
4816}
4817
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004818static int pick_commits(struct repository *r,
4819 struct todo_list *todo_list,
4820 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304821{
Johannes Schindelin9055e402018-04-25 14:28:47 +02004822 int res = 0, reschedule = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304823
Phillip Woodd188a602022-11-09 14:21:57 +00004824 opts->reflog_message = sequencer_reflog_action(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304825 if (opts->allow_ff)
4826 assert(!(opts->signoff || opts->no_commit ||
Elijah Newren39edfd52021-03-31 06:52:20 +00004827 opts->record_origin || should_edit(opts) ||
Phillip Wooda3894aa2020-08-17 18:40:03 +01004828 opts->committer_date_is_author_date ||
4829 opts->ignore_date));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004830 if (read_and_refresh_cache(r, opts))
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02004831 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304832
Phillip Wood36ac8612023-09-06 15:22:45 +00004833 unlink(rebase_path_message());
4834 unlink(rebase_path_stopped_sha());
4835 unlink(rebase_path_amend());
Phillip Wood206a78d2023-09-06 15:22:46 +00004836 unlink(rebase_path_patch());
Phillip Wood36ac8612023-09-06 15:22:45 +00004837
Johannes Schindelin004fefa2016-10-21 14:24:41 +02004838 while (todo_list->current < todo_list->nr) {
4839 struct todo_item *item = todo_list->items + todo_list->current;
Alban Gruin6ad656d2019-01-29 16:01:46 +01004840 const char *arg = todo_item_get_arg(todo_list, item);
Phillip Wooda47ba3c2019-08-19 02:18:22 -07004841 int check_todo = 0;
Alban Gruin6ad656d2019-01-29 16:01:46 +01004842
Phillip Wood203573b2023-09-06 15:22:51 +00004843 if (save_todo(todo_list, opts, reschedule))
Johannes Schindelin221675d2016-09-09 16:37:50 +02004844 return -1;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004845 if (is_rebase_i(opts)) {
Johannes Schindelinef800692017-01-02 16:36:20 +01004846 if (item->command != TODO_COMMENT) {
4847 FILE *f = fopen(rebase_path_msgnum(), "w");
4848
4849 todo_list->done_nr++;
4850
4851 if (f) {
4852 fprintf(f, "%d\n", todo_list->done_nr);
4853 fclose(f);
4854 }
Elijah Newren899b49c2018-12-11 08:11:36 -08004855 if (!opts->quiet)
Alban Gruin4d55d632020-03-28 14:05:15 +01004856 fprintf(stderr, _("Rebasing (%d/%d)%s"),
Elijah Newren899b49c2018-12-11 08:11:36 -08004857 todo_list->done_nr,
4858 todo_list->total_nr,
4859 opts->verbose ? "\n" : "\r");
Johannes Schindelinef800692017-01-02 16:36:20 +01004860 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004861 unlink(rebase_path_author_script());
Nguyễn Thái Ngọc Duy34e77712019-06-27 16:28:52 +07004862 unlink(git_path_merge_head(r));
Patrick Steinhardtfd7c6ff2024-01-19 11:40:09 +01004863 refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
4864 NULL, REF_NO_DEREF);
Patrick Steinhardtbb02e952024-01-19 11:40:04 +01004865 refs_delete_ref(get_main_ref_store(r), "", "REBASE_HEAD",
4866 NULL, REF_NO_DEREF);
Johannes Schindelin71f82462018-10-12 06:14:26 -07004867
SZEDER Gábord7d90882019-06-27 15:42:48 +02004868 if (item->command == TODO_BREAK) {
4869 if (!opts->verbose)
4870 term_clear_line();
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004871 return stopped_at_head(r);
SZEDER Gábord7d90882019-06-27 15:42:48 +02004872 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004873 }
4874 if (item->command <= TODO_SQUASH) {
Phillip Woode032abd2023-09-06 15:22:49 +00004875 res = pick_one_commit(r, todo_list, opts, &check_todo,
4876 &reschedule);
Phillip Woodf2b5f412023-09-06 15:22:48 +00004877 if (!res && item->command == TODO_EDIT)
4878 return 0;
Johannes Schindelin311af522017-01-02 16:26:47 +01004879 } else if (item->command == TODO_EXEC) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004880 char *end_of_arg = (char *)(arg + item->arg_len);
Johannes Schindelin311af522017-01-02 16:26:47 +01004881 int saved = *end_of_arg;
4882
SZEDER Gábord7d90882019-06-27 15:42:48 +02004883 if (!opts->verbose)
4884 term_clear_line();
Johannes Schindelin311af522017-01-02 16:26:47 +01004885 *end_of_arg = '\0';
Alban Gruin6ad656d2019-01-29 16:01:46 +01004886 res = do_exec(r, arg);
Johannes Schindelin311af522017-01-02 16:26:47 +01004887 *end_of_arg = saved;
Stephen Hicks54fd3242017-04-26 21:17:40 +02004888
Johannes Schindelind421afa2018-12-10 11:04:58 -08004889 if (res) {
4890 if (opts->reschedule_failed_exec)
4891 reschedule = 1;
Stephen Hicks54fd3242017-04-26 21:17:40 +02004892 }
Phillip Wooda47ba3c2019-08-19 02:18:22 -07004893 check_todo = 1;
Johannes Schindelin9055e402018-04-25 14:28:47 +02004894 } else if (item->command == TODO_LABEL) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004895 if ((res = do_label(r, arg, item->arg_len)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02004896 reschedule = 1;
4897 } else if (item->command == TODO_RESET) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004898 if ((res = do_reset(r, arg, item->arg_len, opts)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02004899 reschedule = 1;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004900 } else if (item->command == TODO_MERGE) {
Phillip Wood2be6b6f2021-08-20 15:40:35 +00004901 if ((res = do_merge(r, item->commit, arg, item->arg_len,
4902 item->flags, &check_todo, opts)) < 0)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004903 reschedule = 1;
Johannes Schindelin537e7d62018-04-25 14:29:29 +02004904 else if (item->commit)
4905 record_in_rewritten(&item->commit->object.oid,
4906 peek_command(todo_list, 1));
4907 if (res > 0)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004908 /* failed with merge conflicts */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004909 return error_with_patch(r, item->commit,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004910 arg, item->arg_len,
4911 opts, res, 0);
Derrick Stoleea97d7912022-07-19 18:33:38 +00004912 } else if (item->command == TODO_UPDATE_REF) {
4913 struct strbuf ref = STRBUF_INIT;
4914 strbuf_add(&ref, arg, item->arg_len);
4915 if ((res = do_update_ref(r, ref.buf)))
4916 reschedule = 1;
4917 strbuf_release(&ref);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004918 } else if (!is_noop(item->command))
Johannes Schindelin25c43662017-01-02 16:26:38 +01004919 return error(_("unknown command %d"), item->command);
4920
Johannes Schindelin9055e402018-04-25 14:28:47 +02004921 if (reschedule) {
4922 advise(_(rescheduled_advice),
4923 get_item_line_length(todo_list,
4924 todo_list->current),
4925 get_item_line(todo_list, todo_list->current));
Phillip Wood203573b2023-09-06 15:22:51 +00004926 if (save_todo(todo_list, opts, reschedule))
Johannes Schindelin9055e402018-04-25 14:28:47 +02004927 return -1;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004928 if (item->commit)
Phillip Woode032abd2023-09-06 15:22:49 +00004929 write_rebase_head(&item->commit->object.oid);
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004930 } else if (is_rebase_i(opts) && check_todo && !res &&
4931 reread_todo_if_changed(r, todo_list, opts)) {
4932 return -1;
Johannes Schindelin9055e402018-04-25 14:28:47 +02004933 }
4934
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304935 if (res)
4936 return res;
Phillip Woodf2b5f412023-09-06 15:22:48 +00004937
4938 todo_list->current++;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304939 }
4940
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004941 if (is_rebase_i(opts)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004942 struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004943 struct stat st;
Johannes Schindelin556907f2017-01-02 16:26:53 +01004944
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004945 if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
4946 starts_with(head_ref.buf, "refs/")) {
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004947 const char *msg;
brian m. carlson092bbcd2017-07-13 23:49:22 +00004948 struct object_id head, orig;
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004949 int res;
4950
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004951 if (repo_get_oid(r, "HEAD", &head)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004952 res = error(_("cannot read HEAD"));
4953cleanup_head_ref:
4954 strbuf_release(&head_ref);
4955 strbuf_release(&buf);
4956 return res;
4957 }
4958 if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
brian m. carlson092bbcd2017-07-13 23:49:22 +00004959 get_oid_hex(buf.buf, &orig)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004960 res = error(_("could not read orig-head"));
4961 goto cleanup_head_ref;
4962 }
Phillip Wood4ab867b2017-05-18 11:02:32 +01004963 strbuf_reset(&buf);
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004964 if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
4965 res = error(_("could not read 'onto'"));
4966 goto cleanup_head_ref;
4967 }
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004968 msg = reflog_message(opts, "finish", "%s onto %s",
4969 head_ref.buf, buf.buf);
brian m. carlsonae077772017-10-15 22:06:51 +00004970 if (update_ref(msg, head_ref.buf, &head, &orig,
Michael Haggerty91774af2017-11-05 09:42:06 +01004971 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004972 res = error(_("could not update %s"),
4973 head_ref.buf);
4974 goto cleanup_head_ref;
4975 }
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004976 msg = reflog_message(opts, "finish", "returning to %s",
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004977 head_ref.buf);
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004978 if (create_symref("HEAD", head_ref.buf, msg)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004979 res = error(_("could not update HEAD to %s"),
4980 head_ref.buf);
4981 goto cleanup_head_ref;
4982 }
4983 strbuf_reset(&buf);
4984 }
4985
Johannes Schindelin556907f2017-01-02 16:26:53 +01004986 if (opts->verbose) {
4987 struct rev_info log_tree_opt;
4988 struct object_id orig, head;
4989
4990 memset(&log_tree_opt, 0, sizeof(log_tree_opt));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004991 repo_init_revisions(r, &log_tree_opt, NULL);
Johannes Schindelin556907f2017-01-02 16:26:53 +01004992 log_tree_opt.diff = 1;
4993 log_tree_opt.diffopt.output_format =
4994 DIFF_FORMAT_DIFFSTAT;
4995 log_tree_opt.disable_stdin = 1;
4996
4997 if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004998 !repo_get_oid(r, buf.buf, &orig) &&
4999 !repo_get_oid(r, "HEAD", &head)) {
Brandon Williams66f414f2017-05-30 10:31:03 -07005000 diff_tree_oid(&orig, &head, "",
5001 &log_tree_opt.diffopt);
Johannes Schindelin556907f2017-01-02 16:26:53 +01005002 log_tree_diff_flush(&log_tree_opt);
5003 }
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02005004 release_revisions(&log_tree_opt);
Johannes Schindelin556907f2017-01-02 16:26:53 +01005005 }
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01005006 flush_rewritten_pending();
5007 if (!stat(rebase_path_rewritten_list(), &st) &&
5008 st.st_size > 0) {
5009 struct child_process child = CHILD_PROCESS_INIT;
Emily Shaffer96af5642023-02-08 20:21:14 +01005010 struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01005011
5012 child.in = open(rebase_path_rewritten_list(), O_RDONLY);
5013 child.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04005014 strvec_push(&child.args, "notes");
5015 strvec_push(&child.args, "copy");
5016 strvec_push(&child.args, "--for-rewrite=rebase");
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01005017 /* we don't care if this copying failed */
5018 run_command(&child);
Johannes Schindelin79516042017-01-02 16:28:23 +01005019
Emily Shaffer96af5642023-02-08 20:21:14 +01005020 hook_opt.path_to_stdin = rebase_path_rewritten_list();
5021 strvec_push(&hook_opt.args, "rebase");
5022 run_hooks_opt("post-rewrite", &hook_opt);
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01005023 }
Denton Liube1bb602020-04-07 10:27:56 -04005024 apply_autostash(rebase_path_autostash());
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01005025
SZEDER Gábord7d90882019-06-27 15:42:48 +02005026 if (!opts->quiet) {
5027 if (!opts->verbose)
5028 term_clear_line();
Elijah Newren899b49c2018-12-11 08:11:36 -08005029 fprintf(stderr,
Alban Gruin4d55d632020-03-28 14:05:15 +01005030 _("Successfully rebased and updated %s.\n"),
Elijah Newren899b49c2018-12-11 08:11:36 -08005031 head_ref.buf);
SZEDER Gábord7d90882019-06-27 15:42:48 +02005032 }
Johannes Schindelin5da49662017-01-02 16:36:25 +01005033
Johannes Schindelin556907f2017-01-02 16:26:53 +01005034 strbuf_release(&buf);
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01005035 strbuf_release(&head_ref);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00005036
Derrick Stolee46118842022-07-19 18:33:44 +00005037 if (do_update_refs(r, opts->quiet))
Derrick Stolee89fc0b52022-07-19 18:33:40 +00005038 return -1;
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01005039 }
5040
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305041 /*
5042 * Sequence of picks finished successfully; cleanup by
5043 * removing the .git/sequencer directory
5044 */
Johannes Schindelin28635842016-10-21 14:24:55 +02005045 return sequencer_remove_state(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305046}
5047
Elijah Newren39edfd52021-03-31 06:52:20 +00005048static int continue_single_pick(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305049{
René Scharfe0e906732022-10-30 12:51:14 +01005050 struct child_process cmd = CHILD_PROCESS_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305051
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00005052 if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00005053 !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305054 return error(_("no cherry-pick or revert in progress"));
Elijah Newren39edfd52021-03-31 06:52:20 +00005055
René Scharfe0e906732022-10-30 12:51:14 +01005056 cmd.git_cmd = 1;
5057 strvec_push(&cmd.args, "commit");
Elijah Newren39edfd52021-03-31 06:52:20 +00005058
5059 /*
5060 * continue_single_pick() handles the case of recovering from a
5061 * conflict. should_edit() doesn't handle that case; for a conflict,
5062 * we want to edit if the user asked for it, or if they didn't specify
5063 * and stdin is a tty.
5064 */
5065 if (!opts->edit || (opts->edit < 0 && !isatty(0)))
5066 /*
5067 * Include --cleanup=strip as well because we don't want the
5068 * "# Conflicts:" messages.
5069 */
René Scharfe0e906732022-10-30 12:51:14 +01005070 strvec_pushl(&cmd.args, "--no-edit", "--cleanup=strip", NULL);
Elijah Newren39edfd52021-03-31 06:52:20 +00005071
René Scharfe0e906732022-10-30 12:51:14 +01005072 return run_command(&cmd);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305073}
5074
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005075static int commit_staged_changes(struct repository *r,
5076 struct replay_opts *opts,
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005077 struct todo_list *todo_list)
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005078{
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01005079 unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005080 unsigned int final_fixup = 0, is_clean;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005081
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005082 if (has_unstaged_changes(r, 1))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005083 return error(_("cannot rebase: You have unstaged changes."));
Johannes Schindelin52632202017-01-02 16:27:25 +01005084
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005085 is_clean = !has_uncommitted_changes(r, 0);
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005086
Phillip Wood405509c2023-09-06 15:22:50 +00005087 if (!is_clean && !file_exists(rebase_path_message())) {
5088 const char *gpg_opt = gpg_sign_opt_quoted(opts);
5089
5090 return error(_(staged_changes_advice), gpg_opt, gpg_opt);
5091 }
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005092 if (file_exists(rebase_path_amend())) {
5093 struct strbuf rev = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00005094 struct object_id head, to_amend;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005095
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005096 if (repo_get_oid(r, "HEAD", &head))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005097 return error(_("cannot amend non-existing commit"));
5098 if (!read_oneliner(&rev, rebase_path_amend(), 0))
5099 return error(_("invalid file: '%s'"), rebase_path_amend());
brian m. carlson092bbcd2017-07-13 23:49:22 +00005100 if (get_oid_hex(rev.buf, &to_amend))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005101 return error(_("invalid contents: '%s'"),
5102 rebase_path_amend());
Jeff King9001dc22018-08-28 17:22:48 -04005103 if (!is_clean && !oideq(&head, &to_amend))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005104 return error(_("\nYou have uncommitted changes in your "
5105 "working tree. Please, commit them\n"
5106 "first and then run 'git rebase "
5107 "--continue' again."));
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005108 /*
5109 * When skipping a failed fixup/squash, we need to edit the
5110 * commit message, the current fixup list and count, and if it
5111 * was the last fixup/squash in the chain, we need to clean up
5112 * the commit message and if there was a squash, let the user
5113 * edit it.
5114 */
Johannes Schindelin10d2f352018-08-31 16:45:04 -07005115 if (!is_clean || !opts->current_fixup_count)
5116 ; /* this is not the final fixup */
Junio C Hamano87ae8a12018-09-24 10:30:45 -07005117 else if (!oideq(&head, &to_amend) ||
Johannes Schindelin10d2f352018-08-31 16:45:04 -07005118 !file_exists(rebase_path_stopped_sha())) {
5119 /* was a final fixup or squash done manually? */
5120 if (!is_fixup(peek_command(todo_list, 0))) {
5121 unlink(rebase_path_fixup_msg());
5122 unlink(rebase_path_squash_msg());
5123 unlink(rebase_path_current_fixups());
5124 strbuf_reset(&opts->current_fixups);
5125 opts->current_fixup_count = 0;
5126 }
5127 } else {
5128 /* we are in a fixup/squash chain */
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005129 const char *p = opts->current_fixups.buf;
5130 int len = opts->current_fixups.len;
5131
5132 opts->current_fixup_count--;
5133 if (!len)
5134 BUG("Incorrect current_fixups:\n%s", p);
5135 while (len && p[len - 1] != '\n')
5136 len--;
5137 strbuf_setlen(&opts->current_fixups, len);
5138 if (write_message(p, len, rebase_path_current_fixups(),
5139 0) < 0)
5140 return error(_("could not write file: '%s'"),
5141 rebase_path_current_fixups());
5142
5143 /*
5144 * If a fixup/squash in a fixup/squash chain failed, the
5145 * commit message is already correct, no need to commit
5146 * it again.
5147 *
5148 * Only if it is the final command in the fixup/squash
5149 * chain, and only if the chain is longer than a single
5150 * fixup/squash command (which was just skipped), do we
5151 * actually need to re-commit with a cleaned up commit
5152 * message.
5153 */
5154 if (opts->current_fixup_count > 0 &&
5155 !is_fixup(peek_command(todo_list, 0))) {
5156 final_fixup = 1;
5157 /*
5158 * If there was not a single "squash" in the
5159 * chain, we only need to clean up the commit
5160 * message, no need to bother the user with
5161 * opening the commit message in the editor.
5162 */
5163 if (!starts_with(p, "squash ") &&
5164 !strstr(p, "\nsquash "))
5165 flags = (flags & ~EDIT_MSG) | CLEANUP_MSG;
5166 } else if (is_fixup(peek_command(todo_list, 0))) {
5167 /*
5168 * We need to update the squash message to skip
5169 * the latest commit message.
5170 */
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005171 int res = 0;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005172 struct commit *commit;
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005173 const char *msg;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005174 const char *path = rebase_path_squash_msg();
Doan Tran Cong Danhb3757442019-11-08 16:43:48 +07005175 const char *encoding = get_commit_output_encoding();
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005176
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005177 if (parse_head(r, &commit))
5178 return error(_("could not parse HEAD"));
5179
5180 p = repo_logmsg_reencode(r, commit, NULL, encoding);
5181 if (!p) {
5182 res = error(_("could not parse commit %s"),
5183 oid_to_hex(&commit->object.oid));
5184 goto unuse_commit_buffer;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005185 }
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005186 find_commit_subject(p, &msg);
5187 if (write_message(msg, strlen(msg), path, 0)) {
5188 res = error(_("could not write file: "
5189 "'%s'"), path);
5190 goto unuse_commit_buffer;
5191 }
5192 unuse_commit_buffer:
5193 repo_unuse_commit_buffer(r, commit, p);
5194 if (res)
5195 return res;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005196 }
5197 }
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005198
5199 strbuf_release(&rev);
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01005200 flags |= AMEND_MSG;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005201 }
5202
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005203 if (is_clean) {
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00005204 if (refs_ref_exists(get_main_ref_store(r),
5205 "CHERRY_PICK_HEAD") &&
5206 refs_delete_ref(get_main_ref_store(r), "",
Patrick Steinhardt821f6632024-01-19 11:39:59 +01005207 "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF))
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005208 return error(_("could not remove CHERRY_PICK_HEAD"));
Phillip Woode5ee33e2021-08-12 13:42:09 +00005209 if (unlink(git_path_merge_msg(r)) && errno != ENOENT)
5210 return error_errno(_("could not remove '%s'"),
5211 git_path_merge_msg(r));
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005212 if (!final_fixup)
5213 return 0;
5214 }
5215
Jeff King20f4b042020-09-30 08:29:31 -04005216 if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005217 opts, flags))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005218 return error(_("could not commit staged changes."));
5219 unlink(rebase_path_amend());
Nguyễn Thái Ngọc Duy34e77712019-06-27 16:28:52 +07005220 unlink(git_path_merge_head(r));
Patrick Steinhardtfd7c6ff2024-01-19 11:40:09 +01005221 refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
5222 NULL, REF_NO_DEREF);
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005223 if (final_fixup) {
5224 unlink(rebase_path_fixup_msg());
5225 unlink(rebase_path_squash_msg());
5226 }
5227 if (opts->current_fixup_count > 0) {
5228 /*
5229 * Whether final fixup or not, we just cleaned up the commit
5230 * message...
5231 */
5232 unlink(rebase_path_current_fixups());
5233 strbuf_reset(&opts->current_fixups);
5234 opts->current_fixup_count = 0;
5235 }
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005236 return 0;
5237}
5238
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005239int sequencer_continue(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305240{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005241 struct todo_list todo_list = TODO_LIST_INIT;
5242 int res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305243
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005244 if (read_and_refresh_cache(r, opts))
Johannes Schindelin28635842016-10-21 14:24:55 +02005245 return -1;
5246
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005247 if (read_populate_opts(opts))
5248 return -1;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005249 if (is_rebase_i(opts)) {
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01005250 if ((res = read_populate_todo(r, &todo_list, opts)))
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005251 goto release_todo_list;
Alban Gruin5a5445d2020-01-28 22:12:46 +01005252
5253 if (file_exists(rebase_path_dropped())) {
5254 if ((res = todo_list_check_against_backup(r, &todo_list)))
5255 goto release_todo_list;
5256
5257 unlink(rebase_path_dropped());
5258 }
5259
Phillip Woodd188a602022-11-09 14:21:57 +00005260 opts->reflog_message = reflog_message(opts, "continue", NULL);
Alban Gruinf6b94132019-11-29 00:02:03 +01005261 if (commit_staged_changes(r, opts, &todo_list)) {
5262 res = -1;
5263 goto release_todo_list;
5264 }
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005265 } else if (!file_exists(get_todo_path(opts)))
Elijah Newren39edfd52021-03-31 06:52:20 +00005266 return continue_single_pick(r, opts);
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01005267 else if ((res = read_populate_todo(r, &todo_list, opts)))
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005268 goto release_todo_list;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305269
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005270 if (!is_rebase_i(opts)) {
5271 /* Verify that the conflict has been resolved */
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00005272 if (refs_ref_exists(get_main_ref_store(r),
5273 "CHERRY_PICK_HEAD") ||
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00005274 refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
Elijah Newren39edfd52021-03-31 06:52:20 +00005275 res = continue_single_pick(r, opts);
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005276 if (res)
5277 goto release_todo_list;
5278 }
Nguyễn Thái Ngọc Duyffc00a42018-11-10 06:49:04 +01005279 if (index_differs_from(r, "HEAD", NULL, 0)) {
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07005280 res = error_dirty_index(r, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005281 goto release_todo_list;
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005282 }
5283 todo_list.current++;
Johannes Schindelinca98c6d2017-01-02 16:28:20 +01005284 } else if (file_exists(rebase_path_stopped_sha())) {
5285 struct strbuf buf = STRBUF_INIT;
5286 struct object_id oid;
5287
Denton Liu3442c3d2020-04-07 10:27:52 -04005288 if (read_oneliner(&buf, rebase_path_stopped_sha(),
5289 READ_ONELINER_SKIP_IF_EMPTY) &&
Junio C Hamano0512eab2020-09-24 22:49:12 -07005290 !get_oid_hex(buf.buf, &oid))
Johannes Schindelinca98c6d2017-01-02 16:28:20 +01005291 record_in_rewritten(&oid, peek_command(&todo_list, 0));
5292 strbuf_release(&buf);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305293 }
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005294
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005295 res = pick_commits(r, &todo_list, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005296release_todo_list:
5297 todo_list_release(&todo_list);
5298 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305299}
5300
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005301static int single_pick(struct repository *r,
5302 struct commit *cmit,
5303 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305304{
Phillip Wooda47ba3c2019-08-19 02:18:22 -07005305 int check_todo;
Charvi Mendirattaae70e342021-01-29 23:50:45 +05305306 struct todo_item item;
5307
5308 item.command = opts->action == REPLAY_PICK ?
5309 TODO_PICK : TODO_REVERT;
5310 item.commit = cmit;
Phillip Wooda47ba3c2019-08-19 02:18:22 -07005311
Phillip Woodd188a602022-11-09 14:21:57 +00005312 opts->reflog_message = sequencer_reflog_action(opts);
Charvi Mendirattaae70e342021-01-29 23:50:45 +05305313 return do_pick_commit(r, &item, opts, 0, &check_todo);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305314}
5315
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005316int sequencer_pick_revisions(struct repository *r,
5317 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305318{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005319 struct todo_list todo_list = TODO_LIST_INIT;
brian m. carlson1e43ed92017-05-06 22:10:09 +00005320 struct object_id oid;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005321 int i, res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305322
Johannes Schindelin28635842016-10-21 14:24:55 +02005323 assert(opts->revs);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005324 if (read_and_refresh_cache(r, opts))
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02005325 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305326
Miklos Vajna21246db2013-04-11 15:06:52 +02005327 for (i = 0; i < opts->revs->pending.nr; i++) {
brian m. carlson1e43ed92017-05-06 22:10:09 +00005328 struct object_id oid;
Miklos Vajna21246db2013-04-11 15:06:52 +02005329 const char *name = opts->revs->pending.objects[i].name;
5330
5331 /* This happens when using --stdin. */
5332 if (!strlen(name))
5333 continue;
5334
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005335 if (!repo_get_oid(r, name, &oid)) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005336 if (!lookup_commit_reference_gently(r, &oid, 1)) {
5337 enum object_type type = oid_object_info(r,
Stefan Beller0df8e962018-04-25 11:20:59 -07005338 &oid,
brian m. carlsonabef9022018-03-12 02:27:46 +00005339 NULL);
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005340 return error(_("%s: can't cherry-pick a %s"),
Brandon Williamsdebca9d2018-02-14 10:59:24 -08005341 name, type_name(type));
Junio C Hamano7c0b0d82013-05-09 13:27:49 -07005342 }
Miklos Vajna21246db2013-04-11 15:06:52 +02005343 } else
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005344 return error(_("%s: bad revision"), name);
Miklos Vajna21246db2013-04-11 15:06:52 +02005345 }
5346
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305347 /*
5348 * If we were called as "git cherry-pick <commit>", just
5349 * cherry-pick/revert it, set CHERRY_PICK_HEAD /
5350 * REVERT_HEAD, and don't touch the sequencer state.
5351 * This means it is possible to cherry-pick in the middle
5352 * of a cherry-pick sequence.
5353 */
5354 if (opts->revs->cmdline.nr == 1 &&
5355 opts->revs->cmdline.rev->whence == REV_CMD_REV &&
5356 opts->revs->no_walk &&
5357 !opts->revs->cmdline.rev->flags) {
5358 struct commit *cmit;
5359 if (prepare_revision_walk(opts->revs))
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005360 return error(_("revision walk setup failed"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305361 cmit = get_revision(opts->revs);
Jeff Kingc5e358d2018-07-10 00:32:08 -04005362 if (!cmit)
5363 return error(_("empty commit set passed"));
5364 if (get_revision(opts->revs))
5365 BUG("unexpected extra commit from walk");
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005366 return single_pick(r, cmit, opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305367 }
5368
5369 /*
5370 * Start a new cherry-pick/ revert sequence; but
5371 * first, make sure that an existing one isn't in
5372 * progress
5373 */
5374
Johannes Schindelin34b05282016-09-09 16:37:15 +02005375 if (walk_revs_populate_todo(&todo_list, opts) ||
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05305376 create_seq_dir(r) < 0)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305377 return -1;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005378 if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
Johannes Schindelin93b3df62016-10-21 14:26:25 +02005379 return error(_("can't revert as initial commit"));
brian m. carlson1e43ed92017-05-06 22:10:09 +00005380 if (save_head(oid_to_hex(&oid)))
Johannes Schindelin311fd392016-09-09 16:37:47 +02005381 return -1;
Johannes Schindelin88d5a272016-09-09 16:37:53 +02005382 if (save_opts(opts))
5383 return -1;
Stephan Beyer1e412292016-12-07 22:51:32 +01005384 update_abort_safety_file();
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005385 res = pick_commits(r, &todo_list, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005386 todo_list_release(&todo_list);
5387 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305388}
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005389
Jeff King66e83d92018-08-22 20:50:51 -04005390void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005391{
Brandon Caseybab4d102013-02-12 02:17:35 -08005392 unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005393 struct strbuf sob = STRBUF_INIT;
Brandon Caseybab4d102013-02-12 02:17:35 -08005394 int has_footer;
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005395
5396 strbuf_addstr(&sob, sign_off_header);
William Hubbs39ab4d02019-02-04 12:48:50 -06005397 strbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005398 strbuf_addch(&sob, '\n');
Brandon Caseybab4d102013-02-12 02:17:35 -08005399
Jonathan Tan44dc7382017-04-26 13:50:03 -07005400 if (!ignore_footer)
5401 strbuf_complete_line(msgbuf);
5402
Brandon Caseybab4d102013-02-12 02:17:35 -08005403 /*
5404 * If the whole message buffer is equal to the sob, pretend that we
5405 * found a conforming footer with a matching sob
5406 */
5407 if (msgbuf->len - ignore_footer == sob.len &&
5408 !strncmp(msgbuf->buf, sob.buf, sob.len))
5409 has_footer = 3;
5410 else
5411 has_footer = has_conforming_footer(msgbuf, &sob, ignore_footer);
5412
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005413 if (!has_footer) {
5414 const char *append_newlines = NULL;
5415 size_t len = msgbuf->len - ignore_footer;
5416
Brandon Casey8c613fd2013-02-22 14:05:27 -08005417 if (!len) {
5418 /*
5419 * The buffer is completely empty. Leave foom for
5420 * the title and body to be filled in by the user.
5421 */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005422 append_newlines = "\n\n";
Brandon Casey8c613fd2013-02-22 14:05:27 -08005423 } else if (len == 1) {
5424 /*
5425 * Buffer contains a single newline. Add another
5426 * so that we leave room for the title and body.
5427 */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005428 append_newlines = "\n";
Brandon Casey8c613fd2013-02-22 14:05:27 -08005429 } else if (msgbuf->buf[len - 2] != '\n') {
5430 /*
5431 * Buffer ends with a single newline. Add another
5432 * so that there is an empty line between the message
5433 * body and the sob.
5434 */
5435 append_newlines = "\n";
5436 } /* else, the buffer already ends with two newlines. */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005437
5438 if (append_newlines)
5439 strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
5440 append_newlines, strlen(append_newlines));
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005441 }
Brandon Caseybab4d102013-02-12 02:17:35 -08005442
5443 if (has_footer != 3 && (!no_dup_sob || has_footer != 2))
5444 strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
5445 sob.buf, sob.len);
5446
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005447 strbuf_release(&sob);
5448}
Johannes Schindelin62db5242017-07-14 16:44:58 +02005449
Johannes Schindelin1644c732018-04-25 14:29:03 +02005450struct labels_entry {
5451 struct hashmap_entry entry;
5452 char label[FLEX_ARRAY];
5453};
5454
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +02005455static int labels_cmp(const void *fndata UNUSED,
Jeff King02c3c592022-08-19 06:08:46 -04005456 const struct hashmap_entry *eptr,
Eric Wong939af162019-10-06 23:30:37 +00005457 const struct hashmap_entry *entry_or_key, const void *key)
Johannes Schindelin1644c732018-04-25 14:29:03 +02005458{
Eric Wong939af162019-10-06 23:30:37 +00005459 const struct labels_entry *a, *b;
5460
5461 a = container_of(eptr, const struct labels_entry, entry);
5462 b = container_of(entry_or_key, const struct labels_entry, entry);
5463
Johannes Schindelin1644c732018-04-25 14:29:03 +02005464 return key ? strcmp(a->label, key) : strcmp(a->label, b->label);
5465}
5466
5467struct string_entry {
5468 struct oidmap_entry entry;
5469 char string[FLEX_ARRAY];
5470};
5471
5472struct label_state {
5473 struct oidmap commit2label;
5474 struct hashmap labels;
5475 struct strbuf buf;
Johannes Schindelinac300bd2023-08-10 16:35:00 +00005476 int max_label_length;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005477};
5478
5479static const char *label_oid(struct object_id *oid, const char *label,
5480 struct label_state *state)
5481{
5482 struct labels_entry *labels_entry;
5483 struct string_entry *string_entry;
5484 struct object_id dummy;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005485 int i;
5486
5487 string_entry = oidmap_get(&state->commit2label, oid);
5488 if (string_entry)
5489 return string_entry->string;
5490
5491 /*
5492 * For "uninteresting" commits, i.e. commits that are not to be
5493 * rebased, and which can therefore not be labeled, we use a unique
5494 * abbreviation of the commit name. This is slightly more complicated
Ævar Arnfjörð Bjarmasonc7c33f52023-03-28 15:58:57 +02005495 * than calling repo_find_unique_abbrev() because we also need to make
Johannes Schindelin1644c732018-04-25 14:29:03 +02005496 * sure that the abbreviation does not conflict with any other
5497 * label.
5498 *
5499 * We disallow "interesting" commits to be labeled by a string that
5500 * is a valid full-length hash, to ensure that we always can find an
5501 * abbreviation for any uninteresting commit's names that does not
5502 * clash with any other label.
5503 */
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005504 strbuf_reset(&state->buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005505 if (!label) {
5506 char *p;
5507
brian m. carlson4439c7a2019-08-18 20:04:16 +00005508 strbuf_grow(&state->buf, GIT_MAX_HEXSZ);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005509 label = p = state->buf.buf;
5510
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02005511 repo_find_unique_abbrev_r(the_repository, p, oid,
5512 default_abbrev);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005513
5514 /*
5515 * We may need to extend the abbreviated hash so that there is
5516 * no conflicting label.
5517 */
5518 if (hashmap_get_from_hash(&state->labels, strihash(p), p)) {
5519 size_t i = strlen(p) + 1;
5520
5521 oid_to_hex_r(p, oid);
brian m. carlson4439c7a2019-08-18 20:04:16 +00005522 for (; i < the_hash_algo->hexsz; i++) {
Johannes Schindelin1644c732018-04-25 14:29:03 +02005523 char save = p[i];
5524 p[i] = '\0';
5525 if (!hashmap_get_from_hash(&state->labels,
5526 strihash(p), p))
5527 break;
5528 p[i] = save;
5529 }
5530 }
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005531 } else {
Johannes Schindelin1644c732018-04-25 14:29:03 +02005532 struct strbuf *buf = &state->buf;
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +00005533 int label_is_utf8 = 1; /* start with this assumption */
Johannes Schindelinac300bd2023-08-10 16:35:00 +00005534 size_t max_len = buf->len + state->max_label_length;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005535
Matthew Rogerscd552222019-11-17 23:16:10 +00005536 /*
5537 * Sanitize labels by replacing non-alpha-numeric characters
5538 * (including white-space ones) by dashes, as they might be
5539 * illegal in file names (and hence in ref names).
5540 *
5541 * Note that we retain non-ASCII UTF-8 characters (identified
5542 * via the most significant bit). They should be all acceptable
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +00005543 * in file names.
5544 *
5545 * As we will use the labels as names of (loose) refs, it is
5546 * vital that the name not be longer than the maximum component
5547 * size of the file system (`NAME_MAX`). We are careful to
5548 * truncate the label accordingly, allowing for the `.lock`
5549 * suffix and for the label to be UTF-8 encoded (i.e. we avoid
5550 * truncating in the middle of a character).
Matthew Rogerscd552222019-11-17 23:16:10 +00005551 */
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +00005552 for (; *label && buf->len + 1 < max_len; label++)
5553 if (isalnum(*label) ||
5554 (!label_is_utf8 && (*label & 0x80)))
Matthew Rogerscd552222019-11-17 23:16:10 +00005555 strbuf_addch(buf, *label);
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +00005556 else if (*label & 0x80) {
5557 const char *p = label;
5558
5559 utf8_width(&p, NULL);
5560 if (p) {
5561 if (buf->len + (p - label) > max_len)
5562 break;
5563 strbuf_add(buf, label, p - label);
5564 label = p - 1;
5565 } else {
5566 label_is_utf8 = 0;
5567 strbuf_addch(buf, *label);
5568 }
Matthew Rogerscd552222019-11-17 23:16:10 +00005569 /* avoid leading dash and double-dashes */
Mark Ruvald Pedersen7481d2b2023-08-10 16:34:59 +00005570 } else if (buf->len && buf->buf[buf->len - 1] != '-')
Matthew Rogerscd552222019-11-17 23:16:10 +00005571 strbuf_addch(buf, '-');
5572 if (!buf->len) {
5573 strbuf_addstr(buf, "rev-");
5574 strbuf_add_unique_abbrev(buf, oid, default_abbrev);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005575 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005576 label = buf->buf;
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005577
5578 if ((buf->len == the_hash_algo->hexsz &&
5579 !get_oid_hex(label, &dummy)) ||
5580 (buf->len == 1 && *label == '#') ||
5581 hashmap_get_from_hash(&state->labels,
5582 strihash(label), label)) {
5583 /*
5584 * If the label already exists, or if the label is a
5585 * valid full OID, or the label is a '#' (which we use
5586 * as a separator between merge heads and oneline), we
5587 * append a dash and a number to make it unique.
5588 */
5589 size_t len = buf->len;
5590
5591 for (i = 2; ; i++) {
5592 strbuf_setlen(buf, len);
5593 strbuf_addf(buf, "-%d", i);
5594 if (!hashmap_get_from_hash(&state->labels,
5595 strihash(buf->buf),
5596 buf->buf))
5597 break;
5598 }
5599
5600 label = buf->buf;
5601 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005602 }
5603
5604 FLEX_ALLOC_STR(labels_entry, label, label);
Eric Wongd22245a2019-10-06 23:30:27 +00005605 hashmap_entry_init(&labels_entry->entry, strihash(label));
Eric Wongb94e5c12019-10-06 23:30:29 +00005606 hashmap_add(&state->labels, &labels_entry->entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005607
5608 FLEX_ALLOC_STR(string_entry, string, label);
5609 oidcpy(&string_entry->entry.oid, oid);
5610 oidmap_put(&state->commit2label, string_entry);
5611
5612 return string_entry->string;
5613}
5614
5615static int make_script_with_merges(struct pretty_print_context *pp,
Alban Gruind358fc22019-03-05 20:17:56 +01005616 struct rev_info *revs, struct strbuf *out,
Johannes Schindelin1644c732018-04-25 14:29:03 +02005617 unsigned flags)
5618{
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005619 int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
Johannes Schindelin7543f6f2018-04-25 14:29:40 +02005620 int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
Johannes Schindeline1fac532019-07-31 08:18:49 -07005621 int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005622 int skipped_commit = 0;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005623 struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
5624 struct strbuf label = STRBUF_INIT;
5625 struct commit_list *commits = NULL, **tail = &commits, *iter;
5626 struct commit_list *tips = NULL, **tips_tail = &tips;
5627 struct commit *commit;
5628 struct oidmap commit2todo = OIDMAP_INIT;
5629 struct string_entry *entry;
5630 struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
5631 shown = OIDSET_INIT;
Johannes Schindelinac300bd2023-08-10 16:35:00 +00005632 struct label_state state =
5633 { OIDMAP_INIT, { NULL }, STRBUF_INIT, GIT_MAX_LABEL_LENGTH };
Johannes Schindelin1644c732018-04-25 14:29:03 +02005634
5635 int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
5636 const char *cmd_pick = abbr ? "p" : "pick",
5637 *cmd_label = abbr ? "l" : "label",
5638 *cmd_reset = abbr ? "t" : "reset",
5639 *cmd_merge = abbr ? "m" : "merge";
5640
Johannes Schindelinac300bd2023-08-10 16:35:00 +00005641 git_config_get_int("rebase.maxlabellength", &state.max_label_length);
5642
Johannes Schindelin1644c732018-04-25 14:29:03 +02005643 oidmap_init(&commit2todo, 0);
5644 oidmap_init(&state.commit2label, 0);
Eric Wong939af162019-10-06 23:30:37 +00005645 hashmap_init(&state.labels, labels_cmp, NULL, 0);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005646 strbuf_init(&state.buf, 32);
5647
5648 if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
Doan Tran Cong Danhe02058a2019-11-18 18:57:47 +07005649 struct labels_entry *onto_label_entry;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005650 struct object_id *oid = &revs->cmdline.rev[0].item->oid;
5651 FLEX_ALLOC_STR(entry, string, "onto");
5652 oidcpy(&entry->entry.oid, oid);
5653 oidmap_put(&state.commit2label, entry);
Doan Tran Cong Danhe02058a2019-11-18 18:57:47 +07005654
5655 FLEX_ALLOC_STR(onto_label_entry, label, "onto");
5656 hashmap_entry_init(&onto_label_entry->entry, strihash("onto"));
5657 hashmap_add(&state.labels, &onto_label_entry->entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005658 }
5659
5660 /*
5661 * First phase:
5662 * - get onelines for all commits
5663 * - gather all branch tips (i.e. 2nd or later parents of merges)
5664 * - label all branch tips
5665 */
5666 while ((commit = get_revision(revs))) {
5667 struct commit_list *to_merge;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005668 const char *p1, *p2;
5669 struct object_id *oid;
5670 int is_empty;
5671
5672 tail = &commit_list_insert(commit, tail)->next;
5673 oidset_insert(&interesting, &commit->object.oid);
5674
5675 is_empty = is_original_commit_empty(commit);
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005676 if (!is_empty && (commit->object.flags & PATCHSAME)) {
5677 if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
5678 warning(_("skipped previously applied commit %s"),
Jeff Kingcb646ff2023-08-29 19:43:39 -04005679 short_commit_name(the_repository, commit));
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005680 skipped_commit = 1;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005681 continue;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005682 }
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005683 if (is_empty && !keep_empty)
5684 continue;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005685
5686 strbuf_reset(&oneline);
5687 pretty_print_commit(pp, commit, &oneline);
5688
5689 to_merge = commit->parents ? commit->parents->next : NULL;
5690 if (!to_merge) {
5691 /* non-merge commit: easy case */
5692 strbuf_reset(&buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005693 strbuf_addf(&buf, "%s %s %s", cmd_pick,
5694 oid_to_hex(&commit->object.oid),
5695 oneline.buf);
Elijah Newren1b5735f2020-04-11 02:44:24 +00005696 if (is_empty)
Jeff Kingf99e1d92024-03-12 05:17:34 -04005697 strbuf_addf(&buf, " %s empty",
5698 comment_line_str);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005699
5700 FLEX_ALLOC_STR(entry, string, buf.buf);
5701 oidcpy(&entry->entry.oid, &commit->object.oid);
5702 oidmap_put(&commit2todo, entry);
5703
5704 continue;
5705 }
5706
Johannes Schindelin1644c732018-04-25 14:29:03 +02005707 /* Create a label */
5708 strbuf_reset(&label);
5709 if (skip_prefix(oneline.buf, "Merge ", &p1) &&
5710 (p1 = strchr(p1, '\'')) &&
5711 (p2 = strchr(++p1, '\'')))
5712 strbuf_add(&label, p1, p2 - p1);
5713 else if (skip_prefix(oneline.buf, "Merge pull request ",
5714 &p1) &&
5715 (p1 = strstr(p1, " from ")))
5716 strbuf_addstr(&label, p1 + strlen(" from "));
5717 else
5718 strbuf_addbuf(&label, &oneline);
5719
Johannes Schindelin1644c732018-04-25 14:29:03 +02005720 strbuf_reset(&buf);
5721 strbuf_addf(&buf, "%s -C %s",
5722 cmd_merge, oid_to_hex(&commit->object.oid));
5723
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01005724 /* label the tips of merged branches */
5725 for (; to_merge; to_merge = to_merge->next) {
5726 oid = &to_merge->item->object.oid;
5727 strbuf_addch(&buf, ' ');
Johannes Schindelin1644c732018-04-25 14:29:03 +02005728
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01005729 if (!oidset_contains(&interesting, oid)) {
5730 strbuf_addstr(&buf, label_oid(oid, NULL,
5731 &state));
5732 continue;
5733 }
5734
Johannes Schindelin1644c732018-04-25 14:29:03 +02005735 tips_tail = &commit_list_insert(to_merge->item,
5736 tips_tail)->next;
5737
5738 strbuf_addstr(&buf, label_oid(oid, label.buf, &state));
5739 }
5740 strbuf_addf(&buf, " # %s", oneline.buf);
5741
5742 FLEX_ALLOC_STR(entry, string, buf.buf);
5743 oidcpy(&entry->entry.oid, &commit->object.oid);
5744 oidmap_put(&commit2todo, entry);
5745 }
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005746 if (skipped_commit)
5747 advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
5748 _("use --reapply-cherry-picks to include skipped commits"));
Johannes Schindelin1644c732018-04-25 14:29:03 +02005749
5750 /*
5751 * Second phase:
5752 * - label branch points
5753 * - add HEAD to the branch tips
5754 */
5755 for (iter = commits; iter; iter = iter->next) {
5756 struct commit_list *parent = iter->item->parents;
5757 for (; parent; parent = parent->next) {
5758 struct object_id *oid = &parent->item->object.oid;
5759 if (!oidset_contains(&interesting, oid))
5760 continue;
René Scharfe6e8fc702018-10-03 15:06:49 +02005761 if (oidset_insert(&child_seen, oid))
Johannes Schindelin1644c732018-04-25 14:29:03 +02005762 label_oid(oid, "branch-point", &state);
5763 }
5764
Elijah Newren15beaaa2019-11-05 17:07:23 +00005765 /* Add HEAD as implicit "tip of branch" */
Johannes Schindelin1644c732018-04-25 14:29:03 +02005766 if (!iter->next)
5767 tips_tail = &commit_list_insert(iter->item,
5768 tips_tail)->next;
5769 }
5770
5771 /*
5772 * Third phase: output the todo list. This is a bit tricky, as we
5773 * want to avoid jumping back and forth between revisions. To
5774 * accomplish that goal, we walk backwards from the branch tips,
5775 * gathering commits not yet shown, reversing the list on the fly,
5776 * then outputting that list (labeling revisions as needed).
5777 */
Alban Gruind358fc22019-03-05 20:17:56 +01005778 strbuf_addf(out, "%s onto\n", cmd_label);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005779 for (iter = tips; iter; iter = iter->next) {
5780 struct commit_list *list = NULL, *iter2;
5781
5782 commit = iter->item;
5783 if (oidset_contains(&shown, &commit->object.oid))
5784 continue;
5785 entry = oidmap_get(&state.commit2label, &commit->object.oid);
5786
5787 if (entry)
Jeff Kingf99e1d92024-03-12 05:17:34 -04005788 strbuf_addf(out, "\n%s Branch %s\n", comment_line_str, entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005789 else
Alban Gruind358fc22019-03-05 20:17:56 +01005790 strbuf_addch(out, '\n');
Johannes Schindelin1644c732018-04-25 14:29:03 +02005791
5792 while (oidset_contains(&interesting, &commit->object.oid) &&
5793 !oidset_contains(&shown, &commit->object.oid)) {
5794 commit_list_insert(commit, &list);
5795 if (!commit->parents) {
5796 commit = NULL;
5797 break;
5798 }
5799 commit = commit->parents->item;
5800 }
5801
5802 if (!commit)
Alban Gruind358fc22019-03-05 20:17:56 +01005803 strbuf_addf(out, "%s %s\n", cmd_reset,
Johannes Schindeline1fac532019-07-31 08:18:49 -07005804 rebase_cousins || root_with_onto ?
5805 "onto" : "[new root]");
Johannes Schindelin1644c732018-04-25 14:29:03 +02005806 else {
5807 const char *to = NULL;
5808
5809 entry = oidmap_get(&state.commit2label,
5810 &commit->object.oid);
5811 if (entry)
5812 to = entry->string;
Johannes Schindelin7543f6f2018-04-25 14:29:40 +02005813 else if (!rebase_cousins)
5814 to = label_oid(&commit->object.oid, NULL,
5815 &state);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005816
5817 if (!to || !strcmp(to, "onto"))
Alban Gruind358fc22019-03-05 20:17:56 +01005818 strbuf_addf(out, "%s onto\n", cmd_reset);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005819 else {
5820 strbuf_reset(&oneline);
5821 pretty_print_commit(pp, commit, &oneline);
Alban Gruind358fc22019-03-05 20:17:56 +01005822 strbuf_addf(out, "%s %s # %s\n",
5823 cmd_reset, to, oneline.buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005824 }
5825 }
5826
5827 for (iter2 = list; iter2; iter2 = iter2->next) {
5828 struct object_id *oid = &iter2->item->object.oid;
5829 entry = oidmap_get(&commit2todo, oid);
5830 /* only show if not already upstream */
5831 if (entry)
Alban Gruind358fc22019-03-05 20:17:56 +01005832 strbuf_addf(out, "%s\n", entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005833 entry = oidmap_get(&state.commit2label, oid);
5834 if (entry)
Alban Gruind358fc22019-03-05 20:17:56 +01005835 strbuf_addf(out, "%s %s\n",
5836 cmd_label, entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005837 oidset_insert(&shown, oid);
5838 }
5839
5840 free_commit_list(list);
5841 }
5842
5843 free_commit_list(commits);
5844 free_commit_list(tips);
5845
5846 strbuf_release(&label);
5847 strbuf_release(&oneline);
5848 strbuf_release(&buf);
5849
5850 oidmap_free(&commit2todo, 1);
5851 oidmap_free(&state.commit2label, 1);
Elijah Newren6da1a252020-11-02 18:55:05 +00005852 hashmap_clear_and_free(&state.labels, struct labels_entry, entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005853 strbuf_release(&state.buf);
5854
5855 return 0;
5856}
5857
Alban Gruind358fc22019-03-05 20:17:56 +01005858int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
5859 const char **argv, unsigned flags)
Johannes Schindelin62db5242017-07-14 16:44:58 +02005860{
5861 char *format = NULL;
5862 struct pretty_print_context pp = {0};
Johannes Schindelin62db5242017-07-14 16:44:58 +02005863 struct rev_info revs;
5864 struct commit *commit;
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005865 int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
Liam Beguind8ae6c82017-12-05 12:52:34 -05005866 const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
Johannes Schindelin1644c732018-04-25 14:29:03 +02005867 int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
Jonathan Tan0fcb4f62020-04-11 02:44:27 +00005868 int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005869 int skipped_commit = 0;
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005870 int ret = 0;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005871
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005872 repo_init_revisions(r, &revs, NULL);
Johannes Schindelin62db5242017-07-14 16:44:58 +02005873 revs.verbose_header = 1;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005874 if (!rebase_merges)
5875 revs.max_parents = 1;
Jonathan Tan0fcb4f62020-04-11 02:44:27 +00005876 revs.cherry_mark = !reapply_cherry_picks;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005877 revs.limited = 1;
5878 revs.reverse = 1;
5879 revs.right_only = 1;
5880 revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
5881 revs.topo_order = 1;
5882
5883 revs.pretty_given = 1;
5884 git_config_get_string("rebase.instructionFormat", &format);
5885 if (!format || !*format) {
5886 free(format);
5887 format = xstrdup("%s");
5888 }
5889 get_commit_format(format, &revs);
5890 free(format);
5891 pp.fmt = revs.commit_format;
5892 pp.output_encoding = get_log_output_encoding();
5893
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005894 if (setup_revisions(argc, argv, &revs, NULL) > 1) {
5895 ret = error(_("make_script: unhandled options"));
5896 goto cleanup;
5897 }
Johannes Schindelin62db5242017-07-14 16:44:58 +02005898
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005899 if (prepare_revision_walk(&revs) < 0) {
5900 ret = error(_("make_script: error preparing revisions"));
5901 goto cleanup;
5902 }
Johannes Schindelin62db5242017-07-14 16:44:58 +02005903
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005904 if (rebase_merges) {
5905 ret = make_script_with_merges(&pp, &revs, out, flags);
5906 goto cleanup;
5907 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005908
Johannes Schindelin62db5242017-07-14 16:44:58 +02005909 while ((commit = get_revision(&revs))) {
Elijah Newrend48e5e22020-02-15 21:36:24 +00005910 int is_empty = is_original_commit_empty(commit);
Phillip Wood76ea2352018-03-20 10:03:14 +00005911
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005912 if (!is_empty && (commit->object.flags & PATCHSAME)) {
5913 if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
5914 warning(_("skipped previously applied commit %s"),
Jeff Kingcb646ff2023-08-29 19:43:39 -04005915 short_commit_name(r, commit));
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005916 skipped_commit = 1;
Phillip Wood76ea2352018-03-20 10:03:14 +00005917 continue;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005918 }
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005919 if (is_empty && !keep_empty)
5920 continue;
Alban Gruind358fc22019-03-05 20:17:56 +01005921 strbuf_addf(out, "%s %s ", insn,
Liam Beguind8ae6c82017-12-05 12:52:34 -05005922 oid_to_hex(&commit->object.oid));
Alban Gruind358fc22019-03-05 20:17:56 +01005923 pretty_print_commit(&pp, commit, out);
Elijah Newren1b5735f2020-04-11 02:44:24 +00005924 if (is_empty)
Jeff Kingf99e1d92024-03-12 05:17:34 -04005925 strbuf_addf(out, " %s empty", comment_line_str);
Alban Gruind358fc22019-03-05 20:17:56 +01005926 strbuf_addch(out, '\n');
Johannes Schindelin62db5242017-07-14 16:44:58 +02005927 }
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005928 if (skipped_commit)
5929 advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
5930 _("use --reapply-cherry-picks to include skipped commits"));
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005931cleanup:
5932 release_revisions(&revs);
5933 return ret;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005934}
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005935
Liam Beguin0cce4a22017-12-05 12:52:33 -05005936/*
5937 * Add commands after pick and (series of) squash/fixup commands
5938 * in the todo list.
5939 */
Johannes Schindelin17919c32021-09-07 21:05:12 +00005940static void todo_list_add_exec_commands(struct todo_list *todo_list,
5941 struct string_list *commands)
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005942{
Alban Gruin683153a2019-03-05 20:17:54 +01005943 struct strbuf *buf = &todo_list->buf;
5944 size_t base_offset = buf->len;
5945 int i, insert, nr = 0, alloc = 0;
5946 struct todo_item *items = NULL, *base_items = NULL;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005947
René Scharfeca56dad2021-03-13 17:17:22 +01005948 CALLOC_ARRAY(base_items, commands->nr);
Alban Gruin683153a2019-03-05 20:17:54 +01005949 for (i = 0; i < commands->nr; i++) {
5950 size_t command_len = strlen(commands->items[i].string);
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005951
Alban Gruin683153a2019-03-05 20:17:54 +01005952 strbuf_addstr(buf, commands->items[i].string);
5953 strbuf_addch(buf, '\n');
5954
5955 base_items[i].command = TODO_EXEC;
5956 base_items[i].offset_in_buf = base_offset;
Phillip Woode57d2c52023-01-12 16:50:01 +00005957 base_items[i].arg_offset = base_offset;
5958 base_items[i].arg_len = command_len;
Alban Gruin683153a2019-03-05 20:17:54 +01005959
5960 base_offset += command_len + 1;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005961 }
5962
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005963 /*
5964 * Insert <commands> after every pick. Here, fixup/squash chains
5965 * are considered part of the pick, so we insert the commands *after*
5966 * those chains if there are any.
Alban Gruin683153a2019-03-05 20:17:54 +01005967 *
Elijah Newren15beaaa2019-11-05 17:07:23 +00005968 * As we insert the exec commands immediately after rearranging
Alban Gruin683153a2019-03-05 20:17:54 +01005969 * any fixups and before the user edits the list, a fixup chain
5970 * can never contain comments (any comments are empty picks that
5971 * have been commented out because the user did not specify
5972 * --keep-empty). So, it is safe to insert an exec command
5973 * without looking at the command following a comment.
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005974 */
Alban Gruin683153a2019-03-05 20:17:54 +01005975 insert = 0;
5976 for (i = 0; i < todo_list->nr; i++) {
5977 enum todo_command command = todo_list->items[i].command;
5978 if (insert && !is_fixup(command)) {
5979 ALLOC_GROW(items, nr + commands->nr, alloc);
5980 COPY_ARRAY(items + nr, base_items, commands->nr);
5981 nr += commands->nr;
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005982
Alban Gruin683153a2019-03-05 20:17:54 +01005983 insert = 0;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005984 }
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005985
Alban Gruin683153a2019-03-05 20:17:54 +01005986 ALLOC_GROW(items, nr + 1, alloc);
5987 items[nr++] = todo_list->items[i];
5988
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005989 if (command == TODO_PICK || command == TODO_MERGE)
Alban Gruin683153a2019-03-05 20:17:54 +01005990 insert = 1;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005991 }
Liam Beguin0cce4a22017-12-05 12:52:33 -05005992
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005993 /* insert or append final <commands> */
Elijah Newrencc9dcde2021-11-30 03:58:39 +00005994 if (insert) {
Alban Gruin683153a2019-03-05 20:17:54 +01005995 ALLOC_GROW(items, nr + commands->nr, alloc);
5996 COPY_ARRAY(items + nr, base_items, commands->nr);
5997 nr += commands->nr;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005998 }
5999
Alban Gruin683153a2019-03-05 20:17:54 +01006000 free(base_items);
6001 FREE_AND_NULL(todo_list->items);
6002 todo_list->items = items;
6003 todo_list->nr = nr;
6004 todo_list->alloc = alloc;
6005}
6006
Jeff Kingcb646ff2023-08-29 19:43:39 -04006007static void todo_list_to_strbuf(struct repository *r,
6008 struct todo_list *todo_list,
Alban Gruin616d7742019-01-29 16:01:48 +01006009 struct strbuf *buf, int num, unsigned flags)
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006010{
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006011 struct todo_item *item;
Alban Gruin616d7742019-01-29 16:01:48 +01006012 int i, max = todo_list->nr;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006013
Alban Gruin616d7742019-01-29 16:01:48 +01006014 if (num > 0 && num < max)
6015 max = num;
6016
6017 for (item = todo_list->items, i = 0; i < max; i++, item++) {
Alban Gruin68e70902020-03-30 14:42:35 +02006018 char cmd;
6019
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006020 /* if the item is not a command write it and continue */
6021 if (item->command >= TODO_COMMENT) {
Alban Gruin616d7742019-01-29 16:01:48 +01006022 strbuf_addf(buf, "%.*s\n", item->arg_len,
Alban Gruincbef27d2019-01-29 16:01:47 +01006023 todo_item_get_arg(todo_list, item));
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006024 continue;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006025 }
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006026
6027 /* add command to the buffer */
Alban Gruin68e70902020-03-30 14:42:35 +02006028 cmd = command_to_char(item->command);
6029 if ((flags & TODO_LIST_ABBREVIATE_CMDS) && cmd)
6030 strbuf_addch(buf, cmd);
Liam Beguind8ae6c82017-12-05 12:52:34 -05006031 else
Alban Gruin616d7742019-01-29 16:01:48 +01006032 strbuf_addstr(buf, command_to_string(item->command));
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006033
6034 /* add commit id */
6035 if (item->commit) {
Liam Beguin313a48e2017-12-05 12:52:32 -05006036 const char *oid = flags & TODO_LIST_SHORTEN_IDS ?
Jeff Kingcb646ff2023-08-29 19:43:39 -04006037 short_commit_name(r, item->commit) :
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006038 oid_to_hex(&item->commit->object.oid);
6039
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05306040 if (item->command == TODO_FIXUP) {
6041 if (item->flags & TODO_EDIT_FIXUP_MSG)
6042 strbuf_addstr(buf, " -c");
6043 else if (item->flags & TODO_REPLACE_FIXUP_MSG) {
6044 strbuf_addstr(buf, " -C");
6045 }
6046 }
6047
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02006048 if (item->command == TODO_MERGE) {
6049 if (item->flags & TODO_EDIT_MERGE_MSG)
Alban Gruin616d7742019-01-29 16:01:48 +01006050 strbuf_addstr(buf, " -c");
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02006051 else
Alban Gruin616d7742019-01-29 16:01:48 +01006052 strbuf_addstr(buf, " -C");
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02006053 }
6054
Alban Gruin616d7742019-01-29 16:01:48 +01006055 strbuf_addf(buf, " %s", oid);
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006056 }
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02006057
Liam Beguin8dccc7a2017-12-05 12:52:30 -05006058 /* add all the rest */
Johannes Schindelinc7b4d792017-12-23 00:56:00 +01006059 if (!item->arg_len)
Alban Gruin616d7742019-01-29 16:01:48 +01006060 strbuf_addch(buf, '\n');
Johannes Schindelinc7b4d792017-12-23 00:56:00 +01006061 else
Alban Gruin616d7742019-01-29 16:01:48 +01006062 strbuf_addf(buf, " %.*s\n", item->arg_len,
Alban Gruincbef27d2019-01-29 16:01:47 +01006063 todo_item_get_arg(todo_list, item));
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006064 }
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02006065}
Johannes Schindelin94399942017-07-14 16:45:21 +02006066
Alban Gruin616d7742019-01-29 16:01:48 +01006067int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
6068 const char *file, const char *shortrevisions,
6069 const char *shortonto, int num, unsigned flags)
Johannes Schindelin94399942017-07-14 16:45:21 +02006070{
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01006071 int res;
Alban Gruin616d7742019-01-29 16:01:48 +01006072 struct strbuf buf = STRBUF_INIT;
Johannes Schindelin94399942017-07-14 16:45:21 +02006073
Alban Gruin616d7742019-01-29 16:01:48 +01006074 todo_list_to_strbuf(r, todo_list, &buf, num, flags);
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01006075 if (flags & TODO_LIST_APPEND_TODO_HELP)
Elijah Newrend48e5e22020-02-15 21:36:24 +00006076 append_todo_help(count_commands(todo_list),
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01006077 shortrevisions, shortonto, &buf);
Johannes Schindelin94399942017-07-14 16:45:21 +02006078
Alban Gruin616d7742019-01-29 16:01:48 +01006079 res = write_message(buf.buf, buf.len, file, 0);
Alban Gruincbef27d2019-01-29 16:01:47 +01006080 strbuf_release(&buf);
Johannes Schindelin94399942017-07-14 16:45:21 +02006081
6082 return res;
6083}
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006084
6085/* skip picking commits whose parents are unchanged */
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006086static int skip_unnecessary_picks(struct repository *r,
6087 struct todo_list *todo_list,
6088 struct object_id *base_oid)
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006089{
Alban Gruind4ed5d72018-08-10 18:51:36 +02006090 struct object_id *parent_oid;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006091 int i;
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006092
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006093 for (i = 0; i < todo_list->nr; i++) {
6094 struct todo_item *item = todo_list->items + i;
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006095
6096 if (item->command >= TODO_NOOP)
6097 continue;
6098 if (item->command != TODO_PICK)
6099 break;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02006100 if (repo_parse_commit(r, item->commit)) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006101 return error(_("could not parse commit '%s'"),
6102 oid_to_hex(&item->commit->object.oid));
6103 }
6104 if (!item->commit->parents)
6105 break; /* root commit */
6106 if (item->commit->parents->next)
6107 break; /* merge commit */
6108 parent_oid = &item->commit->parents->item->object.oid;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006109 if (!oideq(parent_oid, base_oid))
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006110 break;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006111 oidcpy(base_oid, &item->commit->object.oid);
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006112 }
6113 if (i > 0) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006114 const char *done_path = rebase_path_done();
6115
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006116 if (todo_list_write_to_file(r, todo_list, done_path, NULL, NULL, i, 0)) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006117 error_errno(_("could not write to '%s'"), done_path);
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006118 return -1;
6119 }
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006120
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006121 MOVE_ARRAY(todo_list->items, todo_list->items + i, todo_list->nr - i);
6122 todo_list->nr -= i;
6123 todo_list->current = 0;
Alban Gruin34065542019-11-24 18:43:29 +01006124 todo_list->done_nr += i;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006125
6126 if (is_fixup(peek_command(todo_list, 0)))
6127 record_in_rewritten(base_oid, peek_command(todo_list, 0));
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006128 }
6129
Johannes Schindelincdac2b02017-07-14 16:45:25 +02006130 return 0;
6131}
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006132
Derrick Stolee900b50c2022-07-19 18:33:39 +00006133struct todo_add_branch_context {
6134 struct todo_item *items;
6135 size_t items_nr;
6136 size_t items_alloc;
6137 struct strbuf *buf;
6138 struct commit *commit;
6139 struct string_list refs_to_oids;
6140};
6141
6142static int add_decorations_to_list(const struct commit *commit,
6143 struct todo_add_branch_context *ctx)
6144{
6145 const struct name_decoration *decoration = get_name_decoration(&commit->object);
Derrick Stoleeaa37f3e2022-07-19 18:33:43 +00006146 const char *head_ref = resolve_ref_unsafe("HEAD",
6147 RESOLVE_REF_READING,
6148 NULL,
6149 NULL);
Derrick Stolee900b50c2022-07-19 18:33:39 +00006150
6151 while (decoration) {
6152 struct todo_item *item;
6153 const char *path;
6154 size_t base_offset = ctx->buf->len;
6155
Derrick Stoleeaa37f3e2022-07-19 18:33:43 +00006156 /*
6157 * If the branch is the current HEAD, then it will be
6158 * updated by the default rebase behavior.
6159 */
6160 if (head_ref && !strcmp(head_ref, decoration->name)) {
6161 decoration = decoration->next;
6162 continue;
6163 }
6164
Derrick Stolee900b50c2022-07-19 18:33:39 +00006165 ALLOC_GROW(ctx->items,
6166 ctx->items_nr + 1,
6167 ctx->items_alloc);
6168 item = &ctx->items[ctx->items_nr];
6169 memset(item, 0, sizeof(*item));
6170
6171 /* If the branch is checked out, then leave a comment instead. */
6172 if ((path = branch_checked_out(decoration->name))) {
6173 item->command = TODO_COMMENT;
6174 strbuf_addf(ctx->buf, "# Ref %s checked out at '%s'\n",
6175 decoration->name, path);
6176 } else {
6177 struct string_list_item *sti;
6178 item->command = TODO_UPDATE_REF;
6179 strbuf_addf(ctx->buf, "%s\n", decoration->name);
6180
6181 sti = string_list_insert(&ctx->refs_to_oids,
6182 decoration->name);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006183 sti->util = init_update_ref_record(decoration->name);
Derrick Stolee900b50c2022-07-19 18:33:39 +00006184 }
6185
6186 item->offset_in_buf = base_offset;
6187 item->arg_offset = base_offset;
6188 item->arg_len = ctx->buf->len - base_offset;
6189 ctx->items_nr++;
6190
6191 decoration = decoration->next;
6192 }
6193
6194 return 0;
6195}
6196
6197/*
6198 * For each 'pick' command, find out if the commit has a decoration in
6199 * refs/heads/. If so, then add a 'label for-update-refs/' command.
6200 */
6201static int todo_list_add_update_ref_commands(struct todo_list *todo_list)
6202{
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006203 int i, res;
Derrick Stolee900b50c2022-07-19 18:33:39 +00006204 static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
6205 static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
6206 static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
6207 struct decoration_filter decoration_filter = {
6208 .include_ref_pattern = &decorate_refs_include,
6209 .exclude_ref_pattern = &decorate_refs_exclude,
6210 .exclude_ref_config_pattern = &decorate_refs_exclude_config,
6211 };
6212 struct todo_add_branch_context ctx = {
6213 .buf = &todo_list->buf,
6214 .refs_to_oids = STRING_LIST_INIT_DUP,
6215 };
6216
6217 ctx.items_alloc = 2 * todo_list->nr + 1;
6218 ALLOC_ARRAY(ctx.items, ctx.items_alloc);
6219
6220 string_list_append(&decorate_refs_include, "refs/heads/");
6221 load_ref_decorations(&decoration_filter, 0);
6222
6223 for (i = 0; i < todo_list->nr; ) {
6224 struct todo_item *item = &todo_list->items[i];
6225
6226 /* insert ith item into new list */
6227 ALLOC_GROW(ctx.items,
6228 ctx.items_nr + 1,
6229 ctx.items_alloc);
6230
6231 ctx.items[ctx.items_nr++] = todo_list->items[i++];
6232
6233 if (item->commit) {
6234 ctx.commit = item->commit;
6235 add_decorations_to_list(item->commit, &ctx);
6236 }
6237 }
6238
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006239 res = write_update_refs_state(&ctx.refs_to_oids);
6240
Derrick Stolee900b50c2022-07-19 18:33:39 +00006241 string_list_clear(&ctx.refs_to_oids, 1);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006242
6243 if (res) {
6244 /* we failed, so clean up the new list. */
6245 free(ctx.items);
6246 return res;
6247 }
6248
Derrick Stolee900b50c2022-07-19 18:33:39 +00006249 free(todo_list->items);
6250 todo_list->items = ctx.items;
6251 todo_list->nr = ctx.items_nr;
6252 todo_list->alloc = ctx.items_alloc;
6253
6254 return 0;
6255}
6256
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01006257int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
Alban Gruinb97e1872018-08-28 14:10:36 +02006258 const char *shortrevisions, const char *onto_name,
Phillip Woodf3e27a02020-11-04 15:29:38 +00006259 struct commit *onto, const struct object_id *orig_head,
Phillip Wood7d3488e2019-04-17 15:30:39 +01006260 struct string_list *commands, unsigned autosquash,
Derrick Stolee900b50c2022-07-19 18:33:39 +00006261 unsigned update_refs,
Phillip Wood7d3488e2019-04-17 15:30:39 +01006262 struct todo_list *todo_list)
Alban Gruinb97e1872018-08-28 14:10:36 +02006263{
Antti Keränen5da69c02020-08-13 20:42:57 +03006264 char shortonto[GIT_MAX_HEXSZ + 1];
6265 const char *todo_file = rebase_path_todo();
Alban Gruin94bcad72019-03-05 20:17:57 +01006266 struct todo_list new_todo = TODO_LIST_INIT;
Johannes Schindelinb6992262020-01-23 12:28:18 +00006267 struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT;
Phillip Wood7d3488e2019-04-17 15:30:39 +01006268 struct object_id oid = onto->object.oid;
Alban Gruin1451d0f2019-03-05 20:18:04 +01006269 int res;
Alban Gruinb97e1872018-08-28 14:10:36 +02006270
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02006271 repo_find_unique_abbrev_r(r, shortonto, &oid,
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02006272 DEFAULT_ABBREV);
Alban Gruinb97e1872018-08-28 14:10:36 +02006273
Alban Gruinb97e1872018-08-28 14:10:36 +02006274 if (buf->len == 0) {
Alban Gruin94bcad72019-03-05 20:17:57 +01006275 struct todo_item *item = append_new_todo(todo_list);
6276 item->command = TODO_NOOP;
6277 item->commit = NULL;
6278 item->arg_len = item->arg_offset = item->flags = item->offset_in_buf = 0;
6279 }
Alban Gruinb97e1872018-08-28 14:10:36 +02006280
Derrick Stolee900b50c2022-07-19 18:33:39 +00006281 if (update_refs && todo_list_add_update_ref_commands(todo_list))
6282 return -1;
6283
Alban Gruin94bcad72019-03-05 20:17:57 +01006284 if (autosquash && todo_list_rearrange_squash(todo_list))
Alban Gruinb97e1872018-08-28 14:10:36 +02006285 return -1;
6286
Alban Gruin683153a2019-03-05 20:17:54 +01006287 if (commands->nr)
Alban Gruin94bcad72019-03-05 20:17:57 +01006288 todo_list_add_exec_commands(todo_list, commands);
Alban Gruinb97e1872018-08-28 14:10:36 +02006289
Alban Gruin94bcad72019-03-05 20:17:57 +01006290 if (count_commands(todo_list) == 0) {
Denton Liube1bb602020-04-07 10:27:56 -04006291 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006292 sequencer_remove_state(opts);
Alban Gruinb97e1872018-08-28 14:10:36 +02006293
6294 return error(_("nothing to do"));
6295 }
6296
Alban Gruin1451d0f2019-03-05 20:18:04 +01006297 res = edit_todo_list(r, todo_list, &new_todo, shortrevisions,
6298 shortonto, flags);
6299 if (res == -1)
6300 return -1;
6301 else if (res == -2) {
Denton Liube1bb602020-04-07 10:27:56 -04006302 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006303 sequencer_remove_state(opts);
Alban Gruinb97e1872018-08-28 14:10:36 +02006304
Alban Gruinb97e1872018-08-28 14:10:36 +02006305 return -1;
Alban Gruin1451d0f2019-03-05 20:18:04 +01006306 } else if (res == -3) {
Denton Liube1bb602020-04-07 10:27:56 -04006307 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006308 sequencer_remove_state(opts);
Alban Gruin94bcad72019-03-05 20:17:57 +01006309 todo_list_release(&new_todo);
Alban Gruinb97e1872018-08-28 14:10:36 +02006310
6311 return error(_("nothing to do"));
Alban Gruin5a5445d2020-01-28 22:12:46 +01006312 } else if (res == -4) {
Phillip Wood7d3488e2019-04-17 15:30:39 +01006313 checkout_onto(r, opts, onto_name, &onto->object.oid, orig_head);
Alban Gruin94bcad72019-03-05 20:17:57 +01006314 todo_list_release(&new_todo);
6315
Alban Gruinb97e1872018-08-28 14:10:36 +02006316 return -1;
6317 }
6318
Johannes Schindelinb6992262020-01-23 12:28:18 +00006319 /* Expand the commit IDs */
6320 todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0);
6321 strbuf_swap(&new_todo.buf, &buf2);
6322 strbuf_release(&buf2);
Johannes Schindelin170eea92023-05-13 08:11:26 +00006323 /* Nothing is done yet, and we're reparsing, so let's reset the count */
6324 new_todo.total_nr = 0;
Johannes Schindelinb6992262020-01-23 12:28:18 +00006325 if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0)
6326 BUG("invalid todo list after expanding IDs:\n%s",
6327 new_todo.buf.buf);
6328
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006329 if (opts->allow_ff && skip_unnecessary_picks(r, &new_todo, &oid)) {
6330 todo_list_release(&new_todo);
Alban Gruinb97e1872018-08-28 14:10:36 +02006331 return error(_("could not skip unnecessary pick commands"));
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006332 }
6333
Alban Gruin94bcad72019-03-05 20:17:57 +01006334 if (todo_list_write_to_file(r, &new_todo, todo_file, NULL, NULL, -1,
6335 flags & ~(TODO_LIST_SHORTEN_IDS))) {
6336 todo_list_release(&new_todo);
6337 return error_errno(_("could not write '%s'"), todo_file);
6338 }
6339
Alban Gruin393adf72019-11-24 18:43:32 +01006340 res = -1;
Alban Gruinb97e1872018-08-28 14:10:36 +02006341
Phillip Wood7d3488e2019-04-17 15:30:39 +01006342 if (checkout_onto(r, opts, onto_name, &oid, orig_head))
Alban Gruin393adf72019-11-24 18:43:32 +01006343 goto cleanup;
Nguyễn Thái Ngọc Duy29d51e22018-11-03 15:32:29 +01006344
Oswald Buddenhagena9b59552023-08-24 17:00:46 +02006345 if (require_clean_work_tree(r, "rebase", NULL, 1, 1))
Alban Gruin393adf72019-11-24 18:43:32 +01006346 goto cleanup;
Alban Gruinb97e1872018-08-28 14:10:36 +02006347
Alban Gruin393adf72019-11-24 18:43:32 +01006348 todo_list_write_total_nr(&new_todo);
6349 res = pick_commits(r, &new_todo, opts);
6350
6351cleanup:
6352 todo_list_release(&new_todo);
6353
6354 return res;
Alban Gruinb97e1872018-08-28 14:10:36 +02006355}
6356
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006357struct subject2item_entry {
6358 struct hashmap_entry entry;
6359 int i;
6360 char subject[FLEX_ARRAY];
6361};
6362
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +02006363static int subject2item_cmp(const void *fndata UNUSED,
Eric Wong939af162019-10-06 23:30:37 +00006364 const struct hashmap_entry *eptr,
6365 const struct hashmap_entry *entry_or_key,
6366 const void *key)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006367{
Eric Wong939af162019-10-06 23:30:37 +00006368 const struct subject2item_entry *a, *b;
6369
6370 a = container_of(eptr, const struct subject2item_entry, entry);
6371 b = container_of(entry_or_key, const struct subject2item_entry, entry);
6372
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006373 return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);
6374}
6375
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006376define_commit_slab(commit_todo_item, struct todo_item *);
6377
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306378static int skip_fixupish(const char *subject, const char **p) {
Charvi Mendirattabae5b4a2021-01-29 23:50:49 +05306379 return skip_prefix(subject, "fixup! ", p) ||
6380 skip_prefix(subject, "amend! ", p) ||
6381 skip_prefix(subject, "squash! ", p);
6382}
6383
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006384/*
6385 * Rearrange the todo list that has both "pick commit-id msg" and "pick
6386 * commit-id fixup!/squash! msg" in it so that the latter is put immediately
6387 * after the former, and change "pick" to "fixup"/"squash".
6388 *
6389 * Note that if the config has specified a custom instruction format, each log
6390 * message will have to be retrieved from the commit (as the oneline in the
6391 * script cannot be trusted) in order to normalize the autosquash arrangement.
6392 */
Alban Gruin79d7e882019-03-05 20:17:59 +01006393int todo_list_rearrange_squash(struct todo_list *todo_list)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006394{
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006395 struct hashmap subject2item;
Oswald Buddenhagen82dc42c2023-08-09 19:15:32 +02006396 int rearranged = 0, *next, *tail, i, nr = 0;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006397 char **subjects;
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006398 struct commit_todo_item commit_todo;
Alban Gruinf2a04902019-03-05 20:17:55 +01006399 struct todo_item *items = NULL;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006400
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006401 init_commit_todo_item(&commit_todo);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006402 /*
6403 * The hashmap maps onelines to the respective todo list index.
6404 *
6405 * If any items need to be rearranged, the next[i] value will indicate
6406 * which item was moved directly after the i'th.
6407 *
6408 * In that case, last[i] will indicate the index of the latest item to
6409 * be moved to appear after the i'th.
6410 */
Eric Wong939af162019-10-06 23:30:37 +00006411 hashmap_init(&subject2item, subject2item_cmp, NULL, todo_list->nr);
Alban Gruinf2a04902019-03-05 20:17:55 +01006412 ALLOC_ARRAY(next, todo_list->nr);
6413 ALLOC_ARRAY(tail, todo_list->nr);
6414 ALLOC_ARRAY(subjects, todo_list->nr);
6415 for (i = 0; i < todo_list->nr; i++) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006416 struct strbuf buf = STRBUF_INIT;
Alban Gruinf2a04902019-03-05 20:17:55 +01006417 struct todo_item *item = todo_list->items + i;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006418 const char *commit_buffer, *subject, *p;
6419 size_t subject_len;
6420 int i2 = -1;
6421 struct subject2item_entry *entry;
6422
6423 next[i] = tail[i] = -1;
Johannes Schindelin2f6b1d12018-04-25 14:28:25 +02006424 if (!item->commit || item->command == TODO_DROP) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006425 subjects[i] = NULL;
6426 continue;
6427 }
6428
6429 if (is_fixup(item->command)) {
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006430 clear_commit_todo_item(&commit_todo);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006431 return error(_("the script was already rearranged."));
6432 }
6433
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02006434 repo_parse_commit(the_repository, item->commit);
6435 commit_buffer = repo_logmsg_reencode(the_repository,
6436 item->commit, NULL,
6437 "UTF-8");
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006438 find_commit_subject(commit_buffer, &subject);
6439 format_subject(&buf, subject, " ");
6440 subject = subjects[i] = strbuf_detach(&buf, &subject_len);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02006441 repo_unuse_commit_buffer(the_repository, item->commit,
6442 commit_buffer);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306443 if (skip_fixupish(subject, &p)) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006444 struct commit *commit2;
6445
6446 for (;;) {
6447 while (isspace(*p))
6448 p++;
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306449 if (!skip_fixupish(p, &p))
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006450 break;
6451 }
6452
Eric Wongf23a4652019-10-06 23:30:36 +00006453 entry = hashmap_get_entry_from_hash(&subject2item,
6454 strhash(p), p,
6455 struct subject2item_entry,
6456 entry);
6457 if (entry)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006458 /* found by title */
6459 i2 = entry->i;
6460 else if (!strchr(p, ' ') &&
6461 (commit2 =
6462 lookup_commit_reference_by_name(p)) &&
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006463 *commit_todo_item_at(&commit_todo, commit2))
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006464 /* found by commit name */
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006465 i2 = *commit_todo_item_at(&commit_todo, commit2)
Alban Gruinf2a04902019-03-05 20:17:55 +01006466 - todo_list->items;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006467 else {
6468 /* copy can be a prefix of the commit subject */
6469 for (i2 = 0; i2 < i; i2++)
6470 if (subjects[i2] &&
6471 starts_with(subjects[i2], p))
6472 break;
6473 if (i2 == i)
6474 i2 = -1;
6475 }
6476 }
6477 if (i2 >= 0) {
6478 rearranged = 1;
Charvi Mendirattabae5b4a2021-01-29 23:50:49 +05306479 if (starts_with(subject, "fixup!")) {
6480 todo_list->items[i].command = TODO_FIXUP;
6481 } else if (starts_with(subject, "amend!")) {
6482 todo_list->items[i].command = TODO_FIXUP;
6483 todo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;
6484 } else {
6485 todo_list->items[i].command = TODO_SQUASH;
6486 }
Johannes Schindelin02471e72020-05-09 19:23:39 +00006487 if (tail[i2] < 0) {
6488 next[i] = next[i2];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006489 next[i2] = i;
Johannes Schindelin02471e72020-05-09 19:23:39 +00006490 } else {
6491 next[i] = next[tail[i2]];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006492 next[tail[i2]] = i;
Johannes Schindelin02471e72020-05-09 19:23:39 +00006493 }
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006494 tail[i2] = i;
6495 } else if (!hashmap_get_from_hash(&subject2item,
6496 strhash(subject), subject)) {
6497 FLEX_ALLOC_MEM(entry, subject, subject, subject_len);
6498 entry->i = i;
Eric Wongd22245a2019-10-06 23:30:27 +00006499 hashmap_entry_init(&entry->entry,
6500 strhash(entry->subject));
Eric Wong26b455f2019-10-06 23:30:32 +00006501 hashmap_put(&subject2item, &entry->entry);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006502 }
Johannes Altmanninger3e367a52022-09-24 17:29:04 -05006503
6504 *commit_todo_item_at(&commit_todo, item->commit) = item;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006505 }
6506
6507 if (rearranged) {
Oswald Buddenhagen82dc42c2023-08-09 19:15:32 +02006508 ALLOC_ARRAY(items, todo_list->nr);
6509
Alban Gruinf2a04902019-03-05 20:17:55 +01006510 for (i = 0; i < todo_list->nr; i++) {
6511 enum todo_command command = todo_list->items[i].command;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006512 int cur = i;
6513
6514 /*
6515 * Initially, all commands are 'pick's. If it is a
6516 * fixup or a squash now, we have rearranged it.
6517 */
6518 if (is_fixup(command))
6519 continue;
6520
6521 while (cur >= 0) {
Alban Gruinf2a04902019-03-05 20:17:55 +01006522 items[nr++] = todo_list->items[cur];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006523 cur = next[cur];
6524 }
6525 }
6526
Oswald Buddenhagen82dc42c2023-08-09 19:15:32 +02006527 assert(nr == todo_list->nr);
6528 todo_list->alloc = nr;
Alban Gruinf2a04902019-03-05 20:17:55 +01006529 FREE_AND_NULL(todo_list->items);
6530 todo_list->items = items;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006531 }
6532
6533 free(next);
6534 free(tail);
Alban Gruinf2a04902019-03-05 20:17:55 +01006535 for (i = 0; i < todo_list->nr; i++)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006536 free(subjects[i]);
6537 free(subjects);
Elijah Newren6da1a252020-11-02 18:55:05 +00006538 hashmap_clear_and_free(&subject2item, struct subject2item_entry, entry);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006539
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006540 clear_commit_todo_item(&commit_todo);
Alban Gruinf2a04902019-03-05 20:17:55 +01006541
6542 return 0;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006543}
Phillip Wood901ba7b2019-12-06 16:06:11 +00006544
6545int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
6546{
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00006547 if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
Phillip Wood430b75f2019-12-06 16:06:12 +00006548 struct object_id cherry_pick_head, rebase_head;
6549
6550 if (file_exists(git_path_seq_dir()))
6551 *whence = FROM_CHERRY_PICK_MULTI;
6552 if (file_exists(rebase_path()) &&
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02006553 !repo_get_oid(r, "REBASE_HEAD", &rebase_head) &&
6554 !repo_get_oid(r, "CHERRY_PICK_HEAD", &cherry_pick_head) &&
Phillip Wood430b75f2019-12-06 16:06:12 +00006555 oideq(&rebase_head, &cherry_pick_head))
6556 *whence = FROM_REBASE_PICK;
6557 else
6558 *whence = FROM_CHERRY_PICK_SINGLE;
6559
Phillip Wood901ba7b2019-12-06 16:06:11 +00006560 return 1;
6561 }
6562
6563 return 0;
6564}
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +00006565
6566int sequencer_get_update_refs_state(const char *wt_dir,
6567 struct string_list *refs)
6568{
6569 int result = 0;
6570 FILE *fp = NULL;
6571 struct strbuf ref = STRBUF_INIT;
6572 struct strbuf hash = STRBUF_INIT;
6573 struct update_ref_record *rec = NULL;
6574
6575 char *path = rebase_path_update_refs(wt_dir);
6576
6577 fp = fopen(path, "r");
6578 if (!fp)
6579 goto cleanup;
6580
6581 while (strbuf_getline(&ref, fp) != EOF) {
6582 struct string_list_item *item;
6583
6584 CALLOC_ARRAY(rec, 1);
6585
6586 if (strbuf_getline(&hash, fp) == EOF ||
6587 get_oid_hex(hash.buf, &rec->before)) {
6588 warning(_("update-refs file at '%s' is invalid"),
6589 path);
6590 result = -1;
6591 goto cleanup;
6592 }
6593
6594 if (strbuf_getline(&hash, fp) == EOF ||
6595 get_oid_hex(hash.buf, &rec->after)) {
6596 warning(_("update-refs file at '%s' is invalid"),
6597 path);
6598 result = -1;
6599 goto cleanup;
6600 }
6601
6602 item = string_list_insert(refs, ref.buf);
6603 item->util = rec;
6604 rec = NULL;
6605 }
6606
6607cleanup:
6608 if (fp)
6609 fclose(fp);
6610 free(path);
6611 free(rec);
6612 strbuf_release(&ref);
6613 strbuf_release(&hash);
6614 return result;
6615}