blob: 5e0c15a16b73b3bf04fc76afc2bc2bd1c15f677d [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 "tag.h"
19#include "run-command.h"
Ævar Arnfjörð Bjarmason5e3aba32021-09-26 21:03:26 +020020#include "hook.h"
Stefan Bellerd807c4a2018-04-10 14:26:18 -070021#include "exec-cmd.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053022#include "utf8.h"
23#include "cache-tree.h"
24#include "diff.h"
Elijah Newrenc3399322023-05-16 06:33:59 +000025#include "path.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053026#include "revision.h"
27#include "rerere.h"
Elijah Newren750324d2023-05-16 06:33:54 +000028#include "merge.h"
Elijah Newren14c45862020-11-02 23:45:34 +000029#include "merge-ort.h"
30#include "merge-ort-wrappers.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053031#include "refs.h"
Elijah Newrenbaf889c2023-05-16 06:33:51 +000032#include "sparse-index.h"
Jeff Kingdbbcd442020-07-28 16:23:39 -040033#include "strvec.h"
Johannes Schindelina1c75762016-10-21 14:25:12 +020034#include "quote.h"
Jonathan Tan967dfd42016-11-02 10:29:20 -070035#include "trailer.h"
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +010036#include "log-tree.h"
Johannes Schindelin311af522017-01-02 16:26:47 +010037#include "wt-status.h"
Johannes Schindelinc44a4c62017-07-14 16:45:31 +020038#include "hashmap.h"
Phillip Wooda87a6f32017-11-17 11:34:48 +000039#include "notes-utils.h"
40#include "sigchain.h"
Johannes Schindelin9055e402018-04-25 14:28:47 +020041#include "unpack-trees.h"
42#include "worktree.h"
Johannes Schindelin1644c732018-04-25 14:29:03 +020043#include "oidmap.h"
44#include "oidset.h"
Nguyễn Thái Ngọc Duy8315bd22018-05-19 07:28:22 +020045#include "commit-slab.h"
Nguyễn Thái Ngọc Duy65b5f942018-05-20 20:40:06 +020046#include "alias.h"
Derrick Stolee64043552018-07-20 16:33:04 +000047#include "commit-reach.h"
Alban Gruinb97e1872018-08-28 14:10:36 +020048#include "rebase-interactive.h"
Denton Liu0816f1d2020-04-07 10:28:03 -040049#include "reset.h"
Derrick Stolee900b50c2022-07-19 18:33:39 +000050#include "branch.h"
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +053051
52#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +053053
Ramsay Jones5fe81432019-02-11 17:16:58 +000054static const char sign_off_header[] = "Signed-off-by: ";
Brandon Caseycd650a42013-02-12 02:17:32 -080055static const char cherry_picked_prefix[] = "(cherry picked from commit ";
Miklos Vajna5ed75e22012-09-14 08:52:03 +020056
Phillip Wood66618a52018-01-24 12:34:22 +000057GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
58
Phillip Wood901ba7b2019-12-06 16:06:11 +000059static GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
Johannes Schindelin8a2a0f52016-10-14 15:17:12 +020060
61static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
62static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
63static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
Stephan Beyer1e412292016-12-07 22:51:32 +010064static GIT_PATH_FUNC(git_path_abort_safety_file, "sequencer/abort-safety")
Jeff Kingf9327292015-08-10 05:38:57 -040065
Johannes Schindelin84583952017-01-02 16:26:28 +010066static GIT_PATH_FUNC(rebase_path, "rebase-merge")
67/*
68 * The file containing rebase commands, comments, and empty lines.
69 * This file is created by "git rebase -i" then edited by the user. As
70 * the lines are processed, they are removed from the front of this
71 * file and written to the tail of 'done'.
72 */
Alban Gruin44b776c2018-08-10 18:51:28 +020073GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
Alban Gruina930eb02019-03-05 20:18:03 +010074GIT_PATH_FUNC(rebase_path_todo_backup, "rebase-merge/git-rebase-todo.backup")
Alban Gruinb97e1872018-08-28 14:10:36 +020075
Alban Gruin5a5445d2020-01-28 22:12:46 +010076GIT_PATH_FUNC(rebase_path_dropped, "rebase-merge/dropped")
77
Johannes Schindelinb5a67042016-10-21 14:25:04 +020078/*
Johannes Schindelin1df6df02017-01-02 16:27:00 +010079 * The rebase command lines that have already been processed. A line
80 * is moved here when it is first handled, before any associated user
81 * actions.
82 */
83static GIT_PATH_FUNC(rebase_path_done, "rebase-merge/done")
84/*
Johannes Schindelinef800692017-01-02 16:36:20 +010085 * The file to keep track of how many commands were already processed (e.g.
86 * for the prompt).
87 */
Beat Bolli9ad36352018-07-09 21:25:35 +020088static GIT_PATH_FUNC(rebase_path_msgnum, "rebase-merge/msgnum")
Johannes Schindelinef800692017-01-02 16:36:20 +010089/*
90 * The file to keep track of how many commands are to be processed in total
91 * (e.g. for the prompt).
92 */
Beat Bolli9ad36352018-07-09 21:25:35 +020093static GIT_PATH_FUNC(rebase_path_msgtotal, "rebase-merge/end")
Johannes Schindelinef800692017-01-02 16:36:20 +010094/*
Johannes Schindelin6e98de72017-01-02 16:27:07 +010095 * The commit message that is planned to be used for any changes that
96 * need to be committed following a user interaction.
97 */
98static GIT_PATH_FUNC(rebase_path_message, "rebase-merge/message")
99/*
100 * The file into which is accumulated the suggested commit message for
101 * squash/fixup commands. When the first of a series of squash/fixups
102 * is seen, the file is created and the commit message from the
103 * previous commit and from the first squash/fixup commit are written
104 * to it. The commit message for each subsequent squash/fixup commit
105 * is appended to the file as it is processed.
Johannes Schindelin6e98de72017-01-02 16:27:07 +0100106 */
107static GIT_PATH_FUNC(rebase_path_squash_msg, "rebase-merge/message-squash")
108/*
109 * If the current series of squash/fixups has not yet included a squash
110 * command, then this file exists and holds the commit message of the
111 * original "pick" commit. (If the series ends without a "squash"
112 * command, then this can be used as the commit message of the combined
113 * commit without opening the editor.)
114 */
115static GIT_PATH_FUNC(rebase_path_fixup_msg, "rebase-merge/message-fixup")
116/*
Johannes Schindeline12a7ef2018-04-27 22:48:21 +0200117 * This file contains the list fixup/squash commands that have been
118 * accumulated into message-fixup or message-squash so far.
119 */
120static GIT_PATH_FUNC(rebase_path_current_fixups, "rebase-merge/current-fixups")
121/*
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200122 * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
123 * GIT_AUTHOR_DATE that will be used for the commit that is currently
124 * being rebased.
125 */
126static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
Johannes Schindelina1c75762016-10-21 14:25:12 +0200127/*
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +0100128 * When an "edit" rebase command is being processed, the SHA1 of the
129 * commit to be edited is recorded in this file. When "git rebase
130 * --continue" is executed, if there are any staged changes then they
131 * will be amended to the HEAD commit, but only provided the HEAD
132 * commit is still the commit to be edited. When any other rebase
133 * command is processed, this file is deleted.
134 */
135static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
136/*
137 * When we stop at a given patch via the "edit" command, this file contains
Junio C Hamano0512eab2020-09-24 22:49:12 -0700138 * the commit object name of the corresponding patch.
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +0100139 */
140static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
141/*
Johannes Schindelin25cb8df2017-01-02 16:28:16 +0100142 * For the post-rewrite hook, we make a list of rewritten commits and
143 * their new sha1s. The rewritten-pending list keeps the sha1s of
144 * commits that have been processed, but not committed yet,
145 * e.g. because they are waiting for a 'squash' command.
146 */
147static GIT_PATH_FUNC(rebase_path_rewritten_list, "rebase-merge/rewritten-list")
148static GIT_PATH_FUNC(rebase_path_rewritten_pending,
149 "rebase-merge/rewritten-pending")
Johannes Schindelin9055e402018-04-25 14:28:47 +0200150
151/*
Elijah Newren15beaaa2019-11-05 17:07:23 +0000152 * The path of the file containing the OID of the "squash onto" commit, i.e.
Johannes Schindelind87d48b2018-05-04 01:01:17 +0200153 * the dummy commit used for `reset [new root]`.
154 */
155static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto")
156
157/*
Johannes Schindelin9055e402018-04-25 14:28:47 +0200158 * The path of the file listing refs that need to be deleted after the rebase
159 * finishes. This is used by the `label` command to record the need for cleanup.
160 */
161static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
162
Johannes Schindelin25cb8df2017-01-02 16:28:16 +0100163/*
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +0000164 * The update-refs file stores a list of refs that will be updated at the end
165 * of the rebase sequence. The 'update-ref <ref>' commands in the todo file
166 * update the OIDs for the refs in this file, but the refs are not updated
167 * until the end of the rebase sequence.
168 *
169 * rebase_path_update_refs() returns the path to this file for a given
170 * worktree directory. For the current worktree, pass the_repository->gitdir.
171 */
172static char *rebase_path_update_refs(const char *wt_git_dir)
173{
174 return xstrfmt("%s/rebase-merge/update-refs", wt_git_dir);
175}
176
177/*
Johannes Schindelina1c75762016-10-21 14:25:12 +0200178 * The following files are written by git-rebase just after parsing the
Alban Gruin65850682018-08-28 14:10:40 +0200179 * command-line.
Johannes Schindelina1c75762016-10-21 14:25:12 +0200180 */
181static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
Phillip Wood7573cec2020-08-17 18:40:02 +0100182static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
Phillip Wooda3894aa2020-08-17 18:40:03 +0100183static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
Johannes Schindelin556907f2017-01-02 16:26:53 +0100184static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
185static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
Elijah Newren899b49c2018-12-11 08:11:36 -0800186static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
Phillip Wooda852ec72018-03-20 11:10:55 +0000187static GIT_PATH_FUNC(rebase_path_signoff, "rebase-merge/signoff")
Johannes Schindelin4b83ce92017-01-02 16:27:53 +0100188static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name")
189static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
Johannes Schindelin796c7972017-01-02 16:28:27 +0100190static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash")
Johannes Schindelinca6c6b42017-01-02 16:28:30 +0100191static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
192static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
Phillip Wood9b6d7a62017-08-02 11:44:17 +0100193static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
Johannes Schindelind421afa2018-12-10 11:04:58 -0800194static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +0200195static GIT_PATH_FUNC(rebase_path_no_reschedule_failed_exec, "rebase-merge/no-reschedule-failed-exec")
Elijah Newrene98c4262020-02-15 21:36:25 +0000196static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
197static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200198
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +0000199/**
200 * A 'struct update_refs_record' represents a value in the update-refs
201 * list. We use a string_list to map refs to these (before, after) pairs.
202 */
203struct update_ref_record {
204 struct object_id before;
205 struct object_id after;
206};
207
Derrick Stolee89fc0b52022-07-19 18:33:40 +0000208static struct update_ref_record *init_update_ref_record(const char *ref)
209{
210 struct update_ref_record *rec;
211
212 CALLOC_ARRAY(rec, 1);
213
214 oidcpy(&rec->before, null_oid());
215 oidcpy(&rec->after, null_oid());
216
217 /* This may fail, but that's fine, we will keep the null OID. */
218 read_ref(ref, &rec->before);
219
220 return rec;
221}
222
Glen Chooa4e7e312023-06-28 19:26:22 +0000223static int git_sequencer_config(const char *k, const char *v,
224 const struct config_context *ctx, void *cb)
Phillip Wood28d6dae2017-12-13 11:46:21 +0000225{
226 struct replay_opts *opts = cb;
227 int status;
228
229 if (!strcmp(k, "commit.cleanup")) {
230 const char *s;
231
232 status = git_config_string(&s, k, v);
233 if (status)
234 return status;
235
Phillip Woodd74f3e52019-03-29 11:08:42 +0000236 if (!strcmp(s, "verbatim")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000237 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000238 opts->explicit_cleanup = 1;
239 } else if (!strcmp(s, "whitespace")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000240 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000241 opts->explicit_cleanup = 1;
242 } else if (!strcmp(s, "strip")) {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000243 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000244 opts->explicit_cleanup = 1;
245 } else if (!strcmp(s, "scissors")) {
Denton Liu1a2b9852019-04-17 11:23:30 +0100246 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
Phillip Woodd74f3e52019-03-29 11:08:42 +0000247 opts->explicit_cleanup = 1;
248 } else {
Phillip Wood28d6dae2017-12-13 11:46:21 +0000249 warning(_("invalid commit message cleanup mode '%s'"),
250 s);
Phillip Woodd74f3e52019-03-29 11:08:42 +0000251 }
Phillip Wood28d6dae2017-12-13 11:46:21 +0000252
Stefan Bellerf40f3c12018-06-01 13:01:46 -0700253 free((char *)s);
Phillip Wood28d6dae2017-12-13 11:46:21 +0000254 return status;
255 }
256
257 if (!strcmp(k, "commit.gpgsign")) {
Johannes Schindelined1e5282017-12-22 12:50:50 +0100258 opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
Phillip Wood28d6dae2017-12-13 11:46:21 +0000259 return 0;
260 }
261
Elijah Newren14c45862020-11-02 23:45:34 +0000262 if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
263 int ret = git_config_string((const char**)&opts->default_strategy, k, v);
264 if (ret == 0) {
265 /*
266 * pull.twohead is allowed to be multi-valued; we only
267 * care about the first value.
268 */
269 char *tmp = strchr(opts->default_strategy, ' ');
270 if (tmp)
271 *tmp = '\0';
272 }
273 return ret;
274 }
275
Junio C Hamano191faaf2022-05-31 09:22:20 -0700276 if (opts->action == REPLAY_REVERT && !strcmp(k, "revert.reference"))
Junio C Hamano43966ab2022-05-26 23:01:39 -0700277 opts->commit_use_reference = git_config_bool(k, v);
278
Glen Chooa4e7e312023-06-28 19:26:22 +0000279 return git_diff_basic_config(k, v, ctx, NULL);
Phillip Wood28d6dae2017-12-13 11:46:21 +0000280}
281
282void sequencer_init_config(struct replay_opts *opts)
283{
284 opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
285 git_config(git_sequencer_config, opts);
286}
287
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200288static inline int is_rebase_i(const struct replay_opts *opts)
289{
Johannes Schindelin84583952017-01-02 16:26:28 +0100290 return opts->action == REPLAY_INTERACTIVE_REBASE;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200291}
292
Johannes Schindelin285abf52016-10-14 15:17:20 +0200293static const char *get_dir(const struct replay_opts *opts)
294{
Johannes Schindelin84583952017-01-02 16:26:28 +0100295 if (is_rebase_i(opts))
296 return rebase_path();
Johannes Schindelin285abf52016-10-14 15:17:20 +0200297 return git_path_seq_dir();
298}
299
Johannes Schindelinc0246502016-10-21 14:24:32 +0200300static const char *get_todo_path(const struct replay_opts *opts)
301{
Johannes Schindelin84583952017-01-02 16:26:28 +0100302 if (is_rebase_i(opts))
303 return rebase_path_todo();
Johannes Schindelinc0246502016-10-21 14:24:32 +0200304 return git_path_todo_file();
305}
306
Brandon Caseybab4d102013-02-12 02:17:35 -0800307/*
308 * Returns 0 for non-conforming footer
309 * Returns 1 for conforming footer
310 * Returns 2 when sob exists within conforming footer
311 * Returns 3 when sob exists within conforming footer as last entry
312 */
313static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
Jeff King66e83d92018-08-22 20:50:51 -0400314 size_t ignore_footer)
Brandon Caseyb971e042013-02-12 02:17:34 -0800315{
Jeff King00a21f52018-08-22 20:46:23 -0400316 struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
Jonathan Tan967dfd42016-11-02 10:29:20 -0700317 struct trailer_info info;
Jeff Kinga3b636e2018-08-22 20:45:44 -0400318 size_t i;
Jonathan Tan967dfd42016-11-02 10:29:20 -0700319 int found_sob = 0, found_sob_last = 0;
Jeff King9dad0732020-09-30 08:34:11 -0400320 char saved_char;
Brandon Caseyb971e042013-02-12 02:17:34 -0800321
Jeff Kingffce7f52018-08-22 20:50:37 -0400322 opts.no_divider = 1;
323
Jeff King9dad0732020-09-30 08:34:11 -0400324 if (ignore_footer) {
325 saved_char = sb->buf[sb->len - ignore_footer];
326 sb->buf[sb->len - ignore_footer] = '\0';
327 }
328
Jeff King00a21f52018-08-22 20:46:23 -0400329 trailer_info_get(&info, sb->buf, &opts);
Jonathan Tan967dfd42016-11-02 10:29:20 -0700330
Jeff King9dad0732020-09-30 08:34:11 -0400331 if (ignore_footer)
332 sb->buf[sb->len - ignore_footer] = saved_char;
333
Jonathan Tan967dfd42016-11-02 10:29:20 -0700334 if (info.trailer_start == info.trailer_end)
Brandon Caseyb971e042013-02-12 02:17:34 -0800335 return 0;
336
Jonathan Tan967dfd42016-11-02 10:29:20 -0700337 for (i = 0; i < info.trailer_nr; i++)
338 if (sob && !strncmp(info.trailers[i], sob->buf, sob->len)) {
339 found_sob = 1;
340 if (i == info.trailer_nr - 1)
341 found_sob_last = 1;
342 }
Brandon Caseyb971e042013-02-12 02:17:34 -0800343
Jonathan Tan967dfd42016-11-02 10:29:20 -0700344 trailer_info_release(&info);
Brandon Caseyb971e042013-02-12 02:17:34 -0800345
Jonathan Tan967dfd42016-11-02 10:29:20 -0700346 if (found_sob_last)
Brandon Caseybab4d102013-02-12 02:17:35 -0800347 return 3;
348 if (found_sob)
349 return 2;
Brandon Caseyb971e042013-02-12 02:17:34 -0800350 return 1;
351}
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530352
Johannes Schindelina1c75762016-10-21 14:25:12 +0200353static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
354{
355 static struct strbuf buf = STRBUF_INIT;
356
357 strbuf_reset(&buf);
358 if (opts->gpg_sign)
359 sq_quotef(&buf, "-S%s", opts->gpg_sign);
360 return buf.buf;
361}
362
Ævar Arnfjörð Bjarmason9ff2f062023-02-06 20:08:08 +0100363void replay_opts_release(struct replay_opts *opts)
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100364{
365 free(opts->gpg_sign);
366 free(opts->reflog_action);
367 free(opts->default_strategy);
368 free(opts->strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +0100369 strvec_clear (&opts->xopts);
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100370 strbuf_release(&opts->current_fixups);
Ævar Arnfjörð Bjarmasona6a700a2023-02-06 20:08:09 +0100371 if (opts->revs)
372 release_revisions(opts->revs);
373 free(opts->revs);
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100374}
375
Johannes Schindelin28635842016-10-21 14:24:55 +0200376int sequencer_remove_state(struct replay_opts *opts)
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530377{
Johannes Schindelin9055e402018-04-25 14:28:47 +0200378 struct strbuf buf = STRBUF_INIT;
Ævar Arnfjörð Bjarmason6a09c3a2023-02-06 20:08:07 +0100379 int ret = 0;
Johannes Schindelin03a4e262016-10-21 14:24:13 +0200380
Johannes Schindelin9055e402018-04-25 14:28:47 +0200381 if (is_rebase_i(opts) &&
382 strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
383 char *p = buf.buf;
384 while (*p) {
385 char *eol = strchr(p, '\n');
386 if (eol)
387 *eol = '\0';
Elijah Newrenc2417d32020-02-15 21:36:36 +0000388 if (delete_ref("(rebase) cleanup", p, NULL, 0) < 0) {
Johannes Schindelin9055e402018-04-25 14:28:47 +0200389 warning(_("could not delete '%s'"), p);
Phillip Wood37e9ee52019-05-14 19:03:48 +0100390 ret = -1;
391 }
Johannes Schindelin9055e402018-04-25 14:28:47 +0200392 if (!eol)
393 break;
394 p = eol + 1;
395 }
396 }
397
Johannes Schindelin9055e402018-04-25 14:28:47 +0200398 strbuf_reset(&buf);
399 strbuf_addstr(&buf, get_dir(opts));
Phillip Wood37e9ee52019-05-14 19:03:48 +0100400 if (remove_dir_recursively(&buf, 0))
401 ret = error(_("could not remove '%s'"), buf.buf);
Johannes Schindelin9055e402018-04-25 14:28:47 +0200402 strbuf_release(&buf);
Johannes Schindelin28635842016-10-21 14:24:55 +0200403
Phillip Wood37e9ee52019-05-14 19:03:48 +0100404 return ret;
Ramkumar Ramachandra26ae3372011-08-04 16:09:11 +0530405}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530406
407static const char *action_name(const struct replay_opts *opts)
408{
Johannes Schindelin84583952017-01-02 16:26:28 +0100409 switch (opts->action) {
410 case REPLAY_REVERT:
411 return N_("revert");
412 case REPLAY_PICK:
413 return N_("cherry-pick");
414 case REPLAY_INTERACTIVE_REBASE:
Elijah Newrenc2417d32020-02-15 21:36:36 +0000415 return N_("rebase");
Johannes Schindelin84583952017-01-02 16:26:28 +0100416 }
Nguyễn Thái Ngọc Duy1a07e592018-07-21 09:49:19 +0200417 die(_("unknown action: %d"), opts->action);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530418}
419
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530420struct commit_message {
421 char *parent_label;
Jeff King7b35eaf2016-02-22 17:44:57 -0500422 char *label;
423 char *subject;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530424 const char *message;
425};
426
Johannes Schindelin39755962016-10-21 14:24:37 +0200427static const char *short_commit_name(struct commit *commit)
428{
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +0200429 return repo_find_unique_abbrev(the_repository, &commit->object.oid,
430 DEFAULT_ABBREV);
Johannes Schindelin39755962016-10-21 14:24:37 +0200431}
432
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530433static int get_message(struct commit *commit, struct commit_message *out)
434{
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530435 const char *abbrev, *subject;
Jeff King7b35eaf2016-02-22 17:44:57 -0500436 int subject_len;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530437
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200438 out->message = repo_logmsg_reencode(the_repository, commit, NULL,
439 get_commit_output_encoding());
Johannes Schindelin39755962016-10-21 14:24:37 +0200440 abbrev = short_commit_name(commit);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530441
442 subject_len = find_commit_subject(out->message, &subject);
443
Jeff King7b35eaf2016-02-22 17:44:57 -0500444 out->subject = xmemdupz(subject, subject_len);
Elijah Newren7d056de2020-08-12 14:40:04 +0000445 out->label = xstrfmt("%s (%s)", abbrev, out->subject);
Jeff King7b35eaf2016-02-22 17:44:57 -0500446 out->parent_label = xstrfmt("parent of %s", out->label);
447
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530448 return 0;
449}
450
Jeff Kingd74a4e52014-06-10 17:39:35 -0400451static void free_message(struct commit *commit, struct commit_message *msg)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530452{
453 free(msg->parent_label);
Jeff King7b35eaf2016-02-22 17:44:57 -0500454 free(msg->label);
455 free(msg->subject);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +0200456 repo_unuse_commit_buffer(the_repository, commit, msg->message);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530457}
458
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100459static void print_advice(struct repository *r, int show_hint,
460 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530461{
462 char *msg = getenv("GIT_CHERRY_PICK_HELP");
463
464 if (msg) {
ZheNing Huf1725562021-08-22 13:08:41 +0000465 advise("%s\n", msg);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530466 /*
Stefano Lattarini41ccfdd2013-04-12 00:36:10 +0200467 * A conflict has occurred but the porcelain
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530468 * (typically rebase --interactive) wants to take care
469 * of the commit itself so remove CHERRY_PICK_HEAD
470 */
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +0000471 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
472 NULL, 0);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530473 return;
474 }
475
Phil Horded727b12012-02-21 19:44:17 -0500476 if (show_hint) {
477 if (opts->no_commit)
478 advise(_("after resolving the conflicts, mark the corrected paths\n"
479 "with 'git add <paths>' or 'git rm <paths>'"));
ZheNing Huf1725562021-08-22 13:08:41 +0000480 else if (opts->action == REPLAY_PICK)
481 advise(_("After resolving the conflicts, mark them with\n"
482 "\"git add/rm <pathspec>\", then run\n"
483 "\"git cherry-pick --continue\".\n"
484 "You can instead skip this commit with \"git cherry-pick --skip\".\n"
485 "To abort and get back to the state before \"git cherry-pick\",\n"
486 "run \"git cherry-pick --abort\"."));
487 else if (opts->action == REPLAY_REVERT)
488 advise(_("After resolving the conflicts, mark them with\n"
489 "\"git add/rm <pathspec>\", then run\n"
490 "\"git revert --continue\".\n"
491 "You can instead skip this commit with \"git revert --skip\".\n"
492 "To abort and get back to the state before \"git revert\",\n"
493 "run \"git revert --abort\"."));
Phil Horded727b12012-02-21 19:44:17 -0500494 else
ZheNing Huf1725562021-08-22 13:08:41 +0000495 BUG("unexpected pick action in print_advice()");
Phil Horded727b12012-02-21 19:44:17 -0500496 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530497}
498
Alban Gruinddb81e52019-03-05 20:18:01 +0100499static int write_message(const void *buf, size_t len, const char *filename,
500 int append_eol)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530501{
Martin Ågren14bca6c2018-02-27 22:30:09 +0100502 struct lock_file msg_file = LOCK_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530503
Johannes Schindelin4ef3d8f2016-09-09 16:37:05 +0200504 int msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);
505 if (msg_fd < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200506 return error_errno(_("could not lock '%s'"), filename);
Johannes Schindelin75871492016-10-21 14:26:05 +0200507 if (write_in_full(msg_fd, buf, len) < 0) {
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200508 error_errno(_("could not write to '%s'"), filename);
Johannes Schindelin4f66c832016-10-21 14:26:00 +0200509 rollback_lock_file(&msg_file);
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200510 return -1;
Johannes Schindelin4f66c832016-10-21 14:26:00 +0200511 }
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200512 if (append_eol && write(msg_fd, "\n", 1) < 0) {
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200513 error_errno(_("could not write eol to '%s'"), filename);
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200514 rollback_lock_file(&msg_file);
Johannes Schindelinbf5c0572018-04-25 14:28:17 +0200515 return -1;
Johannes Schindelinf56fffe2016-10-21 14:26:09 +0200516 }
Martin Ågren350292a2018-02-28 20:07:58 +0100517 if (commit_lock_file(&msg_file) < 0)
518 return error(_("failed to finalize '%s'"), filename);
Johannes Schindelin4ef3d8f2016-09-09 16:37:05 +0200519
520 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530521}
522
Denton Liuc20de8b2020-04-07 10:27:54 -0400523int read_oneliner(struct strbuf *buf,
Denton Liu3442c3d2020-04-07 10:27:52 -0400524 const char *path, unsigned flags)
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200525{
526 int orig_len = buf->len;
527
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200528 if (strbuf_read_file(buf, path, 0) < 0) {
Denton Liubfa50c22020-04-07 10:27:53 -0400529 if ((flags & READ_ONELINER_WARN_MISSING) ||
530 (errno != ENOENT && errno != ENOTDIR))
Denton Liu5b2f6d92020-04-07 10:27:51 -0400531 warning_errno(_("could not read '%s'"), path);
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200532 return 0;
533 }
534
535 if (buf->len > orig_len && buf->buf[buf->len - 1] == '\n') {
536 if (--buf->len > orig_len && buf->buf[buf->len - 1] == '\r')
537 --buf->len;
538 buf->buf[buf->len] = '\0';
539 }
540
Denton Liu3442c3d2020-04-07 10:27:52 -0400541 if ((flags & READ_ONELINER_SKIP_IF_EMPTY) && buf->len == orig_len)
Johannes Schindelin1dfc84e2016-10-21 14:25:08 +0200542 return 0;
543
544 return 1;
545}
546
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100547static struct tree *empty_tree(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530548{
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100549 return lookup_tree(r, the_hash_algo->empty_tree);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530550}
551
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700552static int error_dirty_index(struct repository *repo, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530553{
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700554 if (repo_read_index_unmerged(repo))
Michael J Gruber1c8dfc32022-08-18 15:13:27 +0200555 return error_resolve_conflict(action_name(opts));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530556
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200557 error(_("your local changes would be overwritten by %s."),
Johannes Schindelinc28cbc52016-10-21 14:26:17 +0200558 _(action_name(opts)));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530559
Ben Boeckeled9bff02021-08-23 12:44:00 +0200560 if (advice_enabled(ADVICE_COMMIT_BEFORE_MERGE))
Johannes Schindelin93b3df62016-10-21 14:26:25 +0200561 advise(_("commit your changes or stash them to proceed."));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530562 return -1;
563}
564
Stephan Beyer1e412292016-12-07 22:51:32 +0100565static void update_abort_safety_file(void)
566{
567 struct object_id head;
568
569 /* Do nothing on a single-pick */
570 if (!file_exists(git_path_seq_dir()))
571 return;
572
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +0200573 if (!repo_get_oid(the_repository, "HEAD", &head))
Stephan Beyer1e412292016-12-07 22:51:32 +0100574 write_file(git_path_abort_safety_file(), "%s", oid_to_hex(&head));
575 else
576 write_file(git_path_abort_safety_file(), "%s", "");
577}
578
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100579static int fast_forward_to(struct repository *r,
580 const struct object_id *to,
581 const struct object_id *from,
582 int unborn,
583 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530584{
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700585 struct ref_transaction *transaction;
Ramkumar Ramachandraeb4be1c2013-06-19 13:07:09 +0530586 struct strbuf sb = STRBUF_INIT;
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700587 struct strbuf err = STRBUF_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530588
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700589 repo_read_index(r);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100590 if (checkout_fast_forward(r, from, to, 1))
Johannes Schindelin0e408fc2016-09-09 16:37:55 +0200591 return -1; /* the callee should have complained already */
Ronnie Sahlberg651ab9f2014-04-16 11:56:52 -0700592
Michael J Gruber5670e0e2022-08-18 15:13:26 +0200593 strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700594
595 transaction = ref_transaction_begin(&err);
596 if (!transaction ||
597 ref_transaction_update(transaction, "HEAD",
Johannes Schindelind87d48b2018-05-04 01:01:17 +0200598 to, unborn && !is_rebase_i(opts) ?
brian m. carlson14228442021-04-26 01:02:56 +0000599 null_oid() : from,
Michael Haggerty1d147bd2015-02-17 18:00:15 +0100600 0, sb.buf, &err) ||
Ronnie Sahlbergdb7516a2014-04-30 12:22:42 -0700601 ref_transaction_commit(transaction, &err)) {
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700602 ref_transaction_free(transaction);
603 error("%s", err.buf);
604 strbuf_release(&sb);
605 strbuf_release(&err);
606 return -1;
607 }
Ronnie Sahlberg651ab9f2014-04-16 11:56:52 -0700608
Ramkumar Ramachandraeb4be1c2013-06-19 13:07:09 +0530609 strbuf_release(&sb);
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700610 strbuf_release(&err);
611 ref_transaction_free(transaction);
Stephan Beyer1e412292016-12-07 22:51:32 +0100612 update_abort_safety_file();
Ronnie Sahlbergd668d162014-04-16 15:37:45 -0700613 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530614}
615
Denton Liuf29cd862019-04-17 11:23:25 +0100616enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
617 int use_editor)
618{
619 if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
620 return use_editor ? COMMIT_MSG_CLEANUP_ALL :
621 COMMIT_MSG_CLEANUP_SPACE;
622 else if (!strcmp(cleanup_arg, "verbatim"))
623 return COMMIT_MSG_CLEANUP_NONE;
624 else if (!strcmp(cleanup_arg, "whitespace"))
625 return COMMIT_MSG_CLEANUP_SPACE;
626 else if (!strcmp(cleanup_arg, "strip"))
627 return COMMIT_MSG_CLEANUP_ALL;
628 else if (!strcmp(cleanup_arg, "scissors"))
629 return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
630 COMMIT_MSG_CLEANUP_SPACE;
631 else
632 die(_("Invalid cleanup mode %s"), cleanup_arg);
633}
634
Phillip Wooddc42e9a2019-04-17 11:23:29 +0100635/*
636 * NB using int rather than enum cleanup_mode to stop clang's
637 * -Wtautological-constant-out-of-range-compare complaining that the comparison
638 * is always true.
639 */
640static const char *describe_cleanup_mode(int cleanup_mode)
641{
642 static const char *modes[] = { "whitespace",
643 "verbatim",
644 "scissors",
645 "strip" };
646
647 if (cleanup_mode < ARRAY_SIZE(modes))
648 return modes[cleanup_mode];
649
650 BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
651}
652
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100653void append_conflicts_hint(struct index_state *istate,
Denton Liu1a2b9852019-04-17 11:23:30 +0100654 struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
Junio C Hamano75c961b2014-10-24 11:34:59 -0700655{
656 int i;
657
Denton Liu1a2b9852019-04-17 11:23:30 +0100658 if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
659 strbuf_addch(msgbuf, '\n');
660 wt_status_append_cut_line(msgbuf);
661 strbuf_addch(msgbuf, comment_line_char);
662 }
663
Junio C Hamano261f3152014-10-28 13:04:38 -0700664 strbuf_addch(msgbuf, '\n');
Calvin Wan787cb8a2023-06-06 19:48:43 +0000665 strbuf_commented_addf(msgbuf, comment_line_char, "Conflicts:\n");
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100666 for (i = 0; i < istate->cache_nr;) {
667 const struct cache_entry *ce = istate->cache[i++];
Junio C Hamano75c961b2014-10-24 11:34:59 -0700668 if (ce_stage(ce)) {
Calvin Wan787cb8a2023-06-06 19:48:43 +0000669 strbuf_commented_addf(msgbuf, comment_line_char,
670 "\t%s\n", ce->name);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100671 while (i < istate->cache_nr &&
672 !strcmp(ce->name, istate->cache[i]->name))
Junio C Hamano75c961b2014-10-24 11:34:59 -0700673 i++;
674 }
675 }
676}
677
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100678static int do_recursive_merge(struct repository *r,
679 struct commit *base, struct commit *next,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530680 const char *base_label, const char *next_label,
brian m. carlson48be4c62017-05-06 22:10:36 +0000681 struct object_id *head, struct strbuf *msgbuf,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530682 struct replay_opts *opts)
683{
684 struct merge_options o;
Elijah Newren14c45862020-11-02 23:45:34 +0000685 struct merge_result result;
Elijah Newrenb4db8a22019-08-17 11:41:30 -0700686 struct tree *next_tree, *base_tree, *head_tree;
Elijah Newren14c45862020-11-02 23:45:34 +0000687 int clean, show_output;
Jeff Kingd20bc012020-01-29 00:46:47 -0500688 int i;
Martin Ågren14bca6c2018-02-27 22:30:09 +0100689 struct lock_file index_lock = LOCK_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530690
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +0700691 if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0)
Phillip Woodbd588862017-11-15 10:41:25 +0000692 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530693
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700694 repo_read_index(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530695
Nguyễn Thái Ngọc Duy0d6caa22019-01-12 09:13:29 +0700696 init_merge_options(&o, r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530697 o.ancestor = base ? base_label : "(empty tree)";
698 o.branch1 = "HEAD";
699 o.branch2 = next ? next_label : "(empty tree)";
Johannes Schindelin62fdb652017-01-02 16:35:39 +0100700 if (is_rebase_i(opts))
701 o.buffer_output = 2;
Elijah Newren9268cf42017-11-13 12:16:00 -0800702 o.show_rename_progress = 1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530703
704 head_tree = parse_tree_indirect(head);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +0200705 next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
706 base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530707
Phillip Woodfb60b9f2023-04-10 10:08:28 +0100708 for (i = 0; i < opts->xopts.nr; i++)
709 parse_merge_opt(&o, opts->xopts.v[i]);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530710
Elijah Newren6a5fb962021-08-04 05:38:01 +0000711 if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
Elijah Newren14c45862020-11-02 23:45:34 +0000712 memset(&result, 0, sizeof(result));
713 merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,
714 &result);
715 show_output = !is_rebase_i(opts) || !result.clean;
716 /*
717 * TODO: merge_switch_to_result will update index/working tree;
718 * we only really want to do that if !result.clean || this is
719 * the final patch to be picked. But determining this is the
720 * final patch would take some work, and "head_tree" would need
721 * to be replace with the tree the index matched before we
722 * started doing any picks.
723 */
724 merge_switch_to_result(&o, head_tree, &result, 1, show_output);
725 clean = result.clean;
726 } else {
Derrick Stolee5d9c9342021-09-08 11:24:00 +0000727 ensure_full_index(r->index);
Elijah Newren14c45862020-11-02 23:45:34 +0000728 clean = merge_trees(&o, head_tree, next_tree, base_tree);
729 if (is_rebase_i(opts) && clean <= 0)
730 fputs(o.obuf.buf, stdout);
731 strbuf_release(&o.obuf);
732 }
Martin Ågren64816522018-02-27 22:30:10 +0100733 if (clean < 0) {
734 rollback_lock_file(&index_lock);
Johannes Schindelinf241ff02016-07-26 18:06:02 +0200735 return clean;
Martin Ågren64816522018-02-27 22:30:10 +0100736 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530737
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100738 if (write_locked_index(r->index, &index_lock,
Martin Ågren61000812018-03-01 21:40:20 +0100739 COMMIT_LOCK | SKIP_IF_UNCHANGED))
Ævar Arnfjörð Bjarmason66f5f6d2017-05-11 21:20:12 +0000740 /*
741 * TRANSLATORS: %s will be "revert", "cherry-pick" or
Elijah Newrenc2417d32020-02-15 21:36:36 +0000742 * "rebase".
Johannes Schindelin84583952017-01-02 16:26:28 +0100743 */
Johannes Schindelinc527b552016-09-09 16:37:10 +0200744 return error(_("%s: Unable to write new index file"),
Johannes Schindelinc28cbc52016-10-21 14:26:17 +0200745 _(action_name(opts)));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530746
Junio C Hamano75c961b2014-10-24 11:34:59 -0700747 if (!clean)
Denton Liu1a2b9852019-04-17 11:23:30 +0100748 append_conflicts_hint(r->index, msgbuf,
749 opts->default_msg_cleanup);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530750
751 return !clean;
752}
753
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100754static struct object_id *get_cache_tree_oid(struct index_state *istate)
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200755{
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100756 if (!cache_tree_fully_valid(istate->cache_tree))
757 if (cache_tree_update(istate, 0)) {
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200758 error(_("unable to update cache tree"));
759 return NULL;
760 }
761
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100762 return &istate->cache_tree->oid;
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200763}
764
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100765static int is_index_unchanged(struct repository *r)
Neil Hormanb27cfb02012-04-20 10:36:15 -0400766{
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200767 struct object_id head_oid, *cache_tree_oid;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400768 struct commit *head_commit;
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100769 struct index_state *istate = r->index;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400770
brian m. carlson49e61472017-10-15 22:07:09 +0000771 if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
Johannes Schindelinaee42e12017-12-23 00:55:43 +0100772 return error(_("could not resolve HEAD commit"));
Neil Hormanb27cfb02012-04-20 10:36:15 -0400773
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +0100774 head_commit = lookup_commit(r, &head_oid);
Neil Horman4b580062012-05-03 08:10:22 -0400775
776 /*
777 * If head_commit is NULL, check_commit, called from
778 * lookup_commit, would have indicated that head_commit is not
Ævar Arnfjörð Bjarmasonc7c33f52023-03-28 15:58:57 +0200779 * a commit object already. repo_parse_commit() will return failure
Neil Horman4b580062012-05-03 08:10:22 -0400780 * without further complaints in such a case. Otherwise, if
Ævar Arnfjörð Bjarmasonc7c33f52023-03-28 15:58:57 +0200781 * the commit is invalid, repo_parse_commit() will complain. So
Neil Horman4b580062012-05-03 08:10:22 -0400782 * there is nothing for us to say here. Just return failure.
783 */
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +0200784 if (repo_parse_commit(r, head_commit))
Neil Horman4b580062012-05-03 08:10:22 -0400785 return -1;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400786
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +0100787 if (!(cache_tree_oid = get_cache_tree_oid(istate)))
Johannes Schindelinba97aea2018-05-04 01:01:15 +0200788 return -1;
Neil Hormanb27cfb02012-04-20 10:36:15 -0400789
Jeff King4a7e27e2018-08-28 17:22:40 -0400790 return oideq(cache_tree_oid, get_commit_tree_oid(head_commit));
Neil Hormanb27cfb02012-04-20 10:36:15 -0400791}
792
Johannes Schindelin0473f282017-01-02 16:27:18 +0100793static int write_author_script(const char *message)
794{
795 struct strbuf buf = STRBUF_INIT;
796 const char *eol;
797 int res;
798
799 for (;;)
800 if (!*message || starts_with(message, "\n")) {
801missing_author:
802 /* Missing 'author' line? */
803 unlink(rebase_path_author_script());
804 return 0;
805 } else if (skip_prefix(message, "author ", &message))
806 break;
807 else if ((eol = strchr(message, '\n')))
808 message = eol + 1;
809 else
810 goto missing_author;
811
812 strbuf_addstr(&buf, "GIT_AUTHOR_NAME='");
813 while (*message && *message != '\n' && *message != '\r')
814 if (skip_prefix(message, " <", &message))
815 break;
816 else if (*message != '\'')
817 strbuf_addch(&buf, *(message++));
818 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100819 strbuf_addf(&buf, "'\\%c'", *(message++));
Johannes Schindelin0473f282017-01-02 16:27:18 +0100820 strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
821 while (*message && *message != '\n' && *message != '\r')
822 if (skip_prefix(message, "> ", &message))
823 break;
824 else if (*message != '\'')
825 strbuf_addch(&buf, *(message++));
826 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100827 strbuf_addf(&buf, "'\\%c'", *(message++));
Johannes Schindelin0473f282017-01-02 16:27:18 +0100828 strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
829 while (*message && *message != '\n' && *message != '\r')
830 if (*message != '\'')
831 strbuf_addch(&buf, *(message++));
832 else
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100833 strbuf_addf(&buf, "'\\%c'", *(message++));
Eric Sunshine0f16c092018-07-31 03:33:29 -0400834 strbuf_addch(&buf, '\'');
Johannes Schindelin0473f282017-01-02 16:27:18 +0100835 res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
836 strbuf_release(&buf);
837 return res;
838}
839
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000840/**
841 * Take a series of KEY='VALUE' lines where VALUE part is
842 * sq-quoted, and append <KEY, VALUE> at the end of the string list
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100843 */
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000844static int parse_key_value_squoted(char *buf, struct string_list *list)
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100845{
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000846 while (*buf) {
847 struct string_list_item *item;
848 char *np;
849 char *cp = strchr(buf, '=');
850 if (!cp) {
851 np = strchrnul(buf, '\n');
852 return error(_("no key present in '%.*s'"),
853 (int) (np - buf), buf);
854 }
855 np = strchrnul(cp, '\n');
856 *cp++ = '\0';
857 item = string_list_append(list, buf);
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100858
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000859 buf = np + (*np == '\n');
860 *np = '\0';
861 cp = sq_dequote(cp);
862 if (!cp)
863 return error(_("unable to dequote value of '%s'"),
864 item->string);
865 item->util = xstrdup(cp);
866 }
Phillip Wood4aa5ff92018-08-07 10:34:52 +0100867 return 0;
868}
869
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000870/**
871 * Reads and parses the state directory's "author-script" file, and sets name,
872 * email and date accordingly.
873 * Returns 0 on success, -1 if the file could not be parsed.
874 *
875 * The author script is of the format:
876 *
877 * GIT_AUTHOR_NAME='$author_name'
878 * GIT_AUTHOR_EMAIL='$author_email'
879 * GIT_AUTHOR_DATE='$author_date'
880 *
881 * where $author_name, $author_email and $author_date are quoted. We are strict
Johannes Schindelinc3c003e2019-05-14 04:22:33 -0700882 * with our parsing, as the file was meant to be eval'd in the now-removed
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000883 * git-am.sh/git-rebase--interactive.sh scripts, and thus if the file differs
884 * from what this function expects, it is better to bail out than to do
885 * something that the user does not expect.
886 */
887int read_author_script(const char *path, char **name, char **email, char **date,
888 int allow_missing)
889{
890 struct strbuf buf = STRBUF_INIT;
891 struct string_list kv = STRING_LIST_INIT_DUP;
892 int retval = -1; /* assume failure */
893 int i, name_i = -2, email_i = -2, date_i = -2, err = 0;
894
895 if (strbuf_read_file(&buf, path, 256) <= 0) {
896 strbuf_release(&buf);
897 if (errno == ENOENT && allow_missing)
898 return 0;
899 else
900 return error_errno(_("could not open '%s' for reading"),
901 path);
902 }
903
904 if (parse_key_value_squoted(buf.buf, &kv))
905 goto finish;
906
907 for (i = 0; i < kv.nr; i++) {
908 if (!strcmp(kv.items[i].string, "GIT_AUTHOR_NAME")) {
909 if (name_i != -2)
910 name_i = error(_("'GIT_AUTHOR_NAME' already given"));
911 else
912 name_i = i;
913 } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_EMAIL")) {
914 if (email_i != -2)
915 email_i = error(_("'GIT_AUTHOR_EMAIL' already given"));
916 else
917 email_i = i;
918 } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_DATE")) {
919 if (date_i != -2)
920 date_i = error(_("'GIT_AUTHOR_DATE' already given"));
921 else
922 date_i = i;
923 } else {
924 err = error(_("unknown variable '%s'"),
925 kv.items[i].string);
926 }
927 }
928 if (name_i == -2)
929 error(_("missing 'GIT_AUTHOR_NAME'"));
930 if (email_i == -2)
931 error(_("missing 'GIT_AUTHOR_EMAIL'"));
932 if (date_i == -2)
933 error(_("missing 'GIT_AUTHOR_DATE'"));
Jeff King45350ae2022-10-03 13:35:02 -0400934 if (name_i < 0 || email_i < 0 || date_i < 0 || err)
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000935 goto finish;
Junio C Hamano4d924522020-01-12 12:27:41 -0800936 *name = kv.items[name_i].util;
937 *email = kv.items[email_i].util;
938 *date = kv.items[date_i].util;
Phillip Woodbcd33ec2018-10-31 10:15:55 +0000939 retval = 0;
940finish:
941 string_list_clear(&kv, !!retval);
942 strbuf_release(&buf);
943 return retval;
944}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530945
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +0530946/*
Phillip Wood4d010a72018-10-31 10:15:56 +0000947 * Read a GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL AND GIT_AUTHOR_DATE from a
Jeff Kingc972bf42020-07-28 16:25:12 -0400948 * file with shell quoting into struct strvec. Returns -1 on
Phillip Wood4d010a72018-10-31 10:15:56 +0000949 * error, 0 otherwise.
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200950 */
Jeff Kingc972bf42020-07-28 16:25:12 -0400951static int read_env_script(struct strvec *env)
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200952{
Phillip Wood4d010a72018-10-31 10:15:56 +0000953 char *name, *email, *date;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200954
Phillip Wood4d010a72018-10-31 10:15:56 +0000955 if (read_author_script(rebase_path_author_script(),
956 &name, &email, &date, 0))
Johannes Schindelina2a20b02017-01-02 16:35:25 +0100957 return -1;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200958
Jeff Kingc972bf42020-07-28 16:25:12 -0400959 strvec_pushf(env, "GIT_AUTHOR_NAME=%s", name);
960 strvec_pushf(env, "GIT_AUTHOR_EMAIL=%s", email);
961 strvec_pushf(env, "GIT_AUTHOR_DATE=%s", date);
Phillip Wood4d010a72018-10-31 10:15:56 +0000962 free(name);
963 free(email);
964 free(date);
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200965
Johannes Schindelina2a20b02017-01-02 16:35:25 +0100966 return 0;
Johannes Schindelinb5a67042016-10-21 14:25:04 +0200967}
968
Phillip Wood356ee462017-11-24 11:07:57 +0000969static char *get_author(const char *message)
970{
971 size_t len;
972 const char *a;
973
974 a = find_commit_header(message, "author", &len);
975 if (a)
976 return xmemdupz(a, len);
977
978 return NULL;
979}
980
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +0200981static const char *author_date_from_env(const struct strvec *env)
Phillip Wood7573cec2020-08-17 18:40:02 +0100982{
983 int i;
984 const char *date;
985
Junio C Hamano9c31b192020-09-03 12:37:01 -0700986 for (i = 0; i < env->nr; i++)
987 if (skip_prefix(env->v[i],
Phillip Wood7573cec2020-08-17 18:40:02 +0100988 "GIT_AUTHOR_DATE=", &date))
989 return date;
990 /*
991 * If GIT_AUTHOR_DATE is missing we should have already errored out when
992 * reading the script
993 */
994 BUG("GIT_AUTHOR_DATE missing from author script");
995}
996
Johannes Schindelin791eb872016-10-21 14:26:32 +0200997static const char staged_changes_advice[] =
998N_("you have staged changes in your working tree\n"
999"If these changes are meant to be squashed into the previous commit, run:\n"
1000"\n"
1001" git commit --amend %s\n"
1002"\n"
1003"If they are meant to go into a new commit, run:\n"
1004"\n"
1005" git commit %s\n"
1006"\n"
1007"In both cases, once you're done, continue with:\n"
1008"\n"
1009" git rebase --continue\n");
1010
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001011#define ALLOW_EMPTY (1<<0)
1012#define EDIT_MSG (1<<1)
1013#define AMEND_MSG (1<<2)
1014#define CLEANUP_MSG (1<<3)
Johannes Schindelinb92ff6e2017-03-23 17:07:17 +01001015#define VERIFY_MSG (1<<4)
Johannes Schindelind87d48b2018-05-04 01:01:17 +02001016#define CREATE_ROOT_COMMIT (1<<5)
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001017#define VERBATIM_MSG (1<<6)
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001018
Alban Gruin34bec2c2018-08-10 18:51:32 +02001019static int run_command_silent_on_success(struct child_process *cmd)
1020{
1021 struct strbuf buf = STRBUF_INIT;
1022 int rc;
1023
1024 cmd->stdout_to_stderr = 1;
1025 rc = pipe_command(cmd,
1026 NULL, 0,
1027 NULL, 0,
1028 &buf, 0);
1029
1030 if (rc)
1031 fputs(buf.buf, stderr);
1032 strbuf_release(&buf);
1033 return rc;
1034}
1035
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001036/*
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301037 * If we are cherry-pick, and if the merge did not result in
1038 * hand-editing, we will hit this commit and inherit the original
1039 * author date and name.
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001040 *
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301041 * If we are revert, or if our cherry-pick results in a hand merge,
1042 * we had better say that the current user is responsible for that.
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001043 *
1044 * An exception is when run_git_commit() is called during an
1045 * interactive rebase: in that case, we will want to retain the
1046 * author metadata.
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301047 */
Jeff King20f4b042020-09-30 08:29:31 -04001048static int run_git_commit(const char *defmsg,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001049 struct replay_opts *opts,
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001050 unsigned int flags)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301051{
Johannes Schindelin07d968e2017-01-02 16:35:29 +01001052 struct child_process cmd = CHILD_PROCESS_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301053
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001054 if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
1055 BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive");
1056
Johannes Schindelin07d968e2017-01-02 16:35:29 +01001057 cmd.git_cmd = 1;
1058
Phillip Wood9d6b9df2021-11-02 21:30:51 +00001059 if (is_rebase_i(opts) &&
1060 ((opts->committer_date_is_author_date && !opts->ignore_date) ||
1061 !(!defmsg && (flags & AMEND_MSG))) &&
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001062 read_env_script(&cmd.env)) {
Alban Gruin34bec2c2018-08-10 18:51:32 +02001063 const char *gpg_opt = gpg_sign_opt_quoted(opts);
Johannes Schindelin9a757c42017-01-02 16:35:34 +01001064
Alban Gruin34bec2c2018-08-10 18:51:32 +02001065 return error(_(staged_changes_advice),
1066 gpg_opt, gpg_opt);
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001067 }
1068
Phillip Woodd188a602022-11-09 14:21:57 +00001069 strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", opts->reflog_message);
1070
Phillip Wood7573cec2020-08-17 18:40:02 +01001071 if (opts->committer_date_is_author_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001072 strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
Junio C Hamano9c31b192020-09-03 12:37:01 -07001073 opts->ignore_date ?
1074 "" :
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +02001075 author_date_from_env(&cmd.env));
Phillip Wooda3894aa2020-08-17 18:40:03 +01001076 if (opts->ignore_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02001077 strvec_push(&cmd.env, "GIT_AUTHOR_DATE=");
Phillip Wood7573cec2020-08-17 18:40:02 +01001078
Jeff Kingc972bf42020-07-28 16:25:12 -04001079 strvec_push(&cmd.args, "commit");
Neil Hormanb27cfb02012-04-20 10:36:15 -04001080
Johannes Schindelinb92ff6e2017-03-23 17:07:17 +01001081 if (!(flags & VERIFY_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001082 strvec_push(&cmd.args, "-n");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001083 if ((flags & AMEND_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001084 strvec_push(&cmd.args, "--amend");
Jeff King3bdd5522014-06-19 17:28:20 -04001085 if (opts->gpg_sign)
Jeff Kingc972bf42020-07-28 16:25:12 -04001086 strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
Đoàn Trần Công Danhcf0ad4d2020-04-03 17:28:03 +07001087 else
Jeff Kingc972bf42020-07-28 16:25:12 -04001088 strvec_push(&cmd.args, "--no-gpg-sign");
Johannes Schindelinb5a67042016-10-21 14:25:04 +02001089 if (defmsg)
Jeff Kingc972bf42020-07-28 16:25:12 -04001090 strvec_pushl(&cmd.args, "-F", defmsg, NULL);
Johannes Schindelindc4b5bc2018-04-27 22:48:28 +02001091 else if (!(flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001092 strvec_pushl(&cmd.args, "-C", "HEAD", NULL);
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001093 if ((flags & CLEANUP_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001094 strvec_push(&cmd.args, "--cleanup=strip");
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001095 if ((flags & VERBATIM_MSG))
1096 strvec_push(&cmd.args, "--cleanup=verbatim");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001097 if ((flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001098 strvec_push(&cmd.args, "-e");
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001099 else if (!(flags & CLEANUP_MSG) &&
Johannes Schindelin00094262016-10-21 14:25:28 +02001100 !opts->signoff && !opts->record_origin &&
Denton Liu1a2b9852019-04-17 11:23:30 +01001101 !opts->explicit_cleanup)
Jeff Kingc972bf42020-07-28 16:25:12 -04001102 strvec_push(&cmd.args, "--cleanup=verbatim");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301103
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01001104 if ((flags & ALLOW_EMPTY))
Jeff Kingc972bf42020-07-28 16:25:12 -04001105 strvec_push(&cmd.args, "--allow-empty");
Neil Hormandf478b72012-04-11 16:21:53 -04001106
Elijah Newrena3ec9ea2018-09-12 14:18:48 -07001107 if (!(flags & EDIT_MSG))
Jeff Kingc972bf42020-07-28 16:25:12 -04001108 strvec_push(&cmd.args, "--allow-empty-message");
Chris Webb4bee9582012-08-02 11:38:51 +01001109
Alban Gruin34bec2c2018-08-10 18:51:32 +02001110 if (is_rebase_i(opts) && !(flags & EDIT_MSG))
1111 return run_command_silent_on_success(&cmd);
1112 else
1113 return run_command(&cmd);
Neil Hormanb27cfb02012-04-20 10:36:15 -04001114}
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301115
Phillip Woodd0aaa462017-11-10 11:09:42 +00001116static int rest_is_empty(const struct strbuf *sb, int start)
1117{
1118 int i, eol;
1119 const char *nl;
1120
1121 /* Check if the rest is just whitespace and Signed-off-by's. */
1122 for (i = start; i < sb->len; i++) {
1123 nl = memchr(sb->buf + i, '\n', sb->len - i);
1124 if (nl)
1125 eol = nl - sb->buf;
1126 else
1127 eol = sb->len;
1128
1129 if (strlen(sign_off_header) <= eol - i &&
1130 starts_with(sb->buf + i, sign_off_header)) {
1131 i = eol;
1132 continue;
1133 }
1134 while (i < eol)
1135 if (!isspace(sb->buf[i++]))
1136 return 0;
1137 }
1138
1139 return 1;
1140}
1141
Denton Liuf29cd862019-04-17 11:23:25 +01001142void cleanup_message(struct strbuf *msgbuf,
1143 enum commit_msg_cleanup_mode cleanup_mode, int verbose)
1144{
1145 if (verbose || /* Truncate the message just before the diff, if any. */
1146 cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
1147 strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
1148 if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
Calvin Wan787cb8a2023-06-06 19:48:43 +00001149 strbuf_stripspace(msgbuf,
1150 cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
Denton Liuf29cd862019-04-17 11:23:25 +01001151}
1152
Phillip Woodd0aaa462017-11-10 11:09:42 +00001153/*
1154 * Find out if the message in the strbuf contains only whitespace and
1155 * Signed-off-by lines.
1156 */
1157int message_is_empty(const struct strbuf *sb,
1158 enum commit_msg_cleanup_mode cleanup_mode)
1159{
1160 if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
1161 return 0;
1162 return rest_is_empty(sb, 0);
1163}
1164
1165/*
1166 * See if the user edited the message in the editor or left what
1167 * was in the template intact
1168 */
1169int template_untouched(const struct strbuf *sb, const char *template_file,
1170 enum commit_msg_cleanup_mode cleanup_mode)
1171{
1172 struct strbuf tmpl = STRBUF_INIT;
1173 const char *start;
1174
1175 if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
1176 return 0;
1177
1178 if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
1179 return 0;
1180
Calvin Wan787cb8a2023-06-06 19:48:43 +00001181 strbuf_stripspace(&tmpl,
1182 cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
Phillip Woodd0aaa462017-11-10 11:09:42 +00001183 if (!skip_prefix(sb->buf, tmpl.buf, &start))
1184 start = sb->buf;
1185 strbuf_release(&tmpl);
1186 return rest_is_empty(sb, start - sb->buf);
1187}
1188
Phillip Wood0505d602017-11-17 11:34:47 +00001189int update_head_with_reflog(const struct commit *old_head,
1190 const struct object_id *new_head,
1191 const char *action, const struct strbuf *msg,
1192 struct strbuf *err)
1193{
1194 struct ref_transaction *transaction;
1195 struct strbuf sb = STRBUF_INIT;
1196 const char *nl;
1197 int ret = 0;
1198
1199 if (action) {
1200 strbuf_addstr(&sb, action);
1201 strbuf_addstr(&sb, ": ");
1202 }
1203
1204 nl = strchr(msg->buf, '\n');
1205 if (nl) {
1206 strbuf_add(&sb, msg->buf, nl + 1 - msg->buf);
1207 } else {
1208 strbuf_addbuf(&sb, msg);
1209 strbuf_addch(&sb, '\n');
1210 }
1211
1212 transaction = ref_transaction_begin(err);
1213 if (!transaction ||
1214 ref_transaction_update(transaction, "HEAD", new_head,
brian m. carlson14228442021-04-26 01:02:56 +00001215 old_head ? &old_head->object.oid : null_oid(),
Phillip Wood0505d602017-11-17 11:34:47 +00001216 0, sb.buf, err) ||
1217 ref_transaction_commit(transaction, err)) {
1218 ret = -1;
1219 }
1220 ref_transaction_free(transaction);
1221 strbuf_release(&sb);
1222
1223 return ret;
1224}
1225
Phillip Wooda87a6f32017-11-17 11:34:48 +00001226static int run_rewrite_hook(const struct object_id *oldoid,
1227 const struct object_id *newoid)
1228{
1229 struct child_process proc = CHILD_PROCESS_INIT;
Phillip Wooda87a6f32017-11-17 11:34:48 +00001230 int code;
1231 struct strbuf sb = STRBUF_INIT;
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001232 const char *hook_path = find_hook("post-rewrite");
Phillip Wooda87a6f32017-11-17 11:34:48 +00001233
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001234 if (!hook_path)
Phillip Wooda87a6f32017-11-17 11:34:48 +00001235 return 0;
1236
Ævar Arnfjörð Bjarmason2b709892021-11-25 23:52:20 +01001237 strvec_pushl(&proc.args, hook_path, "amend", NULL);
Phillip Wooda87a6f32017-11-17 11:34:48 +00001238 proc.in = -1;
1239 proc.stdout_to_stderr = 1;
Jeff Hostetler62062862019-02-22 14:25:06 -08001240 proc.trace2_hook_name = "post-rewrite";
Phillip Wooda87a6f32017-11-17 11:34:48 +00001241
1242 code = start_command(&proc);
1243 if (code)
1244 return code;
1245 strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
1246 sigchain_push(SIGPIPE, SIG_IGN);
1247 write_in_full(proc.in, sb.buf, sb.len);
1248 close(proc.in);
1249 strbuf_release(&sb);
1250 sigchain_pop(SIGPIPE);
1251 return finish_command(&proc);
1252}
1253
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001254void commit_post_rewrite(struct repository *r,
1255 const struct commit *old_head,
Phillip Wooda87a6f32017-11-17 11:34:48 +00001256 const struct object_id *new_head)
1257{
1258 struct notes_rewrite_cfg *cfg;
1259
1260 cfg = init_copy_notes_for_rewrite("amend");
1261 if (cfg) {
1262 /* we are amending, so old_head is not NULL */
1263 copy_note_for_rewrite(cfg, &old_head->object.oid, new_head);
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001264 finish_copy_notes_for_rewrite(r, cfg, "Notes added by 'git commit --amend'");
Phillip Wooda87a6f32017-11-17 11:34:48 +00001265 }
1266 run_rewrite_hook(&old_head->object.oid, new_head);
1267}
1268
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001269static int run_prepare_commit_msg_hook(struct repository *r,
1270 struct strbuf *msg,
1271 const char *commit)
Phillip Wood66618a52018-01-24 12:34:22 +00001272{
Phillip Wood49697cb2019-10-15 10:25:31 +00001273 int ret = 0;
1274 const char *name, *arg1 = NULL, *arg2 = NULL;
Phillip Wood66618a52018-01-24 12:34:22 +00001275
1276 name = git_path_commit_editmsg();
1277 if (write_message(msg->buf, msg->len, name, 0))
1278 return -1;
1279
Phillip Wood49697cb2019-10-15 10:25:31 +00001280 if (commit) {
1281 arg1 = "commit";
1282 arg2 = commit;
1283 } else {
1284 arg1 = "message";
1285 }
Ævar Arnfjörð Bjarmasona8cc5942022-03-07 13:33:46 +01001286 if (run_commit_hook(0, r->index_file, NULL, "prepare-commit-msg", name,
Phillip Wood49697cb2019-10-15 10:25:31 +00001287 arg1, arg2, NULL))
Phillip Wood66618a52018-01-24 12:34:22 +00001288 ret = error(_("'prepare-commit-msg' hook failed"));
Phillip Wood66618a52018-01-24 12:34:22 +00001289
1290 return ret;
1291}
1292
Phillip Woode47c6ca2017-11-24 11:07:54 +00001293static const char implicit_ident_advice_noconfig[] =
1294N_("Your name and email address were configured automatically based\n"
1295"on your username and hostname. Please check that they are accurate.\n"
1296"You can suppress this message by setting them explicitly. Run the\n"
1297"following command and follow the instructions in your editor to edit\n"
1298"your configuration file:\n"
1299"\n"
1300" git config --global --edit\n"
1301"\n"
1302"After doing this, you may fix the identity used for this commit with:\n"
1303"\n"
1304" git commit --amend --reset-author\n");
1305
1306static const char implicit_ident_advice_config[] =
1307N_("Your name and email address were configured automatically based\n"
1308"on your username and hostname. Please check that they are accurate.\n"
1309"You can suppress this message by setting them explicitly:\n"
1310"\n"
1311" git config --global user.name \"Your Name\"\n"
1312" git config --global user.email you@example.com\n"
1313"\n"
1314"After doing this, you may fix the identity used for this commit with:\n"
1315"\n"
1316" git commit --amend --reset-author\n");
1317
1318static const char *implicit_ident_advice(void)
1319{
Johannes Schindelina03b0972021-07-24 22:06:52 +00001320 char *user_config = interpolate_path("~/.gitconfig", 0);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001321 char *xdg_config = xdg_config_home("config");
1322 int config_exists = file_exists(user_config) || file_exists(xdg_config);
1323
1324 free(user_config);
1325 free(xdg_config);
1326
1327 if (config_exists)
1328 return _(implicit_ident_advice_config);
1329 else
1330 return _(implicit_ident_advice_noconfig);
1331
1332}
1333
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001334void print_commit_summary(struct repository *r,
1335 const char *prefix,
1336 const struct object_id *oid,
Phillip Woode47c6ca2017-11-24 11:07:54 +00001337 unsigned int flags)
1338{
1339 struct rev_info rev;
1340 struct commit *commit;
1341 struct strbuf format = STRBUF_INIT;
1342 const char *head;
1343 struct pretty_print_context pctx = {0};
1344 struct strbuf author_ident = STRBUF_INIT;
1345 struct strbuf committer_ident = STRBUF_INIT;
Ævar Arnfjörð Bjarmasoned90f042021-10-16 11:39:23 +02001346 struct ref_store *refs;
Phillip Woode47c6ca2017-11-24 11:07:54 +00001347
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001348 commit = lookup_commit(r, oid);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001349 if (!commit)
1350 die(_("couldn't look up newly created commit"));
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001351 if (repo_parse_commit(r, commit))
Phillip Woode47c6ca2017-11-24 11:07:54 +00001352 die(_("could not parse newly created commit"));
1353
1354 strbuf_addstr(&format, "format:%h] %s");
1355
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001356 repo_format_commit_message(r, commit, "%an <%ae>", &author_ident,
1357 &pctx);
1358 repo_format_commit_message(r, commit, "%cn <%ce>", &committer_ident,
1359 &pctx);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001360 if (strbuf_cmp(&author_ident, &committer_ident)) {
1361 strbuf_addstr(&format, "\n Author: ");
1362 strbuf_addbuf_percentquote(&format, &author_ident);
1363 }
1364 if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
1365 struct strbuf date = STRBUF_INIT;
1366
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001367 repo_format_commit_message(r, commit, "%ad", &date, &pctx);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001368 strbuf_addstr(&format, "\n Date: ");
1369 strbuf_addbuf_percentquote(&format, &date);
1370 strbuf_release(&date);
1371 }
1372 if (!committer_ident_sufficiently_given()) {
1373 strbuf_addstr(&format, "\n Committer: ");
1374 strbuf_addbuf_percentquote(&format, &committer_ident);
Ben Boeckeled9bff02021-08-23 12:44:00 +02001375 if (advice_enabled(ADVICE_IMPLICIT_IDENTITY)) {
Phillip Woode47c6ca2017-11-24 11:07:54 +00001376 strbuf_addch(&format, '\n');
1377 strbuf_addstr(&format, implicit_ident_advice());
1378 }
1379 }
1380 strbuf_release(&author_ident);
1381 strbuf_release(&committer_ident);
1382
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001383 repo_init_revisions(r, &rev, prefix);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001384 setup_revisions(0, NULL, &rev, NULL);
1385
1386 rev.diff = 1;
1387 rev.diffopt.output_format =
1388 DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
1389
1390 rev.verbose_header = 1;
1391 rev.show_root_diff = 1;
1392 get_commit_format(format.buf, &rev);
1393 rev.always_show_header = 0;
Junio C Hamano0f57f732018-02-13 13:39:15 -08001394 rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
Phillip Woode47c6ca2017-11-24 11:07:54 +00001395 diff_setup_done(&rev.diffopt);
1396
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001397 refs = get_main_ref_store(r);
Ævar Arnfjörð Bjarmasonce14de02022-01-26 15:37:01 +01001398 head = refs_resolve_ref_unsafe(refs, "HEAD", 0, NULL, NULL);
Ævar Arnfjörð Bjarmason09444e72022-01-26 15:37:00 +01001399 if (!head)
1400 die(_("unable to resolve HEAD after creating commit"));
Phillip Woode47c6ca2017-11-24 11:07:54 +00001401 if (!strcmp(head, "HEAD"))
1402 head = _("detached HEAD");
1403 else
1404 skip_prefix(head, "refs/heads/", &head);
1405 printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
1406 _(" (root-commit)") : "");
1407
1408 if (!log_tree_commit(&rev, commit)) {
1409 rev.always_show_header = 1;
1410 rev.use_terminator = 1;
1411 log_tree_commit(&rev, commit);
1412 }
1413
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02001414 release_revisions(&rev);
Phillip Woode47c6ca2017-11-24 11:07:54 +00001415 strbuf_release(&format);
1416}
1417
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001418static int parse_head(struct repository *r, struct commit **head)
Phillip Wood356ee462017-11-24 11:07:57 +00001419{
1420 struct commit *current_head;
1421 struct object_id oid;
1422
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001423 if (repo_get_oid(r, "HEAD", &oid)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001424 current_head = NULL;
1425 } else {
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001426 current_head = lookup_commit_reference(r, &oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001427 if (!current_head)
1428 return error(_("could not parse HEAD"));
Jeff King9001dc22018-08-28 17:22:48 -04001429 if (!oideq(&oid, &current_head->object.oid)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001430 warning(_("HEAD %s is not a commit!"),
1431 oid_to_hex(&oid));
1432 }
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001433 if (repo_parse_commit(r, current_head))
Phillip Wood356ee462017-11-24 11:07:57 +00001434 return error(_("could not parse HEAD commit"));
1435 }
1436 *head = current_head;
1437
1438 return 0;
1439}
1440
1441/*
1442 * Try to commit without forking 'git commit'. In some cases we need
1443 * to run 'git commit' to display an error message
1444 *
1445 * Returns:
1446 * -1 - error unable to commit
1447 * 0 - success
1448 * 1 - run 'git commit'
1449 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001450static int try_to_commit(struct repository *r,
1451 struct strbuf *msg, const char *author,
Phillip Wood356ee462017-11-24 11:07:57 +00001452 struct replay_opts *opts, unsigned int flags,
1453 struct object_id *oid)
1454{
1455 struct object_id tree;
Phillip Woodb0a31862019-08-19 02:18:23 -07001456 struct commit *current_head = NULL;
Phillip Wood356ee462017-11-24 11:07:57 +00001457 struct commit_list *parents = NULL;
1458 struct commit_extra_header *extra = NULL;
1459 struct strbuf err = STRBUF_INIT;
Phillip Wood66618a52018-01-24 12:34:22 +00001460 struct strbuf commit_msg = STRBUF_INIT;
Junio C Hamano4d924522020-01-12 12:27:41 -08001461 char *amend_author = NULL;
Phillip Wood7573cec2020-08-17 18:40:02 +01001462 const char *committer = NULL;
Phillip Wood66618a52018-01-24 12:34:22 +00001463 const char *hook_commit = NULL;
Phillip Wood356ee462017-11-24 11:07:57 +00001464 enum commit_msg_cleanup_mode cleanup;
1465 int res = 0;
1466
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001467 if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
1468 BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive");
1469
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001470 if (parse_head(r, &current_head))
Phillip Wood356ee462017-11-24 11:07:57 +00001471 return -1;
Junio C Hamano4d924522020-01-12 12:27:41 -08001472
Phillip Wood356ee462017-11-24 11:07:57 +00001473 if (flags & AMEND_MSG) {
brian m. carlson42d4e1d2020-02-22 20:17:42 +00001474 const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
Phillip Wood356ee462017-11-24 11:07:57 +00001475 const char *out_enc = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001476 const char *message = repo_logmsg_reencode(r, current_head,
1477 NULL, out_enc);
Phillip Wood356ee462017-11-24 11:07:57 +00001478
1479 if (!msg) {
1480 const char *orig_message = NULL;
1481
1482 find_commit_subject(message, &orig_message);
Phillip Wood66618a52018-01-24 12:34:22 +00001483 msg = &commit_msg;
Phillip Wood356ee462017-11-24 11:07:57 +00001484 strbuf_addstr(msg, orig_message);
Phillip Wood66618a52018-01-24 12:34:22 +00001485 hook_commit = "HEAD";
Phillip Wood356ee462017-11-24 11:07:57 +00001486 }
Junio C Hamano4d924522020-01-12 12:27:41 -08001487 author = amend_author = get_author(message);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02001488 repo_unuse_commit_buffer(r, current_head,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001489 message);
Phillip Wood356ee462017-11-24 11:07:57 +00001490 if (!author) {
1491 res = error(_("unable to parse commit author"));
1492 goto out;
1493 }
1494 parents = copy_commit_list(current_head->parents);
1495 extra = read_commit_extra_headers(current_head, exclude_gpgsig);
Phillip Woodb0a31862019-08-19 02:18:23 -07001496 } else if (current_head &&
1497 (!(flags & CREATE_ROOT_COMMIT) || (flags & AMEND_MSG))) {
Phillip Wood356ee462017-11-24 11:07:57 +00001498 commit_list_insert(current_head, &parents);
1499 }
1500
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001501 if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001502 res = error(_("git write-tree failed to write a tree"));
1503 goto out;
1504 }
1505
Phillip Wood2d05ef22019-11-22 19:43:03 +00001506 if (!(flags & ALLOW_EMPTY)) {
1507 struct commit *first_parent = current_head;
1508
1509 if (flags & AMEND_MSG) {
1510 if (current_head->parents) {
1511 first_parent = current_head->parents->item;
1512 if (repo_parse_commit(r, first_parent)) {
1513 res = error(_("could not parse HEAD commit"));
1514 goto out;
1515 }
1516 } else {
1517 first_parent = NULL;
1518 }
1519 }
1520 if (oideq(first_parent
1521 ? get_commit_tree_oid(first_parent)
1522 : the_hash_algo->empty_tree,
1523 &tree)) {
1524 res = 1; /* run 'git commit' to display error message */
1525 goto out;
1526 }
Phillip Wood356ee462017-11-24 11:07:57 +00001527 }
1528
Ævar Arnfjörð Bjarmason07a348e2021-09-26 21:03:28 +02001529 if (hook_exists("prepare-commit-msg")) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001530 res = run_prepare_commit_msg_hook(r, msg, hook_commit);
Phillip Wood66618a52018-01-24 12:34:22 +00001531 if (res)
1532 goto out;
1533 if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
1534 2048) < 0) {
1535 res = error_errno(_("unable to read commit message "
1536 "from '%s'"),
1537 git_path_commit_editmsg());
1538 goto out;
1539 }
1540 msg = &commit_msg;
1541 }
1542
Phillip Woodd74f3e52019-03-29 11:08:42 +00001543 if (flags & CLEANUP_MSG)
1544 cleanup = COMMIT_MSG_CLEANUP_ALL;
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00001545 else if (flags & VERBATIM_MSG)
1546 cleanup = COMMIT_MSG_CLEANUP_NONE;
Phillip Woodd74f3e52019-03-29 11:08:42 +00001547 else if ((opts->signoff || opts->record_origin) &&
1548 !opts->explicit_cleanup)
1549 cleanup = COMMIT_MSG_CLEANUP_SPACE;
1550 else
1551 cleanup = opts->default_msg_cleanup;
Phillip Wood66618a52018-01-24 12:34:22 +00001552
1553 if (cleanup != COMMIT_MSG_CLEANUP_NONE)
Calvin Wan787cb8a2023-06-06 19:48:43 +00001554 strbuf_stripspace(msg,
1555 cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
Elijah Newrena3ec9ea2018-09-12 14:18:48 -07001556 if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
Phillip Wood66618a52018-01-24 12:34:22 +00001557 res = 1; /* run 'git commit' to display error message */
1558 goto out;
1559 }
1560
Phillip Wood7573cec2020-08-17 18:40:02 +01001561 if (opts->committer_date_is_author_date) {
1562 struct ident_split id;
1563 struct strbuf date = STRBUF_INIT;
Johannes Sixt12f7bab2018-04-18 20:15:04 +02001564
Phillip Wooda3894aa2020-08-17 18:40:03 +01001565 if (!opts->ignore_date) {
1566 if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
1567 res = error(_("invalid author identity '%s'"),
1568 author);
1569 goto out;
1570 }
1571 if (!id.date_begin) {
1572 res = error(_(
1573 "corrupt author: missing date information"));
1574 goto out;
1575 }
1576 strbuf_addf(&date, "@%.*s %.*s",
1577 (int)(id.date_end - id.date_begin),
1578 id.date_begin,
1579 (int)(id.tz_end - id.tz_begin),
1580 id.tz_begin);
1581 } else {
1582 reset_ident_date();
Phillip Wood7573cec2020-08-17 18:40:02 +01001583 }
Jeff King20204512020-10-23 03:26:30 -04001584 committer = fmt_ident(getenv("GIT_COMMITTER_NAME"),
1585 getenv("GIT_COMMITTER_EMAIL"),
Phillip Wooda3894aa2020-08-17 18:40:03 +01001586 WANT_COMMITTER_IDENT,
1587 opts->ignore_date ? NULL : date.buf,
Phillip Wood7573cec2020-08-17 18:40:02 +01001588 IDENT_STRICT);
1589 strbuf_release(&date);
1590 } else {
1591 reset_ident_date();
1592 }
Junio C Hamano8be83422018-02-15 14:55:43 -08001593
Phillip Wooda3894aa2020-08-17 18:40:03 +01001594 if (opts->ignore_date) {
1595 struct ident_split id;
1596 char *name, *email;
1597
1598 if (split_ident_line(&id, author, strlen(author)) < 0) {
1599 error(_("invalid author identity '%s'"), author);
1600 goto out;
1601 }
1602 name = xmemdupz(id.name_begin, id.name_end - id.name_begin);
1603 email = xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
1604 author = fmt_ident(name, email, WANT_AUTHOR_IDENT, NULL,
1605 IDENT_STRICT);
1606 free(name);
1607 free(email);
1608 }
1609
Phillip Woode8cbe212020-08-17 18:40:01 +01001610 if (commit_tree_extended(msg->buf, msg->len, &tree, parents, oid,
Phillip Wood7573cec2020-08-17 18:40:02 +01001611 author, committer, opts->gpg_sign, extra)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001612 res = error(_("failed to write commit object"));
1613 goto out;
1614 }
1615
Phillip Woodd188a602022-11-09 14:21:57 +00001616 if (update_head_with_reflog(current_head, oid, opts->reflog_message,
1617 msg, &err)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001618 res = error("%s", err.buf);
1619 goto out;
1620 }
1621
Ævar Arnfjörð Bjarmasona8cc5942022-03-07 13:33:46 +01001622 run_commit_hook(0, r->index_file, NULL, "post-commit", NULL);
Phillip Wood356ee462017-11-24 11:07:57 +00001623 if (flags & AMEND_MSG)
Nguyễn Thái Ngọc Duy1d18d752019-01-12 09:13:23 +07001624 commit_post_rewrite(r, current_head, oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001625
1626out:
1627 free_commit_extra_headers(extra);
1628 strbuf_release(&err);
Phillip Wood66618a52018-01-24 12:34:22 +00001629 strbuf_release(&commit_msg);
Junio C Hamano4d924522020-01-12 12:27:41 -08001630 free(amend_author);
Phillip Wood356ee462017-11-24 11:07:57 +00001631
1632 return res;
1633}
1634
Phillip Wood430b75f2019-12-06 16:06:12 +00001635static int write_rebase_head(struct object_id *oid)
1636{
1637 if (update_ref("rebase", "REBASE_HEAD", oid,
1638 NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
1639 return error(_("could not update %s"), "REBASE_HEAD");
1640
1641 return 0;
1642}
1643
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001644static int do_commit(struct repository *r,
1645 const char *msg_file, const char *author,
Phillip Wood430b75f2019-12-06 16:06:12 +00001646 struct replay_opts *opts, unsigned int flags,
1647 struct object_id *oid)
Phillip Wood356ee462017-11-24 11:07:57 +00001648{
1649 int res = 1;
1650
Phillip Woodb0a31862019-08-19 02:18:23 -07001651 if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
Phillip Wood356ee462017-11-24 11:07:57 +00001652 struct object_id oid;
1653 struct strbuf sb = STRBUF_INIT;
1654
1655 if (msg_file && strbuf_read_file(&sb, msg_file, 2048) < 0)
1656 return error_errno(_("unable to read commit message "
1657 "from '%s'"),
1658 msg_file);
1659
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001660 res = try_to_commit(r, msg_file ? &sb : NULL,
1661 author, opts, flags, &oid);
Phillip Wood356ee462017-11-24 11:07:57 +00001662 strbuf_release(&sb);
1663 if (!res) {
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00001664 refs_delete_ref(get_main_ref_store(r), "",
1665 "CHERRY_PICK_HEAD", NULL, 0);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001666 unlink(git_path_merge_msg(r));
Phillip Wood356ee462017-11-24 11:07:57 +00001667 if (!is_rebase_i(opts))
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001668 print_commit_summary(r, NULL, &oid,
Phillip Wood356ee462017-11-24 11:07:57 +00001669 SUMMARY_SHOW_AUTHOR_DATE);
1670 return res;
1671 }
1672 }
Phillip Wood430b75f2019-12-06 16:06:12 +00001673 if (res == 1) {
1674 if (is_rebase_i(opts) && oid)
1675 if (write_rebase_head(oid))
1676 return -1;
Jeff King20f4b042020-09-30 08:29:31 -04001677 return run_git_commit(msg_file, opts, flags);
Phillip Wood430b75f2019-12-06 16:06:12 +00001678 }
Phillip Wood356ee462017-11-24 11:07:57 +00001679
1680 return res;
1681}
1682
Neil Hormanb27cfb02012-04-20 10:36:15 -04001683static int is_original_commit_empty(struct commit *commit)
1684{
brian m. carlson092bbcd2017-07-13 23:49:22 +00001685 const struct object_id *ptree_oid;
Neil Hormanb27cfb02012-04-20 10:36:15 -04001686
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001687 if (repo_parse_commit(the_repository, commit))
Johannes Schindelinaee42e12017-12-23 00:55:43 +01001688 return error(_("could not parse commit %s"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00001689 oid_to_hex(&commit->object.oid));
Neil Hormanb27cfb02012-04-20 10:36:15 -04001690 if (commit->parents) {
1691 struct commit *parent = commit->parents->item;
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02001692 if (repo_parse_commit(the_repository, parent))
Johannes Schindelinaee42e12017-12-23 00:55:43 +01001693 return error(_("could not parse parent commit %s"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00001694 oid_to_hex(&parent->object.oid));
Derrick Stolee2e27bd72018-04-06 19:09:38 +00001695 ptree_oid = get_commit_tree_oid(parent);
Neil Hormanb27cfb02012-04-20 10:36:15 -04001696 } else {
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +00001697 ptree_oid = the_hash_algo->empty_tree; /* commit is root */
Neil Hormanb27cfb02012-04-20 10:36:15 -04001698 }
1699
Jeff King4a7e27e2018-08-28 17:22:40 -04001700 return oideq(ptree_oid, get_commit_tree_oid(commit));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301701}
1702
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001703/*
Elijah Newrene98c4262020-02-15 21:36:25 +00001704 * Should empty commits be allowed? Return status:
1705 * <0: Error in is_index_unchanged(r) or is_original_commit_empty(commit)
1706 * 0: Halt on empty commit
1707 * 1: Allow empty commit
1708 * 2: Drop empty commit
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001709 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01001710static int allow_empty(struct repository *r,
1711 struct replay_opts *opts,
1712 struct commit *commit)
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001713{
Elijah Newrend48e5e22020-02-15 21:36:24 +00001714 int index_unchanged, originally_empty;
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001715
1716 /*
Elijah Newrene98c4262020-02-15 21:36:25 +00001717 * Four cases:
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001718 *
1719 * (1) we do not allow empty at all and error out.
1720 *
Elijah Newrene98c4262020-02-15 21:36:25 +00001721 * (2) we allow ones that were initially empty, and
1722 * just drop the ones that become empty
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001723 *
Elijah Newrene98c4262020-02-15 21:36:25 +00001724 * (3) we allow ones that were initially empty, but
1725 * halt for the ones that become empty;
1726 *
1727 * (4) we allow both.
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001728 */
1729 if (!opts->allow_empty)
1730 return 0; /* let "git commit" barf as necessary */
1731
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001732 index_unchanged = is_index_unchanged(r);
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001733 if (index_unchanged < 0)
1734 return index_unchanged;
1735 if (!index_unchanged)
1736 return 0; /* we do not have to say --allow-empty */
1737
1738 if (opts->keep_redundant_commits)
1739 return 1;
1740
Elijah Newrend48e5e22020-02-15 21:36:24 +00001741 originally_empty = is_original_commit_empty(commit);
1742 if (originally_empty < 0)
1743 return originally_empty;
Elijah Newrene98c4262020-02-15 21:36:25 +00001744 if (originally_empty)
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001745 return 1;
Elijah Newrene98c4262020-02-15 21:36:25 +00001746 else if (opts->drop_redundant_commits)
1747 return 2;
1748 else
1749 return 0;
Junio C Hamanoac2b0e82012-05-29 17:14:41 -07001750}
1751
Johannes Schindelin414697a2017-01-02 16:27:15 +01001752static struct {
1753 char c;
1754 const char *str;
1755} todo_command_info[] = {
Derrick Stoleed7ce9a22022-07-19 18:33:37 +00001756 [TODO_PICK] = { 'p', "pick" },
1757 [TODO_REVERT] = { 0, "revert" },
1758 [TODO_EDIT] = { 'e', "edit" },
1759 [TODO_REWORD] = { 'r', "reword" },
1760 [TODO_FIXUP] = { 'f', "fixup" },
1761 [TODO_SQUASH] = { 's', "squash" },
1762 [TODO_EXEC] = { 'x', "exec" },
1763 [TODO_BREAK] = { 'b', "break" },
1764 [TODO_LABEL] = { 'l', "label" },
1765 [TODO_RESET] = { 't', "reset" },
1766 [TODO_MERGE] = { 'm', "merge" },
Derrick Stoleea97d7912022-07-19 18:33:38 +00001767 [TODO_UPDATE_REF] = { 'u', "update-ref" },
Derrick Stoleed7ce9a22022-07-19 18:33:37 +00001768 [TODO_NOOP] = { 0, "noop" },
1769 [TODO_DROP] = { 'd', "drop" },
1770 [TODO_COMMENT] = { 0, NULL },
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001771};
1772
1773static const char *command_to_string(const enum todo_command command)
1774{
Johannes Schindelinac191472017-01-02 16:34:39 +01001775 if (command < TODO_COMMENT)
Johannes Schindelin414697a2017-01-02 16:27:15 +01001776 return todo_command_info[command].str;
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02001777 die(_("unknown command: %d"), command);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001778}
1779
Junio C Hamanoee5462d2017-12-27 11:12:45 -08001780static char command_to_char(const enum todo_command command)
Liam Beguind8ae6c82017-12-05 12:52:34 -05001781{
Alban Gruin68e70902020-03-30 14:42:35 +02001782 if (command < TODO_COMMENT)
Liam Beguind8ae6c82017-12-05 12:52:34 -05001783 return todo_command_info[command].c;
1784 return comment_line_char;
1785}
1786
Johannes Schindelin25c43662017-01-02 16:26:38 +01001787static int is_noop(const enum todo_command command)
1788{
Johannes Schindelinb3fdd582017-01-02 16:34:34 +01001789 return TODO_NOOP <= command;
Johannes Schindelin25c43662017-01-02 16:26:38 +01001790}
Johannes Schindelin004fefa2016-10-21 14:24:41 +02001791
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001792static int is_fixup(enum todo_command command)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05301793{
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001794 return command == TODO_FIXUP || command == TODO_SQUASH;
1795}
1796
Johannes Schindelind87d48b2018-05-04 01:01:17 +02001797/* Does this command create a (non-merge) commit? */
1798static int is_pick_or_similar(enum todo_command command)
1799{
1800 switch (command) {
1801 case TODO_PICK:
1802 case TODO_REVERT:
1803 case TODO_EDIT:
1804 case TODO_REWORD:
1805 case TODO_FIXUP:
1806 case TODO_SQUASH:
1807 return 1;
1808 default:
1809 return 0;
1810 }
1811}
1812
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301813enum todo_item_flags {
1814 TODO_EDIT_MERGE_MSG = (1 << 0),
1815 TODO_REPLACE_FIXUP_MSG = (1 << 1),
1816 TODO_EDIT_FIXUP_MSG = (1 << 2),
1817};
1818
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301819static const char first_commit_msg_str[] = N_("This is the 1st commit message:");
1820static const char nth_commit_msg_fmt[] = N_("This is the commit message #%d:");
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301821static const char skip_first_commit_msg_str[] = N_("The 1st commit message will be skipped:");
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301822static const char skip_nth_commit_msg_fmt[] = N_("The commit message #%d will be skipped:");
1823static const char combined_commit_msg_fmt[] = N_("This is a combination of %d commits.");
1824
Charvi Mendiratta1f969602021-02-09 00:55:20 +05301825static int is_fixup_flag(enum todo_command command, unsigned flag)
Phillip Wood498bb5b2021-01-19 13:10:57 +05301826{
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301827 return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||
1828 (flag & TODO_EDIT_FIXUP_MSG));
1829}
Phillip Wood7cdb9682021-01-29 23:50:44 +05301830
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301831/*
1832 * Wrapper around strbuf_add_commented_lines() which avoids double
1833 * commenting commit subjects.
1834 */
1835static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
1836{
1837 const char *s = str;
1838 while (len > 0 && s[0] == comment_line_char) {
1839 size_t count;
1840 const char *n = memchr(s, '\n', len);
1841 if (!n)
1842 count = len;
1843 else
1844 count = n - s + 1;
1845 strbuf_add(buf, s, count);
1846 s += count;
1847 len -= count;
1848 }
Calvin Wan787cb8a2023-06-06 19:48:43 +00001849 strbuf_add_commented_lines(buf, s, len, comment_line_char);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301850}
1851
1852/* Does the current fixup chain contain a squash command? */
1853static int seen_squash(struct replay_opts *opts)
1854{
1855 return starts_with(opts->current_fixups.buf, "squash") ||
1856 strstr(opts->current_fixups.buf, "\nsquash");
1857}
1858
1859static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)
1860{
1861 strbuf_setlen(buf1, 2);
1862 strbuf_addf(buf1, _(nth_commit_msg_fmt), n);
1863 strbuf_addch(buf1, '\n');
1864 strbuf_setlen(buf2, 2);
1865 strbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);
1866 strbuf_addch(buf2, '\n');
1867}
1868
1869/*
1870 * Comment out any un-commented commit messages, updating the message comments
1871 * to say they will be skipped but do not comment out the empty lines that
1872 * surround commit messages and their comments.
1873 */
1874static void update_squash_message_for_fixup(struct strbuf *msg)
1875{
1876 void (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;
1877 struct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;
1878 const char *s, *start;
1879 char *orig_msg;
1880 size_t orig_msg_len;
1881 int i = 1;
1882
1883 strbuf_addf(&buf1, "# %s\n", _(first_commit_msg_str));
1884 strbuf_addf(&buf2, "# %s\n", _(skip_first_commit_msg_str));
1885 s = start = orig_msg = strbuf_detach(msg, &orig_msg_len);
1886 while (s) {
1887 const char *next;
1888 size_t off;
1889 if (skip_prefix(s, buf1.buf, &next)) {
1890 /*
1891 * Copy the last message, preserving the blank line
1892 * preceding the current line
1893 */
1894 off = (s > start + 1 && s[-2] == '\n') ? 1 : 0;
1895 copy_lines(msg, start, s - start - off);
1896 if (off)
1897 strbuf_addch(msg, '\n');
1898 /*
1899 * The next message needs to be commented out but the
1900 * message header is already commented out so just copy
1901 * it and the blank line that follows it.
1902 */
1903 strbuf_addbuf(msg, &buf2);
1904 if (*next == '\n')
1905 strbuf_addch(msg, *next++);
1906 start = s = next;
1907 copy_lines = add_commented_lines;
1908 update_comment_bufs(&buf1, &buf2, ++i);
1909 } else if (skip_prefix(s, buf2.buf, &next)) {
1910 off = (s > start + 1 && s[-2] == '\n') ? 1 : 0;
1911 copy_lines(msg, start, s - start - off);
1912 start = s - off;
1913 s = next;
1914 copy_lines = strbuf_add;
1915 update_comment_bufs(&buf1, &buf2, ++i);
1916 } else {
1917 s = strchr(s, '\n');
1918 if (s)
1919 s++;
1920 }
1921 }
1922 copy_lines(msg, start, orig_msg_len - (start - orig_msg));
1923 free(orig_msg);
1924 strbuf_release(&buf1);
1925 strbuf_release(&buf2);
1926}
1927
1928static int append_squash_message(struct strbuf *buf, const char *body,
1929 enum todo_command command, struct replay_opts *opts,
Charvi Mendirattaa25314c2021-02-09 00:55:19 +05301930 unsigned flag)
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301931{
1932 const char *fixup_msg;
1933 size_t commented_len = 0, fixup_off;
1934 /*
1935 * amend is non-interactive and not normally used with fixup!
1936 * or squash! commits, so only comment out those subjects when
1937 * squashing commit messages.
1938 */
1939 if (starts_with(body, "amend!") ||
1940 ((command == TODO_SQUASH || seen_squash(opts)) &&
1941 (starts_with(body, "squash!") || starts_with(body, "fixup!"))))
Charvi Mendiratta6e0e2882021-03-15 13:24:31 +05301942 commented_len = commit_subject_length(body);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301943
Phillip Wood498bb5b2021-01-19 13:10:57 +05301944 strbuf_addf(buf, "\n%c ", comment_line_char);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05301945 strbuf_addf(buf, _(nth_commit_msg_fmt),
Phillip Wood498bb5b2021-01-19 13:10:57 +05301946 ++opts->current_fixup_count + 1);
1947 strbuf_addstr(buf, "\n\n");
Calvin Wan787cb8a2023-06-06 19:48:43 +00001948 strbuf_add_commented_lines(buf, body, commented_len, comment_line_char);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301949 /* buf->buf may be reallocated so store an offset into the buffer */
1950 fixup_off = buf->len;
Phillip Wood7cdb9682021-01-29 23:50:44 +05301951 strbuf_addstr(buf, body + commented_len);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301952
1953 /* fixup -C after squash behaves like squash */
Charvi Mendiratta1f969602021-02-09 00:55:20 +05301954 if (is_fixup_flag(command, flag) && !seen_squash(opts)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301955 /*
1956 * We're replacing the commit message so we need to
1957 * append the Signed-off-by: trailer if the user
1958 * requested '--signoff'.
1959 */
1960 if (opts->signoff)
1961 append_signoff(buf, 0, 0);
1962
1963 if ((command == TODO_FIXUP) &&
1964 (flag & TODO_REPLACE_FIXUP_MSG) &&
1965 (file_exists(rebase_path_fixup_msg()) ||
1966 !file_exists(rebase_path_squash_msg()))) {
1967 fixup_msg = skip_blank_lines(buf->buf + fixup_off);
1968 if (write_message(fixup_msg, strlen(fixup_msg),
1969 rebase_path_fixup_msg(), 0) < 0)
1970 return error(_("cannot write '%s'"),
1971 rebase_path_fixup_msg());
1972 } else {
1973 unlink(rebase_path_fixup_msg());
1974 }
1975 } else {
1976 unlink(rebase_path_fixup_msg());
1977 }
1978
1979 return 0;
Phillip Wood498bb5b2021-01-19 13:10:57 +05301980}
1981
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01001982static int update_squash_messages(struct repository *r,
1983 enum todo_command command,
1984 struct commit *commit,
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301985 struct replay_opts *opts,
Charvi Mendirattaa25314c2021-02-09 00:55:19 +05301986 unsigned flag)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001987{
1988 struct strbuf buf = STRBUF_INIT;
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05301989 int res = 0;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001990 const char *message, *body;
Doan Tran Cong Danhb3757442019-11-08 16:43:48 +07001991 const char *encoding = get_commit_output_encoding();
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001992
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02001993 if (opts->current_fixup_count > 0) {
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001994 struct strbuf header = STRBUF_INIT;
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02001995 char *eol;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001996
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02001997 if (strbuf_read_file(&buf, rebase_path_squash_msg(), 9) <= 0)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01001998 return error(_("could not read '%s'"),
1999 rebase_path_squash_msg());
2000
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002001 eol = buf.buf[0] != comment_line_char ?
2002 buf.buf : strchrnul(buf.buf, '\n');
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002003
2004 strbuf_addf(&header, "%c ", comment_line_char);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302005 strbuf_addf(&header, _(combined_commit_msg_fmt),
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002006 opts->current_fixup_count + 2);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002007 strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
2008 strbuf_release(&header);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302009 if (is_fixup_flag(command, flag) && !seen_squash(opts))
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302010 update_squash_message_for_fixup(&buf);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002011 } else {
brian m. carlson33d66df2017-05-06 22:10:07 +00002012 struct object_id head;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002013 struct commit *head_commit;
2014 const char *head_message, *body;
2015
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002016 if (repo_get_oid(r, "HEAD", &head))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002017 return error(_("need a HEAD to fixup"));
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002018 if (!(head_commit = lookup_commit_reference(r, &head)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002019 return error(_("could not read HEAD"));
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002020 if (!(head_message = repo_logmsg_reencode(r, head_commit, NULL,
2021 encoding)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002022 return error(_("could not read HEAD's commit message"));
2023
2024 find_commit_subject(head_message, &body);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302025 if (command == TODO_FIXUP && !flag && write_message(body, strlen(body),
Phillip Woodeab0df02021-01-19 13:10:56 +05302026 rebase_path_fixup_msg(), 0) < 0) {
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002027 repo_unuse_commit_buffer(r, head_commit, head_message);
Phillip Woodeab0df02021-01-19 13:10:56 +05302028 return error(_("cannot write '%s'"), rebase_path_fixup_msg());
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002029 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002030 strbuf_addf(&buf, "%c ", comment_line_char);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302031 strbuf_addf(&buf, _(combined_commit_msg_fmt), 2);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002032 strbuf_addf(&buf, "\n%c ", comment_line_char);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302033 strbuf_addstr(&buf, is_fixup_flag(command, flag) ?
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302034 _(skip_first_commit_msg_str) :
2035 _(first_commit_msg_str));
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002036 strbuf_addstr(&buf, "\n\n");
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302037 if (is_fixup_flag(command, flag))
Calvin Wan787cb8a2023-06-06 19:48:43 +00002038 strbuf_add_commented_lines(&buf, body, strlen(body),
2039 comment_line_char);
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302040 else
2041 strbuf_addstr(&buf, body);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002042
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002043 repo_unuse_commit_buffer(r, head_commit, head_message);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002044 }
2045
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002046 if (!(message = repo_logmsg_reencode(r, commit, NULL, encoding)))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002047 return error(_("could not read commit message of %s"),
2048 oid_to_hex(&commit->object.oid));
2049 find_commit_subject(message, &body);
2050
Charvi Mendiratta1f969602021-02-09 00:55:20 +05302051 if (command == TODO_SQUASH || is_fixup_flag(command, flag)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302052 res = append_squash_message(&buf, body, command, opts, flag);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002053 } else if (command == TODO_FIXUP) {
2054 strbuf_addf(&buf, "\n%c ", comment_line_char);
Charvi Mendiratta71ee81c2021-01-29 23:50:46 +05302055 strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
Phillip Wooddd2e36e2018-08-15 10:41:25 +01002056 ++opts->current_fixup_count + 1);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002057 strbuf_addstr(&buf, "\n\n");
Calvin Wan787cb8a2023-06-06 19:48:43 +00002058 strbuf_add_commented_lines(&buf, body, strlen(body),
2059 comment_line_char);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002060 } else
2061 return error(_("unknown command: %d"), command);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002062 repo_unuse_commit_buffer(r, commit, message);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002063
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302064 if (!res)
2065 res = write_message(buf.buf, buf.len, rebase_path_squash_msg(),
2066 0);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002067 strbuf_release(&buf);
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002068
2069 if (!res) {
2070 strbuf_addf(&opts->current_fixups, "%s%s %s",
2071 opts->current_fixups.len ? "\n" : "",
2072 command_to_string(command),
2073 oid_to_hex(&commit->object.oid));
2074 res = write_message(opts->current_fixups.buf,
2075 opts->current_fixups.len,
2076 rebase_path_current_fixups(), 0);
2077 }
2078
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002079 return res;
2080}
2081
Nguyễn Thái Ngọc Duy3b335762018-12-09 11:25:21 +01002082static void flush_rewritten_pending(void)
2083{
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002084 struct strbuf buf = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00002085 struct object_id newoid;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002086 FILE *out;
2087
brian m. carlson092bbcd2017-07-13 23:49:22 +00002088 if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02002089 !repo_get_oid(the_repository, "HEAD", &newoid) &&
Nguyễn Thái Ngọc Duye9d983f2017-05-03 17:16:50 +07002090 (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002091 char *bol = buf.buf, *eol;
2092
2093 while (*bol) {
2094 eol = strchrnul(bol, '\n');
2095 fprintf(out, "%.*s %s\n", (int)(eol - bol),
brian m. carlson092bbcd2017-07-13 23:49:22 +00002096 bol, oid_to_hex(&newoid));
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002097 if (!*eol)
2098 break;
2099 bol = eol + 1;
2100 }
2101 fclose(out);
2102 unlink(rebase_path_rewritten_pending());
2103 }
2104 strbuf_release(&buf);
2105}
2106
2107static void record_in_rewritten(struct object_id *oid,
Nguyễn Thái Ngọc Duy3b335762018-12-09 11:25:21 +01002108 enum todo_command next_command)
2109{
Nguyễn Thái Ngọc Duye9d983f2017-05-03 17:16:50 +07002110 FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a");
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01002111
2112 if (!out)
2113 return;
2114
2115 fprintf(out, "%s\n", oid_to_hex(oid));
2116 fclose(out);
2117
2118 if (!is_fixup(next_command))
2119 flush_rewritten_pending();
2120}
2121
Elijah Newren39edfd52021-03-31 06:52:20 +00002122static int should_edit(struct replay_opts *opts) {
2123 if (opts->edit < 0)
2124 /*
2125 * Note that we only handle the case of non-conflicted
2126 * commits; continue_single_pick() handles the conflicted
2127 * commits itself instead of calling this function.
2128 */
2129 return (opts->action == REPLAY_REVERT && isatty(0)) ? 1 : 0;
2130 return opts->edit;
2131}
2132
Junio C Hamano43966ab2022-05-26 23:01:39 -07002133static void refer_to_commit(struct replay_opts *opts,
2134 struct strbuf *msgbuf, struct commit *commit)
2135{
2136 if (opts->commit_use_reference) {
2137 struct pretty_print_context ctx = {
2138 .abbrev = DEFAULT_ABBREV,
2139 .date_mode.type = DATE_SHORT,
2140 };
Ævar Arnfjörð Bjarmasonbab82162023-03-28 15:58:51 +02002141 repo_format_commit_message(the_repository, commit,
2142 "%h (%s, %ad)", msgbuf, &ctx);
Junio C Hamano43966ab2022-05-26 23:01:39 -07002143 } else {
2144 strbuf_addstr(msgbuf, oid_to_hex(&commit->object.oid));
2145 }
2146}
2147
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002148static int do_pick_commit(struct repository *r,
Charvi Mendirattaae70e342021-01-29 23:50:45 +05302149 struct todo_item *item,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002150 struct replay_opts *opts,
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002151 int final_fixup, int *check_todo)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002152{
Elijah Newren39edfd52021-03-31 06:52:20 +00002153 unsigned int flags = should_edit(opts) ? EDIT_MSG : 0;
2154 const char *msg_file = should_edit(opts) ? NULL : git_path_merge_msg(r);
brian m. carlsonace976b2017-05-06 22:10:32 +00002155 struct object_id head;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302156 struct commit *base, *next, *parent;
2157 const char *base_label, *next_label;
Phillip Wood356ee462017-11-24 11:07:57 +00002158 char *author = NULL;
Jeff Kingd74a4e52014-06-10 17:39:35 -04002159 struct commit_message msg = { NULL, NULL, NULL, NULL };
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302160 struct strbuf msgbuf = STRBUF_INIT;
Elijah Newrene98c4262020-02-15 21:36:25 +00002161 int res, unborn = 0, reword = 0, allow, drop_commit;
Charvi Mendirattaae70e342021-01-29 23:50:45 +05302162 enum todo_command command = item->command;
2163 struct commit *commit = item->commit;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302164
2165 if (opts->no_commit) {
2166 /*
2167 * We do not intend to commit immediately. We just want to
2168 * merge the differences in, so let's compute the tree
Elijah Newren81483fe2021-08-04 23:50:54 +00002169 * that represents the "current" state for the merge machinery
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302170 * to work on.
2171 */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002172 if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002173 return error(_("your index file is unmerged."));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302174 } else {
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002175 unborn = repo_get_oid(r, "HEAD", &head);
Johannes Schindelind87d48b2018-05-04 01:01:17 +02002176 /* Do we want to generate a root commit? */
2177 if (is_pick_or_similar(command) && opts->have_squash_onto &&
Jeff King4a7e27e2018-08-28 17:22:40 -04002178 oideq(&head, &opts->squash_onto)) {
Johannes Schindelind87d48b2018-05-04 01:01:17 +02002179 if (is_fixup(command))
2180 return error(_("cannot fixup root commit"));
2181 flags |= CREATE_ROOT_COMMIT;
2182 unborn = 1;
2183 } else if (unborn)
brian m. carlsoneb0ccfd2017-11-12 21:28:54 +00002184 oidcpy(&head, the_hash_algo->empty_tree);
Nguyễn Thái Ngọc Duyffc00a42018-11-10 06:49:04 +01002185 if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
Brandon Williams02f2f562017-10-31 11:19:05 -07002186 NULL, 0))
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07002187 return error_dirty_index(r, opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302188 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002189 discard_index(r->index);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302190
Johannes Schindelin637666c2017-01-02 16:26:08 +01002191 if (!commit->parents)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302192 parent = NULL;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302193 else if (commit->parents->next) {
2194 /* Reverting or cherry-picking a merge commit */
2195 int cnt;
2196 struct commit_list *p;
2197
2198 if (!opts->mainline)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002199 return error(_("commit %s is a merge but no -m option was given."),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002200 oid_to_hex(&commit->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302201
2202 for (cnt = 1, p = commit->parents;
2203 cnt != opts->mainline && p;
2204 cnt++)
2205 p = p->next;
2206 if (cnt != opts->mainline || !p)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002207 return error(_("commit %s does not have parent %d"),
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002208 oid_to_hex(&commit->object.oid), opts->mainline);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302209 parent = p->item;
Sergey Organov37897bf2018-12-14 07:53:51 +03002210 } else if (1 < opts->mainline)
2211 /*
2212 * Non-first parent explicitly specified as mainline for
2213 * non-merge commit
2214 */
2215 return error(_("commit %s does not have parent %d"),
2216 oid_to_hex(&commit->object.oid), opts->mainline);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302217 else
2218 parent = commit->parents->item;
2219
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002220 if (get_message(commit, &msg) != 0)
2221 return error(_("cannot get commit message for %s"),
2222 oid_to_hex(&commit->object.oid));
2223
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002224 if (opts->allow_ff && !is_fixup(command) &&
Jeff King4a7e27e2018-08-28 17:22:40 -04002225 ((parent && oideq(&parent->object.oid, &head)) ||
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002226 (!parent && unborn))) {
2227 if (is_rebase_i(opts))
2228 write_author_script(msg.message);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002229 res = fast_forward_to(r, &commit->object.oid, &head, unborn,
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002230 opts);
2231 if (res || command != TODO_REWORD)
2232 goto leave;
Phillip Wood450efe22019-08-19 02:18:21 -07002233 reword = 1;
Johannes Schindelinbcbb68b2017-01-02 16:28:05 +01002234 msg_file = NULL;
2235 goto fast_forward_edit;
2236 }
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002237 if (parent && repo_parse_commit(r, parent) < 0)
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002238 /* TRANSLATORS: The first %s will be a "todo" command like
2239 "revert" or "pick", the second %s a SHA1. */
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302240 return error(_("%s: cannot parse parent commit %s"),
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002241 command_to_string(command),
2242 oid_to_hex(&parent->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302243
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302244 /*
2245 * "commit" is an existing commit. We would want to apply
2246 * the difference it introduces since its first parent "prev"
2247 * on top of the current HEAD if we are cherry-pick. Or the
2248 * reverse of it if we are revert.
2249 */
2250
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002251 if (command == TODO_REVERT) {
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302252 base = commit;
2253 base_label = msg.label;
2254 next = parent;
2255 next_label = msg.parent_label;
Junio C Hamano43966ab2022-05-26 23:01:39 -07002256 if (opts->commit_use_reference) {
2257 strbuf_addstr(&msgbuf,
2258 "# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
2259 } else {
2260 strbuf_addstr(&msgbuf, "Revert \"");
2261 strbuf_addstr(&msgbuf, msg.subject);
2262 strbuf_addstr(&msgbuf, "\"");
2263 }
2264 strbuf_addstr(&msgbuf, "\n\nThis reverts commit ");
2265 refer_to_commit(opts, &msgbuf, commit);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302266
2267 if (commit->parents && commit->parents->next) {
2268 strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
Junio C Hamano43966ab2022-05-26 23:01:39 -07002269 refer_to_commit(opts, &msgbuf, parent);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302270 }
2271 strbuf_addstr(&msgbuf, ".\n");
2272 } else {
2273 const char *p;
2274
2275 base = parent;
2276 base_label = msg.parent_label;
2277 next = commit;
2278 next_label = msg.label;
2279
Johannes Schindelin23aa5142017-01-02 16:26:20 +01002280 /* Append the commit log message to msgbuf. */
2281 if (find_commit_subject(msg.message, &p))
2282 strbuf_addstr(&msgbuf, p);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302283
2284 if (opts->record_origin) {
Jonathan Tan44dc7382017-04-26 13:50:03 -07002285 strbuf_complete_line(&msgbuf);
Brandon Caseybab4d102013-02-12 02:17:35 -08002286 if (!has_conforming_footer(&msgbuf, NULL, 0))
Brandon Caseyb971e042013-02-12 02:17:34 -08002287 strbuf_addch(&msgbuf, '\n');
Brandon Caseycd650a42013-02-12 02:17:32 -08002288 strbuf_addstr(&msgbuf, cherry_picked_prefix);
brian m. carlsonf2fd0762015-11-10 02:22:28 +00002289 strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302290 strbuf_addstr(&msgbuf, ")\n");
2291 }
Phillip Wood356ee462017-11-24 11:07:57 +00002292 if (!is_fixup(command))
2293 author = get_author(msg.message);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302294 }
2295
Johannes Schindelin04efc8b2017-01-02 16:28:00 +01002296 if (command == TODO_REWORD)
Phillip Wood450efe22019-08-19 02:18:21 -07002297 reword = 1;
Johannes Schindelin04efc8b2017-01-02 16:28:00 +01002298 else if (is_fixup(command)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302299 if (update_squash_messages(r, command, commit,
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002300 opts, item->flags)) {
2301 res = -1;
2302 goto leave;
2303 }
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002304 flags |= AMEND_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002305 if (!final_fixup)
2306 msg_file = rebase_path_squash_msg();
2307 else if (file_exists(rebase_path_fixup_msg())) {
Johannes Schindelinf7d42ce2021-01-28 16:16:42 +00002308 flags |= VERBATIM_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002309 msg_file = rebase_path_fixup_msg();
2310 } else {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002311 const char *dest = git_path_squash_msg(r);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002312 unlink(dest);
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002313 if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
2314 res = error(_("could not rename '%s' to '%s'"),
2315 rebase_path_squash_msg(), dest);
2316 goto leave;
2317 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002318 unlink(git_path_merge_msg(r));
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002319 msg_file = dest;
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002320 flags |= EDIT_MSG;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002321 }
2322 }
2323
Phillip Wooda852ec72018-03-20 11:10:55 +00002324 if (opts->signoff && !is_fixup(command))
Phillip Woodb34eeea2017-11-24 11:07:55 +00002325 append_signoff(&msgbuf, 0, 0);
2326
Johannes Schindelin0473f282017-01-02 16:27:18 +01002327 if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
2328 res = -1;
Elijah Newren14c45862020-11-02 23:45:34 +00002329 else if (!opts->strategy ||
2330 !strcmp(opts->strategy, "recursive") ||
2331 !strcmp(opts->strategy, "ort") ||
2332 command == TODO_REVERT) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002333 res = do_recursive_merge(r, base, next, base_label, next_label,
brian m. carlson48be4c62017-05-06 22:10:36 +00002334 &head, &msgbuf, opts);
Johannes Schindelinf241ff02016-07-26 18:06:02 +02002335 if (res < 0)
Stefan Beller19517fb2018-06-01 13:01:45 -07002336 goto leave;
2337
Johannes Schindelin75871492016-10-21 14:26:05 +02002338 res |= write_message(msgbuf.buf, msgbuf.len,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002339 git_path_merge_msg(r), 0);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302340 } else {
2341 struct commit_list *common = NULL;
2342 struct commit_list *remotes = NULL;
2343
Johannes Schindelin75871492016-10-21 14:26:05 +02002344 res = write_message(msgbuf.buf, msgbuf.len,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002345 git_path_merge_msg(r), 0);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302346
2347 commit_list_insert(base, &common);
2348 commit_list_insert(next, &remotes);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002349 res |= try_merge_command(r, opts->strategy,
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002350 opts->xopts.nr, opts->xopts.v,
brian m. carlsonace976b2017-05-06 22:10:32 +00002351 common, oid_to_hex(&head), remotes);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302352 free_commit_list(common);
2353 free_commit_list(remotes);
2354 }
2355
2356 /*
2357 * If the merge was clean or if it failed due to conflict, we write
2358 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
2359 * However, if the merge did not even start, then we don't want to
2360 * write it at all.
2361 */
Phillip Wood21b11c62019-12-06 16:06:09 +00002362 if ((command == TODO_PICK || command == TODO_REWORD ||
2363 command == TODO_EDIT) && !opts->no_commit &&
2364 (res == 0 || res == 1) &&
brian m. carlsonae077772017-10-15 22:06:51 +00002365 update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
Michael Haggerty91774af2017-11-05 09:42:06 +01002366 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
Johannes Schindelindbfad032016-08-26 15:47:14 +02002367 res = -1;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002368 if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
brian m. carlsonae077772017-10-15 22:06:51 +00002369 update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
Michael Haggerty91774af2017-11-05 09:42:06 +01002370 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
Johannes Schindelindbfad032016-08-26 15:47:14 +02002371 res = -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302372
2373 if (res) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002374 error(command == TODO_REVERT
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302375 ? _("could not revert %s... %s")
2376 : _("could not apply %s... %s"),
Johannes Schindelin39755962016-10-21 14:24:37 +02002377 short_commit_name(commit), msg.subject);
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002378 print_advice(r, res == 1, opts);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002379 repo_rerere(r, opts->allow_rerere_auto);
Felipe Contrerasc8d13512013-05-28 22:56:21 -05002380 goto leave;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302381 }
2382
Elijah Newrene98c4262020-02-15 21:36:25 +00002383 drop_commit = 0;
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002384 allow = allow_empty(r, opts, commit);
Felipe Contreras706728a2013-06-06 03:58:57 -05002385 if (allow < 0) {
2386 res = allow;
2387 goto leave;
Elijah Newrene98c4262020-02-15 21:36:25 +00002388 } else if (allow == 1) {
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01002389 flags |= ALLOW_EMPTY;
Elijah Newrene98c4262020-02-15 21:36:25 +00002390 } else if (allow == 2) {
2391 drop_commit = 1;
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00002392 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
2393 NULL, 0);
Elijah Newren9a1b7472020-03-11 15:30:22 +00002394 unlink(git_path_merge_msg(r));
Elijah Newren52918282021-03-20 00:03:52 +00002395 unlink(git_path_auto_merge(r));
Elijah Newrene98c4262020-02-15 21:36:25 +00002396 fprintf(stderr,
2397 _("dropping %s %s -- patch contents already upstream\n"),
2398 oid_to_hex(&commit->object.oid), msg.subject);
2399 } /* else allow == 0 and there's nothing special to do */
2400 if (!opts->no_commit && !drop_commit) {
Phillip Wood356ee462017-11-24 11:07:57 +00002401 if (author || command == TODO_REVERT || (flags & AMEND_MSG))
Phillip Wood430b75f2019-12-06 16:06:12 +00002402 res = do_commit(r, msg_file, author, opts, flags,
2403 commit? &commit->object.oid : NULL);
Phillip Wood356ee462017-11-24 11:07:57 +00002404 else
2405 res = error(_("unable to parse commit author"));
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002406 *check_todo = !!(flags & EDIT_MSG);
2407 if (!res && reword) {
Phillip Wood450efe22019-08-19 02:18:21 -07002408fast_forward_edit:
Jeff King20f4b042020-09-30 08:29:31 -04002409 res = run_git_commit(NULL, opts, EDIT_MSG |
Phillip Wood450efe22019-08-19 02:18:21 -07002410 VERIFY_MSG | AMEND_MSG |
2411 (flags & ALLOW_EMPTY));
Phillip Wooda47ba3c2019-08-19 02:18:22 -07002412 *check_todo = 1;
2413 }
Phillip Wood356ee462017-11-24 11:07:57 +00002414 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002415
Phillip Wood450efe22019-08-19 02:18:21 -07002416
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002417 if (!res && final_fixup) {
2418 unlink(rebase_path_fixup_msg());
2419 unlink(rebase_path_squash_msg());
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02002420 unlink(rebase_path_current_fixups());
2421 strbuf_reset(&opts->current_fixups);
2422 opts->current_fixup_count = 0;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002423 }
Felipe Contrerasc8d13512013-05-28 22:56:21 -05002424
2425leave:
Jeff Kingd74a4e52014-06-10 17:39:35 -04002426 free_message(commit, &msg);
Phillip Wood356ee462017-11-24 11:07:57 +00002427 free(author);
Ævar Arnfjörð Bjarmasona5792e92023-02-06 20:08:11 +01002428 strbuf_release(&msgbuf);
Stephan Beyer1e412292016-12-07 22:51:32 +01002429 update_abort_safety_file();
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302430
2431 return res;
2432}
2433
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002434static int prepare_revs(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302435{
Martin von Zweigbergka73e22e2012-08-28 23:15:56 -07002436 /*
2437 * picking (but not reverting) ranges (but not individual revisions)
2438 * should be done in reverse
2439 */
2440 if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302441 opts->revs->reverse ^= 1;
2442
2443 if (prepare_revision_walk(opts->revs))
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002444 return error(_("revision walk setup failed"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302445
Johannes Schindelinc3e86182016-09-09 16:37:18 +02002446 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302447}
2448
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002449static int read_and_refresh_cache(struct repository *r,
2450 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302451{
Martin Ågren14bca6c2018-02-27 22:30:09 +01002452 struct lock_file index_lock = LOCK_INIT;
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07002453 int index_fd = repo_hold_locked_index(r, &index_lock, 0);
2454 if (repo_read_index(r) < 0) {
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002455 rollback_lock_file(&index_lock);
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002456 return error(_("git %s: failed to read the index"),
Michael J Gruber629444a2022-08-18 15:13:28 +02002457 action_name(opts));
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002458 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002459 refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
Derrick Stolee5d9c9342021-09-08 11:24:00 +00002460
Martin Ågren61000812018-03-01 21:40:20 +01002461 if (index_fd >= 0) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01002462 if (write_locked_index(r->index, &index_lock,
Martin Ågren61000812018-03-01 21:40:20 +01002463 COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002464 return error(_("git %s: failed to refresh the index"),
Michael J Gruber629444a2022-08-18 15:13:28 +02002465 action_name(opts));
Johannes Schindelin49fb9372016-09-09 16:38:20 +02002466 }
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302467 }
Derrick Stolee5d9c9342021-09-08 11:24:00 +00002468
2469 /*
2470 * If we are resolving merges in any way other than "ort", then
2471 * expand the sparse index.
2472 */
2473 if (opts->strategy && strcmp(opts->strategy, "ort"))
2474 ensure_full_index(r->index);
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02002475 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302476}
2477
Alban Gruin5d94d542018-12-29 17:03:59 +01002478void todo_list_release(struct todo_list *todo_list)
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002479{
2480 strbuf_release(&todo_list->buf);
Ævar Arnfjörð Bjarmason6a83d902017-06-15 23:15:46 +00002481 FREE_AND_NULL(todo_list->items);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002482 todo_list->nr = todo_list->alloc = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302483}
2484
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002485static struct todo_item *append_new_todo(struct todo_list *todo_list)
2486{
2487 ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);
2488 return todo_list->items + todo_list->nr++;
2489}
2490
Alban Gruin6ad656d2019-01-29 16:01:46 +01002491const char *todo_item_get_arg(struct todo_list *todo_list,
2492 struct todo_item *item)
2493{
2494 return todo_list->buf.buf + item->arg_offset;
2495}
2496
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002497static int is_command(enum todo_command command, const char **bol)
2498{
2499 const char *str = todo_command_info[command].str;
2500 const char nick = todo_command_info[command].c;
Phillip Wood7aed2c02023-02-23 20:55:00 +00002501 const char *p = *bol;
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002502
Phillip Wood7aed2c02023-02-23 20:55:00 +00002503 return (skip_prefix(p, str, &p) || (nick && *p++ == nick)) &&
2504 (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
2505 (*bol = p);
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002506}
2507
Phillip Wood16b38802023-02-20 14:19:34 +00002508static int check_label_or_ref_arg(enum todo_command command, const char *arg)
2509{
2510 switch (command) {
2511 case TODO_LABEL:
2512 /*
2513 * '#' is not a valid label as the merge command uses it to
2514 * separate merge parents from the commit subject.
2515 */
2516 if (!strcmp(arg, "#") ||
2517 check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
2518 return error(_("'%s' is not a valid label"), arg);
2519 break;
2520
2521 case TODO_UPDATE_REF:
2522 if (check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
2523 return error(_("'%s' is not a valid refname"), arg);
2524 if (check_refname_format(arg, 0))
2525 return error(_("update-ref requires a fully qualified "
2526 "refname e.g. refs/heads/%s"), arg);
2527 break;
2528
2529 default:
2530 BUG("unexpected todo_command");
2531 }
2532
2533 return 0;
2534}
2535
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002536static int parse_insn_line(struct repository *r, struct todo_item *item,
Alban Gruin6ad656d2019-01-29 16:01:46 +01002537 const char *buf, const char *bol, char *eol)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302538{
brian m. carlson1e43ed92017-05-06 22:10:09 +00002539 struct object_id commit_oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302540 char *end_of_object_name;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002541 int i, saved, status, padding;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302542
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002543 item->flags = 0;
2544
Johannes Schindelin8f8550b2016-10-21 14:25:36 +02002545 /* left-trim */
2546 bol += strspn(bol, " \t");
2547
Johannes Schindelin25c43662017-01-02 16:26:38 +01002548 if (bol == eol || *bol == '\r' || *bol == comment_line_char) {
Johannes Schindelinac191472017-01-02 16:34:39 +01002549 item->command = TODO_COMMENT;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002550 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002551 item->arg_offset = bol - buf;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002552 item->arg_len = eol - bol;
2553 return 0;
2554 }
2555
Johannes Schindelinac191472017-01-02 16:34:39 +01002556 for (i = 0; i < TODO_COMMENT; i++)
Phillip Wood3e81bcc2019-06-27 07:12:45 -07002557 if (is_command(i, &bol)) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002558 item->command = i;
2559 break;
2560 }
Johannes Schindelinac191472017-01-02 16:34:39 +01002561 if (i >= TODO_COMMENT)
Phillip Wood7aed2c02023-02-23 20:55:00 +00002562 return error(_("invalid command '%.*s'"),
2563 (int)strcspn(bol, " \t\r\n"), bol);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302564
Johannes Schindelin66afa242017-12-23 00:55:57 +01002565 /* Eat up extra spaces/ tabs before object name */
2566 padding = strspn(bol, " \t");
2567 bol += padding;
2568
Johannes Schindelin71f82462018-10-12 06:14:26 -07002569 if (item->command == TODO_NOOP || item->command == TODO_BREAK) {
Johannes Schindelin66afa242017-12-23 00:55:57 +01002570 if (bol != eol)
2571 return error(_("%s does not accept arguments: '%s'"),
2572 command_to_string(item->command), bol);
Johannes Schindelin25c43662017-01-02 16:26:38 +01002573 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002574 item->arg_offset = bol - buf;
Johannes Schindelin25c43662017-01-02 16:26:38 +01002575 item->arg_len = eol - bol;
2576 return 0;
2577 }
2578
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302579 if (!padding)
Johannes Schindelin66afa242017-12-23 00:55:57 +01002580 return error(_("missing arguments for %s"),
2581 command_to_string(item->command));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302582
Johannes Schindelin9055e402018-04-25 14:28:47 +02002583 if (item->command == TODO_EXEC || item->command == TODO_LABEL ||
Derrick Stoleea97d7912022-07-19 18:33:38 +00002584 item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {
Phillip Wood16b38802023-02-20 14:19:34 +00002585 int ret = 0;
2586
Liam Beguin7dcbb3c2017-12-03 17:17:15 -05002587 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002588 item->arg_offset = bol - buf;
Johannes Schindelin311af522017-01-02 16:26:47 +01002589 item->arg_len = (int)(eol - bol);
Phillip Wood16b38802023-02-20 14:19:34 +00002590 if (item->command == TODO_LABEL ||
2591 item->command == TODO_UPDATE_REF) {
2592 saved = *eol;
2593 *eol = '\0';
2594 ret = check_label_or_ref_arg(item->command, bol);
2595 *eol = saved;
2596 }
2597 return ret;
Johannes Schindelin311af522017-01-02 16:26:47 +01002598 }
2599
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302600 if (item->command == TODO_FIXUP) {
Phillip Wood666b6e12023-02-23 20:55:01 +00002601 if (skip_prefix(bol, "-C", &bol)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302602 bol += strspn(bol, " \t");
2603 item->flags |= TODO_REPLACE_FIXUP_MSG;
Phillip Wood666b6e12023-02-23 20:55:01 +00002604 } else if (skip_prefix(bol, "-c", &bol)) {
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05302605 bol += strspn(bol, " \t");
2606 item->flags |= TODO_EDIT_FIXUP_MSG;
2607 }
2608 }
2609
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002610 if (item->command == TODO_MERGE) {
2611 if (skip_prefix(bol, "-C", &bol))
2612 bol += strspn(bol, " \t");
2613 else if (skip_prefix(bol, "-c", &bol)) {
2614 bol += strspn(bol, " \t");
2615 item->flags |= TODO_EDIT_MERGE_MSG;
2616 } else {
2617 item->flags |= TODO_EDIT_MERGE_MSG;
2618 item->commit = NULL;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002619 item->arg_offset = bol - buf;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02002620 item->arg_len = (int)(eol - bol);
2621 return 0;
2622 }
2623 }
2624
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002625 end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302626 saved = *end_of_object_name;
2627 *end_of_object_name = '\0';
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02002628 status = repo_get_oid(r, bol, &commit_oid);
Johannes Schindelind859dca2020-01-23 12:28:17 +00002629 if (status < 0)
2630 error(_("could not parse '%s'"), bol); /* return later */
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302631 *end_of_object_name = saved;
2632
Alban Gruin6ad656d2019-01-29 16:01:46 +01002633 bol = end_of_object_name + strspn(end_of_object_name, " \t");
2634 item->arg_offset = bol - buf;
2635 item->arg_len = (int)(eol - bol);
Johannes Schindelinc22f7df2016-10-21 14:25:00 +02002636
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302637 if (status < 0)
Johannes Schindelind859dca2020-01-23 12:28:17 +00002638 return status;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302639
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002640 item->commit = lookup_commit_reference(r, &commit_oid);
Johannes Schindelind859dca2020-01-23 12:28:17 +00002641 return item->commit ? 0 : -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302642}
2643
Phillip Wood4a724862019-04-16 11:18:42 +01002644int sequencer_get_last_command(struct repository *r, enum replay_action *action)
2645{
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002646 const char *todo_file, *bol;
Phillip Wood4a724862019-04-16 11:18:42 +01002647 struct strbuf buf = STRBUF_INIT;
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002648 int ret = 0;
Phillip Wood4a724862019-04-16 11:18:42 +01002649
2650 todo_file = git_path_todo_file();
2651 if (strbuf_read_file(&buf, todo_file, 0) < 0) {
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002652 if (errno == ENOENT || errno == ENOTDIR)
Phillip Wood4a724862019-04-16 11:18:42 +01002653 return -1;
2654 else
2655 return error_errno("unable to open '%s'", todo_file);
2656 }
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002657 bol = buf.buf + strspn(buf.buf, " \t\r\n");
2658 if (is_command(TODO_PICK, &bol) && (*bol == ' ' || *bol == '\t'))
Phillip Wood4a724862019-04-16 11:18:42 +01002659 *action = REPLAY_PICK;
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002660 else if (is_command(TODO_REVERT, &bol) &&
2661 (*bol == ' ' || *bol == '\t'))
Phillip Wood4a724862019-04-16 11:18:42 +01002662 *action = REPLAY_REVERT;
2663 else
Phillip Wooded5b1ca2019-06-27 07:12:46 -07002664 ret = -1;
Phillip Wood4a724862019-04-16 11:18:42 +01002665
Phillip Wood4a724862019-04-16 11:18:42 +01002666 strbuf_release(&buf);
2667
2668 return ret;
2669}
2670
Alban Gruin5d94d542018-12-29 17:03:59 +01002671int todo_list_parse_insn_buffer(struct repository *r, char *buf,
2672 struct todo_list *todo_list)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302673{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002674 struct todo_item *item;
2675 char *p = buf, *next_p;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002676 int i, res = 0, fixup_okay = file_exists(rebase_path_done());
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302677
Johannes Schindelin170eea92023-05-13 08:11:26 +00002678 todo_list->current = todo_list->nr = todo_list->total_nr = 0;
Alban Gruin2b715952018-12-29 17:03:58 +01002679
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002680 for (i = 1; *p; i++, p = next_p) {
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302681 char *eol = strchrnul(p, '\n');
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002682
2683 next_p = *eol ? eol + 1 /* skip LF */ : eol;
2684
Johannes Schindelin63070412016-10-21 14:24:46 +02002685 if (p != eol && eol[-1] == '\r')
2686 eol--; /* strip Carriage Return */
2687
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002688 item = append_new_todo(todo_list);
2689 item->offset_in_buf = p - todo_list->buf.buf;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002690 if (parse_insn_line(r, item, buf, p, eol)) {
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002691 res = error(_("invalid line %d: %.*s"),
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002692 i, (int)(eol - p), p);
Alban Gruin2b715952018-12-29 17:03:58 +01002693 item->command = TODO_COMMENT + 1;
Alban Gruin6ad656d2019-01-29 16:01:46 +01002694 item->arg_offset = p - buf;
Alban Gruin2b715952018-12-29 17:03:58 +01002695 item->arg_len = (int)(eol - p);
2696 item->commit = NULL;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002697 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002698
Johannes Schindelin170eea92023-05-13 08:11:26 +00002699 if (item->command != TODO_COMMENT)
2700 todo_list->total_nr++;
2701
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002702 if (fixup_okay)
2703 ; /* do nothing */
2704 else if (is_fixup(item->command))
Alex Henrie9645a082023-07-22 15:28:25 -06002705 res = error(_("cannot '%s' without a previous commit"),
Johannes Schindelin6e98de72017-01-02 16:27:07 +01002706 command_to_string(item->command));
2707 else if (!is_noop(item->command))
2708 fixup_okay = 1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302709 }
Johannes Schindelin52865272017-01-02 16:27:34 +01002710
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002711 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302712}
2713
Johannes Schindelin968492e2017-01-02 16:35:46 +01002714static int count_commands(struct todo_list *todo_list)
2715{
2716 int count = 0, i;
2717
2718 for (i = 0; i < todo_list->nr; i++)
2719 if (todo_list->items[i].command != TODO_COMMENT)
2720 count++;
2721
2722 return count;
2723}
2724
Johannes Schindelina01c2a52018-04-25 14:28:29 +02002725static int get_item_line_offset(struct todo_list *todo_list, int index)
2726{
2727 return index < todo_list->nr ?
2728 todo_list->items[index].offset_in_buf : todo_list->buf.len;
2729}
2730
2731static const char *get_item_line(struct todo_list *todo_list, int index)
2732{
2733 return todo_list->buf.buf + get_item_line_offset(todo_list, index);
2734}
2735
2736static int get_item_line_length(struct todo_list *todo_list, int index)
2737{
2738 return get_item_line_offset(todo_list, index + 1)
2739 - get_item_line_offset(todo_list, index);
2740}
2741
René Scharfe87805602018-02-22 20:29:25 +01002742static ssize_t strbuf_read_file_or_whine(struct strbuf *sb, const char *path)
2743{
2744 int fd;
2745 ssize_t len;
2746
2747 fd = open(path, O_RDONLY);
2748 if (fd < 0)
2749 return error_errno(_("could not open '%s'"), path);
2750 len = strbuf_read(sb, fd, 0);
2751 close(fd);
2752 if (len < 0)
2753 return error(_("could not read '%s'."), path);
2754 return len;
2755}
2756
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002757static int have_finished_the_last_pick(void)
2758{
2759 struct strbuf buf = STRBUF_INIT;
2760 const char *eol;
2761 const char *todo_path = git_path_todo_file();
2762 int ret = 0;
2763
2764 if (strbuf_read_file(&buf, todo_path, 0) < 0) {
2765 if (errno == ENOENT) {
2766 return 0;
2767 } else {
2768 error_errno("unable to open '%s'", todo_path);
2769 return 0;
2770 }
2771 }
2772 /* If there is only one line then we are done */
2773 eol = strchr(buf.buf, '\n');
2774 if (!eol || !eol[1])
2775 ret = 1;
2776
2777 strbuf_release(&buf);
2778
2779 return ret;
2780}
2781
Junio C Hamanof496b062019-07-09 15:25:44 -07002782void sequencer_post_commit_cleanup(struct repository *r, int verbose)
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002783{
2784 struct replay_opts opts = REPLAY_OPTS_INIT;
2785 int need_cleanup = 0;
2786
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00002787 if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
2788 if (!refs_delete_ref(get_main_ref_store(r), "",
2789 "CHERRY_PICK_HEAD", NULL, 0) &&
2790 verbose)
Junio C Hamanof496b062019-07-09 15:25:44 -07002791 warning(_("cancelling a cherry picking in progress"));
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002792 opts.action = REPLAY_PICK;
2793 need_cleanup = 1;
2794 }
2795
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00002796 if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
2797 if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
2798 NULL, 0) &&
2799 verbose)
Junio C Hamanof496b062019-07-09 15:25:44 -07002800 warning(_("cancelling a revert in progress"));
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002801 opts.action = REPLAY_REVERT;
2802 need_cleanup = 1;
2803 }
2804
Elijah Newren52918282021-03-20 00:03:52 +00002805 unlink(git_path_auto_merge(r));
2806
Phillip Woodb07d9bf2019-04-16 11:18:41 +01002807 if (!need_cleanup)
2808 return;
2809
2810 if (!have_finished_the_last_pick())
2811 return;
2812
2813 sequencer_remove_state(&opts);
2814}
2815
Alban Gruin3f34f2d2019-11-24 18:43:30 +01002816static void todo_list_write_total_nr(struct todo_list *todo_list)
2817{
2818 FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
2819
2820 if (f) {
2821 fprintf(f, "%d\n", todo_list->total_nr);
2822 fclose(f);
2823 }
2824}
2825
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01002826static int read_populate_todo(struct repository *r,
2827 struct todo_list *todo_list,
2828 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302829{
Johannes Schindelinc0246502016-10-21 14:24:32 +02002830 const char *todo_file = get_todo_path(opts);
René Scharfe87805602018-02-22 20:29:25 +01002831 int res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302832
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002833 strbuf_reset(&todo_list->buf);
René Scharfe87805602018-02-22 20:29:25 +01002834 if (strbuf_read_file_or_whine(&todo_list->buf, todo_file) < 0)
2835 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302836
Alban Gruin5d94d542018-12-29 17:03:59 +01002837 res = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list);
Johannes Schindelin27fdbb92017-01-02 16:35:42 +01002838 if (res) {
2839 if (is_rebase_i(opts))
2840 return error(_("please fix this using "
2841 "'git rebase --edit-todo'."));
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002842 return error(_("unusable instruction sheet: '%s'"), todo_file);
Johannes Schindelin27fdbb92017-01-02 16:35:42 +01002843 }
Johannes Schindelin2eeaf1b2016-10-21 14:26:13 +02002844
Johannes Schindelin52865272017-01-02 16:27:34 +01002845 if (!todo_list->nr &&
2846 (!is_rebase_i(opts) || !file_exists(rebase_path_done())))
2847 return error(_("no commits parsed."));
2848
Johannes Schindelin2eeaf1b2016-10-21 14:26:13 +02002849 if (!is_rebase_i(opts)) {
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002850 enum todo_command valid =
2851 opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;
2852 int i;
2853
2854 for (i = 0; i < todo_list->nr; i++)
2855 if (valid == todo_list->items[i].command)
2856 continue;
2857 else if (valid == TODO_PICK)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002858 return error(_("cannot cherry-pick during a revert."));
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002859 else
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002860 return error(_("cannot revert during a cherry-pick."));
Johannes Schindelin004fefa2016-10-21 14:24:41 +02002861 }
2862
Johannes Schindelin968492e2017-01-02 16:35:46 +01002863 if (is_rebase_i(opts)) {
2864 struct todo_list done = TODO_LIST_INIT;
2865
2866 if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
Alban Gruin5d94d542018-12-29 17:03:59 +01002867 !todo_list_parse_insn_buffer(r, done.buf.buf, &done))
Johannes Schindelin968492e2017-01-02 16:35:46 +01002868 todo_list->done_nr = count_commands(&done);
2869 else
2870 todo_list->done_nr = 0;
2871
2872 todo_list->total_nr = todo_list->done_nr
2873 + count_commands(todo_list);
Johannes Schindelin968492e2017-01-02 16:35:46 +01002874 todo_list_release(&done);
Johannes Schindelinef800692017-01-02 16:36:20 +01002875
Alban Gruin3f34f2d2019-11-24 18:43:30 +01002876 todo_list_write_total_nr(todo_list);
Johannes Schindelin968492e2017-01-02 16:35:46 +01002877 }
2878
Johannes Schindelin0ae42a02016-09-09 16:37:24 +02002879 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302880}
2881
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002882static int git_config_string_dup(char **dest,
2883 const char *var, const char *value)
2884{
2885 if (!value)
2886 return config_error_nonbool(var);
2887 free(*dest);
2888 *dest = xstrdup(value);
2889 return 0;
2890}
2891
Glen Chooa4e7e312023-06-28 19:26:22 +00002892static int populate_opts_cb(const char *key, const char *value,
Glen Choo8868b1e2023-06-28 19:26:27 +00002893 const struct config_context *ctx,
Glen Chooa4e7e312023-06-28 19:26:22 +00002894 void *data)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302895{
2896 struct replay_opts *opts = data;
2897 int error_flag = 1;
2898
2899 if (!value)
2900 error_flag = 0;
2901 else if (!strcmp(key, "options.no-commit"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002902 opts->no_commit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302903 else if (!strcmp(key, "options.edit"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002904 opts->edit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002905 else if (!strcmp(key, "options.allow-empty"))
2906 opts->allow_empty =
Glen Choo8868b1e2023-06-28 19:26:27 +00002907 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002908 else if (!strcmp(key, "options.allow-empty-message"))
2909 opts->allow_empty_message =
Glen Choo8868b1e2023-06-28 19:26:27 +00002910 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Phillip Wood6860ce52019-03-13 18:26:15 +00002911 else if (!strcmp(key, "options.keep-redundant-commits"))
2912 opts->keep_redundant_commits =
Glen Choo8868b1e2023-06-28 19:26:27 +00002913 git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302914 else if (!strcmp(key, "options.signoff"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002915 opts->signoff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302916 else if (!strcmp(key, "options.record-origin"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002917 opts->record_origin = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302918 else if (!strcmp(key, "options.allow-ff"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002919 opts->allow_ff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302920 else if (!strcmp(key, "options.mainline"))
Glen Choo8868b1e2023-06-28 19:26:27 +00002921 opts->mainline = git_config_int(key, value, ctx->kvi);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302922 else if (!strcmp(key, "options.strategy"))
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002923 git_config_string_dup(&opts->strategy, key, value);
Nicolas Vigier32535532014-01-24 00:50:58 +00002924 else if (!strcmp(key, "options.gpg-sign"))
Johannes Schindelin03a4e262016-10-21 14:24:13 +02002925 git_config_string_dup(&opts->gpg_sign, key, value);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302926 else if (!strcmp(key, "options.strategy-option")) {
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002927 strvec_push(&opts->xopts, value);
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01002928 } else if (!strcmp(key, "options.allow-rerere-auto"))
2929 opts->allow_rerere_auto =
Glen Choo8868b1e2023-06-28 19:26:27 +00002930 git_config_bool_or_int(key, value, ctx->kvi, &error_flag) ?
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01002931 RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
Phillip Wooddc42e9a2019-04-17 11:23:29 +01002932 else if (!strcmp(key, "options.default-msg-cleanup")) {
2933 opts->explicit_cleanup = 1;
2934 opts->default_msg_cleanup = get_cleanup_mode(value, 1);
2935 } else
Johannes Schindelin93b3df62016-10-21 14:26:25 +02002936 return error(_("invalid key: %s"), key);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302937
2938 if (!error_flag)
Jean-Noël Avila1a8aea82022-01-31 22:07:47 +00002939 return error(_("invalid value for '%s': '%s'"), key, value);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302940
2941 return 0;
2942}
2943
Phillip Wood4a8bc982023-04-10 10:08:29 +01002944static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002945{
2946 int i;
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01002947 int count;
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002948 const char **argv;
Alban Gruin65850682018-08-28 14:10:40 +02002949 char *strategy_opts_string = raw_opts;
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002950
Elijah Newren00600412018-06-27 08:48:04 -07002951 if (*strategy_opts_string == ' ')
2952 strategy_opts_string++;
Alban Gruin65850682018-08-28 14:10:40 +02002953
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002954 count = split_cmdline(strategy_opts_string, &argv);
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01002955 if (count < 0)
Phillip Wood4960e5c2023-04-10 10:08:30 +01002956 BUG("could not split '%s': %s", strategy_opts_string,
Ævar Arnfjörð Bjarmason15a4cc92023-03-07 19:21:59 +01002957 split_cmdline_strerror(count));
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002958 for (i = 0; i < count; i++) {
2959 const char *arg = argv[i];
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002960
2961 skip_prefix(arg, "--", &arg);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002962 strvec_push(&opts->xopts, arg);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002963 }
Phillip Woodfb60b9f2023-04-10 10:08:28 +01002964 free(argv);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01002965}
2966
Alban Gruin65850682018-08-28 14:10:40 +02002967static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
2968{
2969 strbuf_reset(buf);
2970 if (!read_oneliner(buf, rebase_path_strategy(), 0))
2971 return;
2972 opts->strategy = strbuf_detach(buf, NULL);
2973 if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
2974 return;
2975
2976 parse_strategy_opts(opts, buf->buf);
2977}
2978
Johannes Schindelin5adf9bd2016-10-14 15:17:16 +02002979static int read_populate_opts(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05302980{
Johannes Schindelina1c75762016-10-21 14:25:12 +02002981 if (is_rebase_i(opts)) {
2982 struct strbuf buf = STRBUF_INIT;
Denton Liu65c425a2020-04-03 21:11:16 -04002983 int ret = 0;
Johannes Schindelina1c75762016-10-21 14:25:12 +02002984
Denton Liu3442c3d2020-04-07 10:27:52 -04002985 if (read_oneliner(&buf, rebase_path_gpg_sign_opt(),
2986 READ_ONELINER_SKIP_IF_EMPTY)) {
Johannes Schindelina1c75762016-10-21 14:25:12 +02002987 if (!starts_with(buf.buf, "-S"))
2988 strbuf_reset(&buf);
2989 else {
2990 free(opts->gpg_sign);
2991 opts->gpg_sign = xstrdup(buf.buf + 2);
2992 }
Phillip Wood9b6d7a62017-08-02 11:44:17 +01002993 strbuf_reset(&buf);
2994 }
2995
Denton Liu3442c3d2020-04-07 10:27:52 -04002996 if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(),
2997 READ_ONELINER_SKIP_IF_EMPTY)) {
Phillip Wood9b6d7a62017-08-02 11:44:17 +01002998 if (!strcmp(buf.buf, "--rerere-autoupdate"))
2999 opts->allow_rerere_auto = RERERE_AUTOUPDATE;
3000 else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
3001 opts->allow_rerere_auto = RERERE_NOAUTOUPDATE;
3002 strbuf_reset(&buf);
Johannes Schindelina1c75762016-10-21 14:25:12 +02003003 }
Johannes Schindelina1c75762016-10-21 14:25:12 +02003004
Johannes Schindelin556907f2017-01-02 16:26:53 +01003005 if (file_exists(rebase_path_verbose()))
3006 opts->verbose = 1;
3007
Elijah Newren899b49c2018-12-11 08:11:36 -08003008 if (file_exists(rebase_path_quiet()))
3009 opts->quiet = 1;
3010
Phillip Wooda852ec72018-03-20 11:10:55 +00003011 if (file_exists(rebase_path_signoff())) {
3012 opts->allow_ff = 0;
3013 opts->signoff = 1;
3014 }
3015
Phillip Wood7573cec2020-08-17 18:40:02 +01003016 if (file_exists(rebase_path_cdate_is_adate())) {
3017 opts->allow_ff = 0;
3018 opts->committer_date_is_author_date = 1;
3019 }
3020
Phillip Wooda3894aa2020-08-17 18:40:03 +01003021 if (file_exists(rebase_path_ignore_date())) {
3022 opts->allow_ff = 0;
3023 opts->ignore_date = 1;
3024 }
3025
Johannes Schindelind421afa2018-12-10 11:04:58 -08003026 if (file_exists(rebase_path_reschedule_failed_exec()))
3027 opts->reschedule_failed_exec = 1;
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +02003028 else if (file_exists(rebase_path_no_reschedule_failed_exec()))
3029 opts->reschedule_failed_exec = 0;
Johannes Schindelind421afa2018-12-10 11:04:58 -08003030
Elijah Newrene98c4262020-02-15 21:36:25 +00003031 if (file_exists(rebase_path_drop_redundant_commits()))
3032 opts->drop_redundant_commits = 1;
3033
3034 if (file_exists(rebase_path_keep_redundant_commits()))
3035 opts->keep_redundant_commits = 1;
3036
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003037 read_strategy_opts(opts, &buf);
Denton Liu65c425a2020-04-03 21:11:16 -04003038 strbuf_reset(&buf);
Johannes Schindelinca6c6b42017-01-02 16:28:30 +01003039
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003040 if (read_oneliner(&opts->current_fixups,
Denton Liu3442c3d2020-04-07 10:27:52 -04003041 rebase_path_current_fixups(),
3042 READ_ONELINER_SKIP_IF_EMPTY)) {
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003043 const char *p = opts->current_fixups.buf;
3044 opts->current_fixup_count = 1;
3045 while ((p = strchr(p, '\n'))) {
3046 opts->current_fixup_count++;
3047 p++;
3048 }
3049 }
3050
Johannes Schindelind87d48b2018-05-04 01:01:17 +02003051 if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003052 if (repo_get_oid_committish(the_repository, buf.buf, &opts->squash_onto) < 0) {
Denton Liu65c425a2020-04-03 21:11:16 -04003053 ret = error(_("unusable squash-onto"));
3054 goto done_rebase_i;
3055 }
Johannes Schindelind87d48b2018-05-04 01:01:17 +02003056 opts->have_squash_onto = 1;
3057 }
3058
Denton Liu65c425a2020-04-03 21:11:16 -04003059done_rebase_i:
3060 strbuf_release(&buf);
3061 return ret;
Johannes Schindelina1c75762016-10-21 14:25:12 +02003062 }
Johannes Schindelinb5a67042016-10-21 14:25:04 +02003063
Jeff Kingf9327292015-08-10 05:38:57 -04003064 if (!file_exists(git_path_opts_file()))
Johannes Schindelin0d00da72016-09-09 16:37:27 +02003065 return 0;
3066 /*
3067 * The function git_parse_source(), called from git_config_from_file(),
3068 * may die() in case of a syntactically incorrect file. We do not care
3069 * about this case, though, because we wrote that file ourselves, so we
3070 * are pretty certain that it is syntactically correct.
3071 */
Johannes Schindelin5adf9bd2016-10-14 15:17:16 +02003072 if (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003073 return error(_("malformed options sheet: '%s'"),
Johannes Schindelin0d00da72016-09-09 16:37:27 +02003074 git_path_opts_file());
3075 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303076}
3077
Alban Gruin65850682018-08-28 14:10:40 +02003078static void write_strategy_opts(struct replay_opts *opts)
3079{
Alban Gruin65850682018-08-28 14:10:40 +02003080 struct strbuf buf = STRBUF_INIT;
3081
Phillip Wood4960e5c2023-04-10 10:08:30 +01003082 /*
3083 * Quote strategy options so that they can be read correctly
3084 * by split_cmdline().
3085 */
3086 quote_cmdline(&buf, opts->xopts.v);
Alban Gruin65850682018-08-28 14:10:40 +02003087 write_file(rebase_path_strategy_opts(), "%s\n", buf.buf);
3088 strbuf_release(&buf);
3089}
3090
3091int write_basic_state(struct replay_opts *opts, const char *head_name,
Phillip Wooda2bb10d2020-11-04 15:29:39 +00003092 struct commit *onto, const struct object_id *orig_head)
Alban Gruin65850682018-08-28 14:10:40 +02003093{
Alban Gruin65850682018-08-28 14:10:40 +02003094 if (head_name)
3095 write_file(rebase_path_head_name(), "%s\n", head_name);
3096 if (onto)
Phillip Wood7d3488e2019-04-17 15:30:39 +01003097 write_file(rebase_path_onto(), "%s\n",
3098 oid_to_hex(&onto->object.oid));
Alban Gruin65850682018-08-28 14:10:40 +02003099 if (orig_head)
Phillip Wooda2bb10d2020-11-04 15:29:39 +00003100 write_file(rebase_path_orig_head(), "%s\n",
3101 oid_to_hex(orig_head));
Alban Gruin65850682018-08-28 14:10:40 +02003102
Elijah Newren8a997ed2020-02-15 21:36:27 +00003103 if (opts->quiet)
3104 write_file(rebase_path_quiet(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003105 if (opts->verbose)
Carlo Marcelo Arenas Belón4af51742018-10-25 02:38:54 -07003106 write_file(rebase_path_verbose(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003107 if (opts->strategy)
3108 write_file(rebase_path_strategy(), "%s\n", opts->strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003109 if (opts->xopts.nr > 0)
Alban Gruin65850682018-08-28 14:10:40 +02003110 write_strategy_opts(opts);
3111
3112 if (opts->allow_rerere_auto == RERERE_AUTOUPDATE)
3113 write_file(rebase_path_allow_rerere_autoupdate(), "--rerere-autoupdate\n");
3114 else if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)
3115 write_file(rebase_path_allow_rerere_autoupdate(), "--no-rerere-autoupdate\n");
3116
3117 if (opts->gpg_sign)
3118 write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
3119 if (opts->signoff)
3120 write_file(rebase_path_signoff(), "--signoff\n");
Elijah Newrene98c4262020-02-15 21:36:25 +00003121 if (opts->drop_redundant_commits)
3122 write_file(rebase_path_drop_redundant_commits(), "%s", "");
3123 if (opts->keep_redundant_commits)
3124 write_file(rebase_path_keep_redundant_commits(), "%s", "");
Phillip Wood7573cec2020-08-17 18:40:02 +01003125 if (opts->committer_date_is_author_date)
3126 write_file(rebase_path_cdate_is_adate(), "%s", "");
Phillip Wooda3894aa2020-08-17 18:40:03 +01003127 if (opts->ignore_date)
3128 write_file(rebase_path_ignore_date(), "%s", "");
Johannes Schindelind421afa2018-12-10 11:04:58 -08003129 if (opts->reschedule_failed_exec)
3130 write_file(rebase_path_reschedule_failed_exec(), "%s", "");
Ævar Arnfjörð Bjarmasone5b32bf2021-04-09 10:01:38 +02003131 else
3132 write_file(rebase_path_no_reschedule_failed_exec(), "%s", "");
Alban Gruin65850682018-08-28 14:10:40 +02003133
3134 return 0;
3135}
3136
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003137static int walk_revs_populate_todo(struct todo_list *todo_list,
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303138 struct replay_opts *opts)
3139{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003140 enum todo_command command = opts->action == REPLAY_PICK ?
3141 TODO_PICK : TODO_REVERT;
Johannes Schindelin414697a2017-01-02 16:27:15 +01003142 const char *command_string = todo_command_info[command].str;
Doan Tran Cong Danh019a9d82019-11-08 16:43:47 +07003143 const char *encoding;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303144 struct commit *commit;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303145
Johannes Schindelin34b05282016-09-09 16:37:15 +02003146 if (prepare_revs(opts))
3147 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303148
Doan Tran Cong Danh019a9d82019-11-08 16:43:47 +07003149 encoding = get_log_output_encoding();
3150
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003151 while ((commit = get_revision(opts->revs))) {
3152 struct todo_item *item = append_new_todo(todo_list);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003153 const char *commit_buffer = repo_logmsg_reencode(the_repository,
3154 commit, NULL,
3155 encoding);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003156 const char *subject;
3157 int subject_len;
3158
3159 item->command = command;
3160 item->commit = commit;
Alban Gruin6ad656d2019-01-29 16:01:46 +01003161 item->arg_offset = 0;
Johannes Schindelinc22f7df2016-10-21 14:25:00 +02003162 item->arg_len = 0;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003163 item->offset_in_buf = todo_list->buf.len;
3164 subject_len = find_commit_subject(commit_buffer, &subject);
3165 strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
3166 short_commit_name(commit), subject_len, subject);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003167 repo_unuse_commit_buffer(the_repository, commit,
3168 commit_buffer);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003169 }
Jeff King8530c732018-07-09 15:48:19 -04003170
3171 if (!todo_list->nr)
3172 return error(_("empty commit set passed"));
3173
Johannes Schindelin34b05282016-09-09 16:37:15 +02003174 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303175}
3176
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303177static int create_seq_dir(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303178{
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303179 enum replay_action action;
3180 const char *in_progress_error = NULL;
3181 const char *in_progress_advice = NULL;
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003182 unsigned int advise_skip =
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003183 refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003184 refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303185
3186 if (!sequencer_get_last_command(r, &action)) {
3187 switch (action) {
3188 case REPLAY_REVERT:
3189 in_progress_error = _("revert is already in progress");
3190 in_progress_advice =
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303191 _("try \"git revert (--continue | %s--abort | --quit)\"");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303192 break;
3193 case REPLAY_PICK:
3194 in_progress_error = _("cherry-pick is already in progress");
3195 in_progress_advice =
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303196 _("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303197 break;
3198 default:
3199 BUG("unexpected action in create_seq_dir");
3200 }
3201 }
3202 if (in_progress_error) {
3203 error("%s", in_progress_error);
Ben Boeckeled9bff02021-08-23 12:44:00 +02003204 if (advice_enabled(ADVICE_SEQUENCER_IN_USE))
Rohit Ashiwaldcb500d2019-07-02 14:41:29 +05303205 advise(in_progress_advice,
3206 advise_skip ? "--skip | " : "");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303207 return -1;
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303208 }
3209 if (mkdir(git_path_seq_dir(), 0777) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003210 return error_errno(_("could not create sequencer directory '%s'"),
Johannes Schindelinf6e82b02016-09-09 16:37:44 +02003211 git_path_seq_dir());
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05303212
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303213 return 0;
3214}
3215
Johannes Schindelin311fd392016-09-09 16:37:47 +02003216static int save_head(const char *head)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303217{
Oswald Buddenhagen54dbd092023-03-23 17:22:35 +01003218 return write_message(head, strlen(head), git_path_head_file(), 1);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303219}
3220
Stephan Beyer1e412292016-12-07 22:51:32 +01003221static int rollback_is_safe(void)
3222{
3223 struct strbuf sb = STRBUF_INIT;
3224 struct object_id expected_head, actual_head;
3225
3226 if (strbuf_read_file(&sb, git_path_abort_safety_file(), 0) >= 0) {
3227 strbuf_trim(&sb);
3228 if (get_oid_hex(sb.buf, &expected_head)) {
3229 strbuf_release(&sb);
3230 die(_("could not parse %s"), git_path_abort_safety_file());
3231 }
3232 strbuf_release(&sb);
3233 }
3234 else if (errno == ENOENT)
3235 oidclr(&expected_head);
3236 else
3237 die_errno(_("could not read '%s'"), git_path_abort_safety_file());
3238
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003239 if (repo_get_oid(the_repository, "HEAD", &actual_head))
Stephan Beyer1e412292016-12-07 22:51:32 +01003240 oidclr(&actual_head);
3241
Jeff King4a7e27e2018-08-28 17:22:40 -04003242 return oideq(&actual_head, &expected_head);
Stephan Beyer1e412292016-12-07 22:51:32 +01003243}
3244
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303245static int reset_merge(const struct object_id *oid)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303246{
René Scharfe0e906732022-10-30 12:51:14 +01003247 struct child_process cmd = CHILD_PROCESS_INIT;
Stephan Beyer1e412292016-12-07 22:51:32 +01003248
René Scharfe0e906732022-10-30 12:51:14 +01003249 cmd.git_cmd = 1;
3250 strvec_pushl(&cmd.args, "reset", "--merge", NULL);
Rohit Ashiwal265ab482019-07-02 14:41:27 +05303251
3252 if (!is_null_oid(oid))
René Scharfe0e906732022-10-30 12:51:14 +01003253 strvec_push(&cmd.args, oid_to_hex(oid));
Rohit Ashiwal265ab482019-07-02 14:41:27 +05303254
René Scharfe0e906732022-10-30 12:51:14 +01003255 return run_command(&cmd);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303256}
3257
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003258static int rollback_single_pick(struct repository *r)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303259{
brian m. carlson092bbcd2017-07-13 23:49:22 +00003260 struct object_id head_oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303261
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003262 if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003263 !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303264 return error(_("no cherry-pick or revert in progress"));
brian m. carlson34c290a2017-10-15 22:06:56 +00003265 if (read_ref_full("HEAD", 0, &head_oid, NULL))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303266 return error(_("cannot resolve HEAD"));
brian m. carlson092bbcd2017-07-13 23:49:22 +00003267 if (is_null_oid(&head_oid))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303268 return error(_("cannot abort from a branch yet to be born"));
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303269 return reset_merge(&head_oid);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303270}
3271
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303272static int skip_single_pick(void)
3273{
3274 struct object_id head;
3275
3276 if (read_ref_full("HEAD", 0, &head, NULL))
3277 return error(_("cannot resolve HEAD"));
3278 return reset_merge(&head);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303279}
3280
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003281int sequencer_rollback(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303282{
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303283 FILE *f;
brian m. carlson092bbcd2017-07-13 23:49:22 +00003284 struct object_id oid;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303285 struct strbuf buf = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00003286 const char *p;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303287
Jeff Kingf9327292015-08-10 05:38:57 -04003288 f = fopen(git_path_head_file(), "r");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303289 if (!f && errno == ENOENT) {
3290 /*
3291 * There is no multiple-cherry-pick in progress.
3292 * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
3293 * a single-cherry-pick in progress, abort that.
3294 */
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01003295 return rollback_single_pick(r);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303296 }
3297 if (!f)
Johannes Schindelinf7ed1952016-10-21 14:26:21 +02003298 return error_errno(_("cannot open '%s'"), git_path_head_file());
Junio C Hamano8f309ae2016-01-13 15:31:17 -08003299 if (strbuf_getline_lf(&buf, f)) {
Johannes Schindelinf7ed1952016-10-21 14:26:21 +02003300 error(_("cannot read '%s': %s"), git_path_head_file(),
Jeff Kingf9327292015-08-10 05:38:57 -04003301 ferror(f) ? strerror(errno) : _("unexpected end of file"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303302 fclose(f);
3303 goto fail;
3304 }
3305 fclose(f);
brian m. carlson092bbcd2017-07-13 23:49:22 +00003306 if (parse_oid_hex(buf.buf, &oid, &p) || *p != '\0') {
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303307 error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
Jeff Kingf9327292015-08-10 05:38:57 -04003308 git_path_head_file());
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303309 goto fail;
3310 }
brian m. carlson092bbcd2017-07-13 23:49:22 +00003311 if (is_null_oid(&oid)) {
Michael J Gruber0f974e22016-06-06 15:23:54 +02003312 error(_("cannot abort from a branch yet to be born"));
3313 goto fail;
3314 }
Stephan Beyer1e412292016-12-07 22:51:32 +01003315
3316 if (!rollback_is_safe()) {
3317 /* Do not error, just do not rollback */
3318 warning(_("You seem to have moved HEAD. "
3319 "Not rewinding, check your HEAD!"));
3320 } else
Rohit Ashiwal918d1e62019-07-02 14:41:26 +05303321 if (reset_merge(&oid))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303322 goto fail;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303323 strbuf_release(&buf);
Johannes Schindelin28635842016-10-21 14:24:55 +02003324 return sequencer_remove_state(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303325fail:
3326 strbuf_release(&buf);
3327 return -1;
3328}
3329
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303330int sequencer_skip(struct repository *r, struct replay_opts *opts)
3331{
3332 enum replay_action action = -1;
3333 sequencer_get_last_command(r, &action);
3334
3335 /*
3336 * Check whether the subcommand requested to skip the commit is actually
3337 * in progress and that it's safe to skip the commit.
3338 *
3339 * opts->action tells us which subcommand requested to skip the commit.
3340 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
3341 * action is in progress and we can skip the commit.
3342 *
3343 * Otherwise we check that the last instruction was related to the
3344 * particular subcommand we're trying to execute and barf if that's not
3345 * the case.
3346 *
3347 * Finally we check that the rollback is "safe", i.e., has the HEAD
3348 * moved? In this case, it doesn't make sense to "reset the merge" and
3349 * "skip the commit" as the user already handled this by committing. But
3350 * we'd not want to barf here, instead give advice on how to proceed. We
3351 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
3352 * it gets removed when the user commits, so if it still exists we're
3353 * sure the user can't have committed before.
3354 */
3355 switch (opts->action) {
3356 case REPLAY_REVERT:
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00003357 if (!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303358 if (action != REPLAY_REVERT)
3359 return error(_("no revert in progress"));
3360 if (!rollback_is_safe())
3361 goto give_advice;
3362 }
3363 break;
3364 case REPLAY_PICK:
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00003365 if (!refs_ref_exists(get_main_ref_store(r),
3366 "CHERRY_PICK_HEAD")) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303367 if (action != REPLAY_PICK)
3368 return error(_("no cherry-pick in progress"));
3369 if (!rollback_is_safe())
3370 goto give_advice;
3371 }
3372 break;
3373 default:
3374 BUG("unexpected action in sequencer_skip");
3375 }
3376
3377 if (skip_single_pick())
3378 return error(_("failed to skip the commit"));
3379 if (!is_directory(git_path_seq_dir()))
3380 return 0;
3381
3382 return sequencer_continue(r, opts);
3383
3384give_advice:
3385 error(_("there is nothing to skip"));
3386
Ben Boeckeled9bff02021-08-23 12:44:00 +02003387 if (advice_enabled(ADVICE_RESOLVE_CONFLICT)) {
Rohit Ashiwalde81ca32019-07-02 14:41:28 +05303388 advise(_("have you committed already?\n"
3389 "try \"git %s --continue\""),
3390 action == REPLAY_REVERT ? "revert" : "cherry-pick");
3391 }
3392 return -1;
3393}
3394
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003395static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303396{
Martin Ågren14bca6c2018-02-27 22:30:09 +01003397 struct lock_file todo_lock = LOCK_INIT;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003398 const char *todo_path = get_todo_path(opts);
3399 int next = todo_list->current, offset, fd;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303400
Johannes Schindelin84583952017-01-02 16:26:28 +01003401 /*
3402 * rebase -i writes "git-rebase-todo" without the currently executing
3403 * command, appending it to "done" instead.
3404 */
3405 if (is_rebase_i(opts))
3406 next++;
3407
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003408 fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
Johannes Schindelin221675d2016-09-09 16:37:50 +02003409 if (fd < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003410 return error_errno(_("could not lock '%s'"), todo_path);
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003411 offset = get_item_line_offset(todo_list, next);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003412 if (write_in_full(fd, todo_list->buf.buf + offset,
3413 todo_list->buf.len - offset) < 0)
Johannes Schindelin93b3df62016-10-21 14:26:25 +02003414 return error_errno(_("could not write to '%s'"), todo_path);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02003415 if (commit_lock_file(&todo_lock) < 0)
Martin Ågren350292a2018-02-28 20:07:58 +01003416 return error(_("failed to finalize '%s'"), todo_path);
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003417
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003418 if (is_rebase_i(opts) && next > 0) {
3419 const char *done = rebase_path_done();
3420 int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
3421 int ret = 0;
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003422
Johannes Schindelina01c2a52018-04-25 14:28:29 +02003423 if (fd < 0)
3424 return 0;
3425 if (write_in_full(fd, get_item_line(todo_list, next - 1),
3426 get_item_line_length(todo_list, next - 1))
3427 < 0)
3428 ret = error_errno(_("could not write to '%s'"), done);
3429 if (close(fd) < 0)
3430 ret = error_errno(_("failed to finalize '%s'"), done);
3431 return ret;
Johannes Schindelin1df6df02017-01-02 16:27:00 +01003432 }
Johannes Schindelin221675d2016-09-09 16:37:50 +02003433 return 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303434}
3435
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003436static int save_opts(struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303437{
Jeff Kingf9327292015-08-10 05:38:57 -04003438 const char *opts_file = git_path_opts_file();
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003439 int res = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303440
3441 if (opts->no_commit)
Phillip Woodf59199d2019-03-13 18:26:13 +00003442 res |= git_config_set_in_file_gently(opts_file,
3443 "options.no-commit", "true");
Elijah Newren39edfd52021-03-31 06:52:20 +00003444 if (opts->edit >= 0)
3445 res |= git_config_set_in_file_gently(opts_file, "options.edit",
3446 opts->edit ? "true" : "false");
Phillip Wood6860ce52019-03-13 18:26:15 +00003447 if (opts->allow_empty)
3448 res |= git_config_set_in_file_gently(opts_file,
3449 "options.allow-empty", "true");
3450 if (opts->allow_empty_message)
3451 res |= git_config_set_in_file_gently(opts_file,
3452 "options.allow-empty-message", "true");
3453 if (opts->keep_redundant_commits)
3454 res |= git_config_set_in_file_gently(opts_file,
3455 "options.keep-redundant-commits", "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303456 if (opts->signoff)
Phillip Woodf59199d2019-03-13 18:26:13 +00003457 res |= git_config_set_in_file_gently(opts_file,
3458 "options.signoff", "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303459 if (opts->record_origin)
Phillip Woodf59199d2019-03-13 18:26:13 +00003460 res |= git_config_set_in_file_gently(opts_file,
3461 "options.record-origin", "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303462 if (opts->allow_ff)
Phillip Woodf59199d2019-03-13 18:26:13 +00003463 res |= git_config_set_in_file_gently(opts_file,
3464 "options.allow-ff", "true");
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303465 if (opts->mainline) {
3466 struct strbuf buf = STRBUF_INIT;
3467 strbuf_addf(&buf, "%d", opts->mainline);
Phillip Woodf59199d2019-03-13 18:26:13 +00003468 res |= git_config_set_in_file_gently(opts_file,
3469 "options.mainline", buf.buf);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303470 strbuf_release(&buf);
3471 }
3472 if (opts->strategy)
Phillip Woodf59199d2019-03-13 18:26:13 +00003473 res |= git_config_set_in_file_gently(opts_file,
3474 "options.strategy", opts->strategy);
Nicolas Vigier32535532014-01-24 00:50:58 +00003475 if (opts->gpg_sign)
Phillip Woodf59199d2019-03-13 18:26:13 +00003476 res |= git_config_set_in_file_gently(opts_file,
3477 "options.gpg-sign", opts->gpg_sign);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003478 for (size_t i = 0; i < opts->xopts.nr; i++)
3479 res |= git_config_set_multivar_in_file_gently(opts_file,
3480 "options.strategy-option",
3481 opts->xopts.v[i], "^$", 0);
Phillip Wood8d8cb4b2017-08-02 11:44:19 +01003482 if (opts->allow_rerere_auto)
Phillip Woodf59199d2019-03-13 18:26:13 +00003483 res |= git_config_set_in_file_gently(opts_file,
3484 "options.allow-rerere-auto",
3485 opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
3486 "true" : "false");
Phillip Wooddc42e9a2019-04-17 11:23:29 +01003487
3488 if (opts->explicit_cleanup)
3489 res |= git_config_set_in_file_gently(opts_file,
3490 "options.default-msg-cleanup",
3491 describe_cleanup_mode(opts->default_msg_cleanup));
Johannes Schindelin88d5a272016-09-09 16:37:53 +02003492 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05303493}
3494
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003495static int make_patch(struct repository *r,
3496 struct commit *commit,
3497 struct replay_opts *opts)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003498{
3499 struct strbuf buf = STRBUF_INIT;
3500 struct rev_info log_tree_opt;
Junio C Hamano0512eab2020-09-24 22:49:12 -07003501 const char *subject;
3502 char hex[GIT_MAX_HEXSZ + 1];
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003503 int res = 0;
3504
Junio C Hamano0512eab2020-09-24 22:49:12 -07003505 oid_to_hex_r(hex, &commit->object.oid);
3506 if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003507 return -1;
Phillip Wood430b75f2019-12-06 16:06:12 +00003508 res |= write_rebase_head(&commit->object.oid);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003509
3510 strbuf_addf(&buf, "%s/patch", get_dir(opts));
3511 memset(&log_tree_opt, 0, sizeof(log_tree_opt));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003512 repo_init_revisions(r, &log_tree_opt, NULL);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003513 log_tree_opt.abbrev = 0;
3514 log_tree_opt.diff = 1;
3515 log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
3516 log_tree_opt.disable_stdin = 1;
3517 log_tree_opt.no_commit_id = 1;
3518 log_tree_opt.diffopt.file = fopen(buf.buf, "w");
3519 log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
3520 if (!log_tree_opt.diffopt.file)
3521 res |= error_errno(_("could not open '%s'"), buf.buf);
3522 else {
3523 res |= log_tree_commit(&log_tree_opt, commit);
3524 fclose(log_tree_opt.diffopt.file);
3525 }
3526 strbuf_reset(&buf);
3527
3528 strbuf_addf(&buf, "%s/message", get_dir(opts));
3529 if (!file_exists(buf.buf)) {
Doan Tran Cong Danh52f52e52019-11-11 13:03:41 +07003530 const char *encoding = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003531 const char *commit_buffer = repo_logmsg_reencode(r,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003532 commit, NULL,
3533 encoding);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003534 find_commit_subject(commit_buffer, &subject);
3535 res |= write_message(subject, strlen(subject), buf.buf, 1);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003536 repo_unuse_commit_buffer(r, commit,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02003537 commit_buffer);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003538 }
3539 strbuf_release(&buf);
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02003540 release_revisions(&log_tree_opt);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003541
3542 return res;
3543}
3544
3545static int intend_to_amend(void)
3546{
brian m. carlson092bbcd2017-07-13 23:49:22 +00003547 struct object_id head;
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003548 char *p;
3549
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003550 if (repo_get_oid(the_repository, "HEAD", &head))
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003551 return error(_("cannot read HEAD"));
3552
brian m. carlson092bbcd2017-07-13 23:49:22 +00003553 p = oid_to_hex(&head);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003554 return write_message(p, strlen(p), rebase_path_amend(), 1);
3555}
3556
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003557static int error_with_patch(struct repository *r,
3558 struct commit *commit,
3559 const char *subject, int subject_len,
3560 struct replay_opts *opts,
3561 int exit_code, int to_amend)
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003562{
Phillip Woodbc9238b2018-08-15 10:39:35 +01003563 if (commit) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003564 if (make_patch(r, commit, opts))
Phillip Woodbc9238b2018-08-15 10:39:35 +01003565 return -1;
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003566 } else if (copy_file(rebase_path_message(),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003567 git_path_merge_msg(r), 0666))
Phillip Woodbc9238b2018-08-15 10:39:35 +01003568 return error(_("unable to copy '%s' to '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003569 git_path_merge_msg(r), rebase_path_message());
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003570
3571 if (to_amend) {
3572 if (intend_to_amend())
3573 return -1;
3574
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02003575 fprintf(stderr,
3576 _("You can amend the commit now, with\n"
3577 "\n"
3578 " git commit --amend %s\n"
3579 "\n"
3580 "Once you are satisfied with your changes, run\n"
3581 "\n"
3582 " git rebase --continue\n"),
3583 gpg_sign_opt_quoted(opts));
Phillip Woodbc9238b2018-08-15 10:39:35 +01003584 } else if (exit_code) {
3585 if (commit)
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003586 fprintf_ln(stderr, _("Could not apply %s... %.*s"),
3587 short_commit_name(commit), subject_len, subject);
Phillip Woodbc9238b2018-08-15 10:39:35 +01003588 else
3589 /*
3590 * We don't have the hash of the parent so
3591 * just print the line from the todo file.
3592 */
Junio C Hamano5a5c5e92018-08-20 12:41:33 -07003593 fprintf_ln(stderr, _("Could not merge %.*s"),
3594 subject_len, subject);
Phillip Woodbc9238b2018-08-15 10:39:35 +01003595 }
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01003596
3597 return exit_code;
3598}
3599
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003600static int error_failed_squash(struct repository *r,
3601 struct commit *commit,
3602 struct replay_opts *opts,
3603 int subject_len,
3604 const char *subject)
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003605{
Johannes Schindeline12a7ef2018-04-27 22:48:21 +02003606 if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
3607 return error(_("could not copy '%s' to '%s'"),
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003608 rebase_path_squash_msg(), rebase_path_message());
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003609 unlink(git_path_merge_msg(r));
3610 if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003611 return error(_("could not copy '%s' to '%s'"),
Stefan Beller102de882018-05-17 15:51:51 -07003612 rebase_path_message(),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003613 git_path_merge_msg(r));
3614 return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
Johannes Schindelin6e98de72017-01-02 16:27:07 +01003615}
3616
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003617static int do_exec(struct repository *r, const char *command_line)
Johannes Schindelin311af522017-01-02 16:26:47 +01003618{
René Scharfeddbb47f2022-10-30 12:55:06 +01003619 struct child_process cmd = CHILD_PROCESS_INIT;
Johannes Schindelin311af522017-01-02 16:26:47 +01003620 int dirty, status;
3621
Alban Gruin4d55d632020-03-28 14:05:15 +01003622 fprintf(stderr, _("Executing: %s\n"), command_line);
René Scharfeddbb47f2022-10-30 12:55:06 +01003623 cmd.use_shell = 1;
3624 strvec_push(&cmd.args, command_line);
3625 status = run_command(&cmd);
Johannes Schindelin311af522017-01-02 16:26:47 +01003626
3627 /* force re-reading of the cache */
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01003628 discard_index(r->index);
3629 if (repo_read_index(r) < 0)
Johannes Schindelin311af522017-01-02 16:26:47 +01003630 return error(_("could not read index"));
3631
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003632 dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1);
Johannes Schindelin311af522017-01-02 16:26:47 +01003633
3634 if (status) {
3635 warning(_("execution failed: %s\n%s"
3636 "You can fix the problem, and then run\n"
3637 "\n"
3638 " git rebase --continue\n"
3639 "\n"),
3640 command_line,
Oswald Buddenhagend45cbe32023-04-28 14:56:48 +02003641 dirty ? _("and made changes to the index and/or the "
Oswald Buddenhagenb734fe42023-04-28 14:56:49 +02003642 "working tree.\n") : "");
Johannes Schindelin311af522017-01-02 16:26:47 +01003643 if (status == 127)
3644 /* command not found */
3645 status = 1;
3646 } else if (dirty) {
3647 warning(_("execution succeeded: %s\nbut "
Oswald Buddenhagenb734fe42023-04-28 14:56:49 +02003648 "left changes to the index and/or the working tree.\n"
Johannes Schindelin311af522017-01-02 16:26:47 +01003649 "Commit or stash your changes, and then run\n"
3650 "\n"
3651 " git rebase --continue\n"
3652 "\n"), command_line);
3653 status = 1;
3654 }
3655
3656 return status;
3657}
3658
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +02003659__attribute__((format (printf, 2, 3)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02003660static int safe_append(const char *filename, const char *fmt, ...)
3661{
3662 va_list ap;
3663 struct lock_file lock = LOCK_INIT;
3664 int fd = hold_lock_file_for_update(&lock, filename,
3665 LOCK_REPORT_ON_ERROR);
3666 struct strbuf buf = STRBUF_INIT;
3667
3668 if (fd < 0)
3669 return -1;
3670
3671 if (strbuf_read_file(&buf, filename, 0) < 0 && errno != ENOENT) {
3672 error_errno(_("could not read '%s'"), filename);
3673 rollback_lock_file(&lock);
3674 return -1;
3675 }
3676 strbuf_complete(&buf, '\n');
3677 va_start(ap, fmt);
3678 strbuf_vaddf(&buf, fmt, ap);
3679 va_end(ap);
3680
3681 if (write_in_full(fd, buf.buf, buf.len) < 0) {
3682 error_errno(_("could not write to '%s'"), filename);
3683 strbuf_release(&buf);
3684 rollback_lock_file(&lock);
3685 return -1;
3686 }
3687 if (commit_lock_file(&lock) < 0) {
3688 strbuf_release(&buf);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003689 return error(_("failed to finalize '%s'"), filename);
3690 }
3691
3692 strbuf_release(&buf);
3693 return 0;
3694}
3695
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003696static int do_label(struct repository *r, const char *name, int len)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003697{
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003698 struct ref_store *refs = get_main_ref_store(r);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003699 struct ref_transaction *transaction;
3700 struct strbuf ref_name = STRBUF_INIT, err = STRBUF_INIT;
3701 struct strbuf msg = STRBUF_INIT;
3702 int ret = 0;
3703 struct object_id head_oid;
3704
3705 if (len == 1 && *name == '#')
Nguyễn Thái Ngọc Duy02127c62018-07-21 09:49:38 +02003706 return error(_("illegal label name: '%.*s'"), len, name);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003707
3708 strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
Elijah Newrenc2417d32020-02-15 21:36:36 +00003709 strbuf_addf(&msg, "rebase (label) '%.*s'", len, name);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003710
Junio C Hamanoc6da34a2022-04-13 15:51:33 -07003711 transaction = ref_store_transaction_begin(refs, &err);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003712 if (!transaction) {
3713 error("%s", err.buf);
3714 ret = -1;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02003715 } else if (repo_get_oid(r, "HEAD", &head_oid)) {
Johannes Schindelin9055e402018-04-25 14:28:47 +02003716 error(_("could not read HEAD"));
3717 ret = -1;
3718 } else if (ref_transaction_update(transaction, ref_name.buf, &head_oid,
3719 NULL, 0, msg.buf, &err) < 0 ||
3720 ref_transaction_commit(transaction, &err)) {
3721 error("%s", err.buf);
3722 ret = -1;
3723 }
3724 ref_transaction_free(transaction);
3725 strbuf_release(&err);
3726 strbuf_release(&msg);
3727
3728 if (!ret)
3729 ret = safe_append(rebase_path_refs_to_delete(),
3730 "%s\n", ref_name.buf);
3731 strbuf_release(&ref_name);
3732
3733 return ret;
3734}
3735
Phillip Woodd188a602022-11-09 14:21:57 +00003736static const char *sequencer_reflog_action(struct replay_opts *opts)
3737{
3738 if (!opts->reflog_action) {
3739 opts->reflog_action = getenv(GIT_REFLOG_ACTION);
3740 opts->reflog_action =
3741 xstrdup(opts->reflog_action ? opts->reflog_action
3742 : action_name(opts));
3743 }
3744
3745 return opts->reflog_action;
3746}
3747
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +02003748__attribute__((format (printf, 3, 4)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02003749static const char *reflog_message(struct replay_opts *opts,
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003750 const char *sub_action, const char *fmt, ...)
3751{
3752 va_list ap;
3753 static struct strbuf buf = STRBUF_INIT;
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003754
3755 va_start(ap, fmt);
3756 strbuf_reset(&buf);
Phillip Woodd188a602022-11-09 14:21:57 +00003757 strbuf_addstr(&buf, sequencer_reflog_action(opts));
Ævar Arnfjörð Bjarmasond4ac3052021-07-10 10:47:28 +02003758 if (sub_action)
3759 strbuf_addf(&buf, " (%s)", sub_action);
3760 if (fmt) {
3761 strbuf_addstr(&buf, ": ");
3762 strbuf_vaddf(&buf, fmt, ap);
3763 }
3764 va_end(ap);
3765
3766 return buf.buf;
3767}
Johannes Schindelin9055e402018-04-25 14:28:47 +02003768
Phillip Wood688d82f2022-11-10 16:43:41 +00003769static struct commit *lookup_label(struct repository *r, const char *label,
3770 int len, struct strbuf *buf)
Phillip Wood82766b22022-11-10 16:43:40 +00003771{
3772 struct commit *commit;
Phillip Wood688d82f2022-11-10 16:43:41 +00003773 struct object_id oid;
Phillip Wood82766b22022-11-10 16:43:40 +00003774
3775 strbuf_reset(buf);
3776 strbuf_addf(buf, "refs/rewritten/%.*s", len, label);
Phillip Wood688d82f2022-11-10 16:43:41 +00003777 if (!read_ref(buf->buf, &oid)) {
3778 commit = lookup_commit_object(r, &oid);
3779 } else {
Phillip Wood82766b22022-11-10 16:43:40 +00003780 /* fall back to non-rewritten ref or commit */
3781 strbuf_splice(buf, 0, strlen("refs/rewritten/"), "", 0);
3782 commit = lookup_commit_reference_by_name(buf->buf);
3783 }
3784
3785 if (!commit)
3786 error(_("could not resolve '%s'"), buf->buf);
3787
3788 return commit;
3789}
3790
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003791static int do_reset(struct repository *r,
3792 const char *name, int len,
3793 struct replay_opts *opts)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003794{
3795 struct strbuf ref_name = STRBUF_INIT;
3796 struct object_id oid;
3797 struct lock_file lock = LOCK_INIT;
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003798 struct tree_desc desc = { 0 };
Johannes Schindelin9055e402018-04-25 14:28:47 +02003799 struct tree *tree;
Ævar Arnfjörð Bjarmason6e658542021-10-13 15:23:55 +02003800 struct unpack_trees_options unpack_tree_opts = { 0 };
Martin Ågren71571cd2018-10-30 09:09:37 +01003801 int ret = 0;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003802
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07003803 if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003804 return -1;
3805
Johannes Schindelinebddf392018-05-04 01:01:23 +02003806 if (len == 10 && !strncmp("[new root]", name, len)) {
3807 if (!opts->have_squash_onto) {
3808 const char *hex;
3809 if (commit_tree("", 0, the_hash_algo->empty_tree,
3810 NULL, &opts->squash_onto,
3811 NULL, NULL))
3812 return error(_("writing fake root commit"));
3813 opts->have_squash_onto = 1;
3814 hex = oid_to_hex(&opts->squash_onto);
3815 if (write_message(hex, strlen(hex),
3816 rebase_path_squash_onto(), 0))
3817 return error(_("writing squash-onto"));
3818 }
3819 oidcpy(&oid, &opts->squash_onto);
3820 } else {
Martin Ågren71571cd2018-10-30 09:09:37 +01003821 int i;
Phillip Wood82766b22022-11-10 16:43:40 +00003822 struct commit *commit;
Martin Ågren71571cd2018-10-30 09:09:37 +01003823
Johannes Schindelinebddf392018-05-04 01:01:23 +02003824 /* Determine the length of the label */
3825 for (i = 0; i < len; i++)
3826 if (isspace(name[i]))
Martin Ågren71571cd2018-10-30 09:09:37 +01003827 break;
3828 len = i;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003829
Phillip Wood688d82f2022-11-10 16:43:41 +00003830 commit = lookup_label(r, name, len, &ref_name);
Phillip Wood82766b22022-11-10 16:43:40 +00003831 if (!commit) {
3832 ret = -1;
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003833 goto cleanup;
Johannes Schindelinebddf392018-05-04 01:01:23 +02003834 }
Phillip Wood82766b22022-11-10 16:43:40 +00003835 oid = commit->object.oid;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003836 }
3837
Johannes Schindelin9055e402018-04-25 14:28:47 +02003838 setup_unpack_trees_porcelain(&unpack_tree_opts, "reset");
3839 unpack_tree_opts.head_idx = 1;
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003840 unpack_tree_opts.src_index = r->index;
3841 unpack_tree_opts.dst_index = r->index;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003842 unpack_tree_opts.fn = oneway_merge;
3843 unpack_tree_opts.merge = 1;
3844 unpack_tree_opts.update = 1;
Elijah Newren1b5f3732021-09-27 16:33:43 +00003845 unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
Victoria Dye652bd022022-11-10 19:06:05 +00003846 unpack_tree_opts.skip_cache_tree_update = 1;
brian m. carlson3f267852020-03-16 18:05:06 +00003847 init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003848
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07003849 if (repo_read_index_unmerged(r)) {
Michael J Gruber1c8dfc32022-08-18 15:13:27 +02003850 ret = error_resolve_conflict(action_name(opts));
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003851 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003852 }
3853
Nguyễn Thái Ngọc Duy5e575802019-06-27 16:28:48 +07003854 if (!fill_tree_descriptor(r, &desc, &oid)) {
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003855 ret = error(_("failed to find tree of %s"), oid_to_hex(&oid));
3856 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003857 }
3858
3859 if (unpack_trees(1, &desc, &unpack_tree_opts)) {
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003860 ret = -1;
3861 goto cleanup;
Johannes Schindelin9055e402018-04-25 14:28:47 +02003862 }
3863
3864 tree = parse_tree_indirect(&oid);
Nguyễn Thái Ngọc Duyc207e9e2018-11-10 06:49:02 +01003865 prime_cache_tree(r, r->index, tree);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003866
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003867 if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
Johannes Schindelin9055e402018-04-25 14:28:47 +02003868 ret = error(_("could not write index"));
Johannes Schindelin9055e402018-04-25 14:28:47 +02003869
3870 if (!ret)
3871 ret = update_ref(reflog_message(opts, "reset", "'%.*s'",
3872 len, name), "HEAD", &oid,
3873 NULL, 0, UPDATE_REFS_MSG_ON_ERR);
Ævar Arnfjörð Bjarmason0c52cf82021-10-13 15:23:54 +02003874cleanup:
3875 free((void *)desc.buffer);
3876 if (ret < 0)
3877 rollback_lock_file(&lock);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003878 strbuf_release(&ref_name);
Ævar Arnfjörð Bjarmason6e658542021-10-13 15:23:55 +02003879 clear_unpack_trees_porcelain(&unpack_tree_opts);
Johannes Schindelin9055e402018-04-25 14:28:47 +02003880 return ret;
3881}
3882
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003883static int do_merge(struct repository *r,
3884 struct commit *commit,
3885 const char *arg, int arg_len,
Phillip Wood2be6b6f2021-08-20 15:40:35 +00003886 int flags, int *check_todo, struct replay_opts *opts)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003887{
Phillip Wood2be6b6f2021-08-20 15:40:35 +00003888 int run_commit_flags = 0;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003889 struct strbuf ref_name = STRBUF_INIT;
3890 struct commit *head_commit, *merge_commit, *i;
Jayati Shrivastava5327d892022-03-16 11:20:23 +00003891 struct commit_list *bases, *j;
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003892 struct commit_list *to_merge = NULL, **tail = &to_merge;
Phillip Woodfb60b9f2023-04-10 10:08:28 +01003893 const char *strategy = !opts->xopts.nr &&
Elijah Newren14c45862020-11-02 23:45:34 +00003894 (!opts->strategy ||
3895 !strcmp(opts->strategy, "recursive") ||
3896 !strcmp(opts->strategy, "ort")) ?
Johannes Schindeline145d992019-07-31 08:18:47 -07003897 NULL : opts->strategy;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003898 struct merge_options o;
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003899 int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003900 static struct lock_file lock;
3901 const char *p;
3902
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +07003903 if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003904 ret = -1;
3905 goto leave_merge;
3906 }
3907
3908 head_commit = lookup_commit_reference_by_name("HEAD");
3909 if (!head_commit) {
3910 ret = error(_("cannot merge without a current revision"));
3911 goto leave_merge;
3912 }
3913
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003914 /*
3915 * For octopus merges, the arg starts with the list of revisions to be
3916 * merged. The list is optionally followed by '#' and the oneline.
3917 */
3918 merge_arg_len = oneline_offset = arg_len;
3919 for (p = arg; p - arg < arg_len; p += strspn(p, " \t\n")) {
3920 if (!*p)
3921 break;
3922 if (*p == '#' && (!p[1] || isspace(p[1]))) {
3923 p += 1 + strspn(p + 1, " \t\n");
3924 oneline_offset = p - arg;
3925 break;
3926 }
3927 k = strcspn(p, " \t\n");
3928 if (!k)
3929 continue;
Phillip Wood688d82f2022-11-10 16:43:41 +00003930 merge_commit = lookup_label(r, p, k, &ref_name);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003931 if (!merge_commit) {
3932 ret = error(_("unable to parse '%.*s'"), k, p);
3933 goto leave_merge;
3934 }
3935 tail = &commit_list_insert(merge_commit, tail)->next;
3936 p += k;
3937 merge_arg_len = p - arg;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003938 }
3939
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003940 if (!to_merge) {
3941 ret = error(_("nothing to merge: '%.*s'"), arg_len, arg);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02003942 goto leave_merge;
3943 }
3944
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02003945 if (opts->have_squash_onto &&
Jeff King4a7e27e2018-08-28 17:22:40 -04003946 oideq(&head_commit->object.oid, &opts->squash_onto)) {
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02003947 /*
3948 * When the user tells us to "merge" something into a
3949 * "[new root]", let's simply fast-forward to the merge head.
3950 */
3951 rollback_lock_file(&lock);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003952 if (to_merge->next)
3953 ret = error(_("octopus merge cannot be executed on "
3954 "top of a [new root]"));
3955 else
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01003956 ret = fast_forward_to(r, &to_merge->item->object.oid,
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01003957 &head_commit->object.oid, 0,
3958 opts);
Johannes Schindelin9c85a1c2018-05-04 01:01:28 +02003959 goto leave_merge;
3960 }
3961
Phillip Woodbaf8ec82021-08-20 15:40:37 +00003962 /*
3963 * If HEAD is not identical to the first parent of the original merge
3964 * commit, we cannot fast-forward.
3965 */
3966 can_fast_forward = opts->allow_ff && commit && commit->parents &&
3967 oideq(&commit->parents->item->object.oid,
3968 &head_commit->object.oid);
3969
3970 /*
3971 * If any merge head is different from the original one, we cannot
3972 * fast-forward.
3973 */
3974 if (can_fast_forward) {
3975 struct commit_list *p = commit->parents->next;
3976
3977 for (j = to_merge; j && p; j = j->next, p = p->next)
3978 if (!oideq(&j->item->object.oid,
3979 &p->item->object.oid)) {
3980 can_fast_forward = 0;
3981 break;
3982 }
3983 /*
3984 * If the number of merge heads differs from the original merge
3985 * commit, we cannot fast-forward.
3986 */
3987 if (j || p)
3988 can_fast_forward = 0;
3989 }
3990
3991 if (can_fast_forward) {
3992 rollback_lock_file(&lock);
3993 ret = fast_forward_to(r, &commit->object.oid,
3994 &head_commit->object.oid, 0, opts);
3995 if (flags & TODO_EDIT_MERGE_MSG)
3996 goto fast_forward_edit;
3997
3998 goto leave_merge;
3999 }
4000
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004001 if (commit) {
Doan Tran Cong Danh5772b0c2019-11-11 13:03:40 +07004002 const char *encoding = get_commit_output_encoding();
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004003 const char *message = repo_logmsg_reencode(r, commit, NULL,
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02004004 encoding);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004005 const char *body;
4006 int len;
4007
4008 if (!message) {
4009 ret = error(_("could not get commit message of '%s'"),
4010 oid_to_hex(&commit->object.oid));
4011 goto leave_merge;
4012 }
4013 write_author_script(message);
4014 find_commit_subject(message, &body);
4015 len = strlen(body);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004016 ret = write_message(body, len, git_path_merge_msg(r), 0);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004017 repo_unuse_commit_buffer(r, commit, message);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004018 if (ret) {
4019 error_errno(_("could not write '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004020 git_path_merge_msg(r));
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004021 goto leave_merge;
4022 }
4023 } else {
4024 struct strbuf buf = STRBUF_INIT;
4025 int len;
4026
4027 strbuf_addf(&buf, "author %s", git_author_info(0));
4028 write_author_script(buf.buf);
4029 strbuf_reset(&buf);
4030
4031 if (oneline_offset < arg_len) {
4032 p = arg + oneline_offset;
4033 len = arg_len - oneline_offset;
4034 } else {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004035 strbuf_addf(&buf, "Merge %s '%.*s'",
4036 to_merge->next ? "branches" : "branch",
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004037 merge_arg_len, arg);
4038 p = buf.buf;
4039 len = buf.len;
4040 }
4041
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004042 ret = write_message(p, len, git_path_merge_msg(r), 0);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004043 strbuf_release(&buf);
4044 if (ret) {
4045 error_errno(_("could not write '%s'"),
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004046 git_path_merge_msg(r));
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004047 goto leave_merge;
4048 }
4049 }
4050
Johannes Schindeline145d992019-07-31 08:18:47 -07004051 if (strategy || to_merge->next) {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004052 /* Octopus merge */
4053 struct child_process cmd = CHILD_PROCESS_INIT;
4054
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004055 if (read_env_script(&cmd.env)) {
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004056 const char *gpg_opt = gpg_sign_opt_quoted(opts);
4057
4058 ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
4059 goto leave_merge;
4060 }
4061
Phillip Wood7573cec2020-08-17 18:40:02 +01004062 if (opts->committer_date_is_author_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004063 strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
Junio C Hamano9c31b192020-09-03 12:37:01 -07004064 opts->ignore_date ?
4065 "" :
Ævar Arnfjörð Bjarmasonb3193252022-06-02 11:09:51 +02004066 author_date_from_env(&cmd.env));
Phillip Wooda3894aa2020-08-17 18:40:03 +01004067 if (opts->ignore_date)
Ævar Arnfjörð Bjarmason29fda242022-06-02 11:09:50 +02004068 strvec_push(&cmd.env, "GIT_AUTHOR_DATE=");
Phillip Wood7573cec2020-08-17 18:40:02 +01004069
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004070 cmd.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004071 strvec_push(&cmd.args, "merge");
4072 strvec_push(&cmd.args, "-s");
Johannes Schindeline145d992019-07-31 08:18:47 -07004073 if (!strategy)
Jeff Kingc972bf42020-07-28 16:25:12 -04004074 strvec_push(&cmd.args, "octopus");
Johannes Schindeline145d992019-07-31 08:18:47 -07004075 else {
Jeff Kingc972bf42020-07-28 16:25:12 -04004076 strvec_push(&cmd.args, strategy);
Phillip Woodfb60b9f2023-04-10 10:08:28 +01004077 for (k = 0; k < opts->xopts.nr; k++)
Jeff Kingc972bf42020-07-28 16:25:12 -04004078 strvec_pushf(&cmd.args,
Phillip Woodfb60b9f2023-04-10 10:08:28 +01004079 "-X%s", opts->xopts.v[k]);
Johannes Schindeline145d992019-07-31 08:18:47 -07004080 }
Phillip Woodf2563c92021-08-20 15:40:38 +00004081 if (!(flags & TODO_EDIT_MERGE_MSG))
4082 strvec_push(&cmd.args, "--no-edit");
4083 else
4084 strvec_push(&cmd.args, "--edit");
Jeff Kingc972bf42020-07-28 16:25:12 -04004085 strvec_push(&cmd.args, "--no-ff");
4086 strvec_push(&cmd.args, "--no-log");
4087 strvec_push(&cmd.args, "--no-stat");
4088 strvec_push(&cmd.args, "-F");
4089 strvec_push(&cmd.args, git_path_merge_msg(r));
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004090 if (opts->gpg_sign)
Samuel Čavojae03c972020-10-18 01:15:55 +02004091 strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
Samuel Čavoj19dad042020-10-18 01:15:56 +02004092 else
4093 strvec_push(&cmd.args, "--no-gpg-sign");
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004094
4095 /* Add the tips to be merged */
4096 for (j = to_merge; j; j = j->next)
Jeff Kingc972bf42020-07-28 16:25:12 -04004097 strvec_push(&cmd.args,
Jeff Kingf6d89422020-07-28 16:26:31 -04004098 oid_to_hex(&j->item->object.oid));
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004099
4100 strbuf_release(&ref_name);
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00004101 refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
4102 NULL, 0);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004103 rollback_lock_file(&lock);
4104
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004105 ret = run_command(&cmd);
4106
4107 /* force re-reading of the cache */
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01004108 if (!ret) {
4109 discard_index(r->index);
4110 if (repo_read_index(r) < 0)
4111 ret = error(_("could not read index"));
4112 }
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004113 goto leave_merge;
4114 }
4115
4116 merge_commit = to_merge->item;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004117 bases = repo_get_merge_bases(r, head_commit, merge_commit);
Jeff King4a7e27e2018-08-28 17:22:40 -04004118 if (bases && oideq(&merge_commit->object.oid,
4119 &bases->item->object.oid)) {
Johannes Schindelin7ccdf652018-04-25 14:29:31 +02004120 ret = 0;
4121 /* skip merging an ancestor of HEAD */
4122 goto leave_merge;
4123 }
4124
brian m. carlson4439c7a2019-08-18 20:04:16 +00004125 write_message(oid_to_hex(&merge_commit->object.oid), the_hash_algo->hexsz,
Junio C Hamanocde55542019-01-04 13:33:33 -08004126 git_path_merge_head(r), 0);
4127 write_message("no-ff", 5, git_path_merge_mode(r), 0);
Johannes Schindelin85f8d9d2018-11-12 15:25:58 -08004128
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004129 bases = reverse_commit_list(bases);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004130
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07004131 repo_read_index(r);
Nguyễn Thái Ngọc Duy0d6caa22019-01-12 09:13:29 +07004132 init_merge_options(&o, r);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004133 o.branch1 = "HEAD";
4134 o.branch2 = ref_name.buf;
4135 o.buffer_output = 2;
4136
Elijah Newren6a5fb962021-08-04 05:38:01 +00004137 if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
Elijah Newren14c45862020-11-02 23:45:34 +00004138 /*
4139 * TODO: Should use merge_incore_recursive() and
4140 * merge_switch_to_result(), skipping the call to
4141 * merge_switch_to_result() when we don't actually need to
4142 * update the index and working copy immediately.
4143 */
4144 ret = merge_ort_recursive(&o,
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004145 head_commit, merge_commit, bases,
Elijah Newren14c45862020-11-02 23:45:34 +00004146 &i);
4147 } else {
Jayati Shrivastava5327d892022-03-16 11:20:23 +00004148 ret = merge_recursive(&o, head_commit, merge_commit, bases,
Elijah Newren14c45862020-11-02 23:45:34 +00004149 &i);
4150 }
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004151 if (ret <= 0)
4152 fputs(o.obuf.buf, stdout);
4153 strbuf_release(&o.obuf);
4154 if (ret < 0) {
4155 error(_("could not even attempt to merge '%.*s'"),
4156 merge_arg_len, arg);
4157 goto leave_merge;
4158 }
4159 /*
4160 * The return value of merge_recursive() is 1 on clean, and 0 on
4161 * unclean merge.
4162 *
4163 * Let's reverse that, so that do_merge() returns 0 upon success and
4164 * 1 upon failed merge (keeping the return value -1 for the cases where
4165 * we will want to reschedule the `merge` command).
4166 */
4167 ret = !ret;
4168
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004169 if (r->index->cache_changed &&
4170 write_locked_index(r->index, &lock, COMMIT_LOCK)) {
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004171 ret = error(_("merge: Unable to write new index file"));
4172 goto leave_merge;
4173 }
4174
4175 rollback_lock_file(&lock);
4176 if (ret)
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004177 repo_rerere(r, opts->allow_rerere_auto);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004178 else
4179 /*
4180 * In case of problems, we now want to return a positive
4181 * value (a negative one would indicate that the `merge`
4182 * command needs to be rescheduled).
4183 */
Jeff King20f4b042020-09-30 08:29:31 -04004184 ret = !!run_git_commit(git_path_merge_msg(r), opts,
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004185 run_commit_flags);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004186
Phillip Wood2be6b6f2021-08-20 15:40:35 +00004187 if (!ret && flags & TODO_EDIT_MERGE_MSG) {
4188 fast_forward_edit:
4189 *check_todo = 1;
4190 run_commit_flags |= AMEND_MSG | EDIT_MSG | VERIFY_MSG;
4191 ret = !!run_git_commit(NULL, opts, run_commit_flags);
4192 }
4193
4194
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004195leave_merge:
4196 strbuf_release(&ref_name);
4197 rollback_lock_file(&lock);
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01004198 free_commit_list(to_merge);
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004199 return ret;
4200}
4201
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004202static int write_update_refs_state(struct string_list *refs_to_oids)
Derrick Stoleea97d7912022-07-19 18:33:38 +00004203{
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004204 int result = 0;
4205 struct lock_file lock = LOCK_INIT;
4206 FILE *fp = NULL;
4207 struct string_list_item *item;
4208 char *path;
4209
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004210 path = rebase_path_update_refs(the_repository->gitdir);
4211
Victoria Dye44da9e02022-11-07 09:47:52 -08004212 if (!refs_to_oids->nr) {
4213 if (unlink(path) && errno != ENOENT)
4214 result = error_errno(_("could not unlink: %s"), path);
4215 goto cleanup;
4216 }
4217
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004218 if (safe_create_leading_directories(path)) {
4219 result = error(_("unable to create leading directories of %s"),
4220 path);
4221 goto cleanup;
4222 }
4223
4224 if (hold_lock_file_for_update(&lock, path, 0) < 0) {
4225 result = error(_("another 'rebase' process appears to be running; "
4226 "'%s.lock' already exists"),
4227 path);
4228 goto cleanup;
4229 }
4230
4231 fp = fdopen_lock_file(&lock, "w");
4232 if (!fp) {
4233 result = error_errno(_("could not open '%s' for writing"), path);
4234 rollback_lock_file(&lock);
4235 goto cleanup;
4236 }
4237
4238 for_each_string_list_item(item, refs_to_oids) {
4239 struct update_ref_record *rec = item->util;
4240 fprintf(fp, "%s\n%s\n%s\n", item->string,
4241 oid_to_hex(&rec->before), oid_to_hex(&rec->after));
4242 }
4243
4244 result = commit_lock_file(&lock);
4245
4246cleanup:
4247 free(path);
4248 return result;
4249}
4250
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004251/*
4252 * Parse the update-refs file for the current rebase, then remove the
4253 * refs that do not appear in the todo_list (and have not had updated
4254 * values stored) and add refs that are in the todo_list but not
4255 * represented in the update-refs file.
4256 *
4257 * If there are changes to the update-refs list, then write the new state
4258 * to disk.
4259 */
4260void todo_list_filter_update_refs(struct repository *r,
4261 struct todo_list *todo_list)
4262{
4263 int i;
4264 int updated = 0;
4265 struct string_list update_refs = STRING_LIST_INIT_DUP;
4266
4267 sequencer_get_update_refs_state(r->gitdir, &update_refs);
4268
4269 /*
4270 * For each item in the update_refs list, if it has no updated
4271 * value and does not appear in the todo_list, then remove it
4272 * from the update_refs list.
4273 */
4274 for (i = 0; i < update_refs.nr; i++) {
4275 int j;
4276 int found = 0;
4277 const char *ref = update_refs.items[i].string;
4278 size_t reflen = strlen(ref);
4279 struct update_ref_record *rec = update_refs.items[i].util;
4280
4281 /* OID already stored as updated. */
4282 if (!is_null_oid(&rec->after))
4283 continue;
4284
Johannes Schindelinfa5103d2023-05-13 08:11:25 +00004285 for (j = 0; !found && j < todo_list->nr; j++) {
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004286 struct todo_item *item = &todo_list->items[j];
4287 const char *arg = todo_list->buf.buf + item->arg_offset;
4288
4289 if (item->command != TODO_UPDATE_REF)
4290 continue;
4291
4292 if (item->arg_len != reflen ||
4293 strncmp(arg, ref, reflen))
4294 continue;
4295
4296 found = 1;
4297 }
4298
4299 if (!found) {
4300 free(update_refs.items[i].string);
4301 free(update_refs.items[i].util);
4302
4303 update_refs.nr--;
4304 MOVE_ARRAY(update_refs.items + i, update_refs.items + i + 1, update_refs.nr - i);
4305
4306 updated = 1;
4307 i--;
4308 }
4309 }
4310
4311 /*
4312 * For each todo_item, check if its ref is in the update_refs list.
4313 * If not, then add it as an un-updated ref.
4314 */
Johannes Schindelinfa5103d2023-05-13 08:11:25 +00004315 for (i = 0; i < todo_list->nr; i++) {
Derrick Stoleeb3b1a212022-07-19 18:33:41 +00004316 struct todo_item *item = &todo_list->items[i];
4317 const char *arg = todo_list->buf.buf + item->arg_offset;
4318 int j, found = 0;
4319
4320 if (item->command != TODO_UPDATE_REF)
4321 continue;
4322
4323 for (j = 0; !found && j < update_refs.nr; j++) {
4324 const char *ref = update_refs.items[j].string;
4325
4326 found = strlen(ref) == item->arg_len &&
4327 !strncmp(ref, arg, item->arg_len);
4328 }
4329
4330 if (!found) {
4331 struct string_list_item *inserted;
4332 struct strbuf argref = STRBUF_INIT;
4333
4334 strbuf_add(&argref, arg, item->arg_len);
4335 inserted = string_list_insert(&update_refs, argref.buf);
4336 inserted->util = init_update_ref_record(argref.buf);
4337 strbuf_release(&argref);
4338 updated = 1;
4339 }
4340 }
4341
4342 if (updated)
4343 write_update_refs_state(&update_refs);
4344 string_list_clear(&update_refs, 1);
4345}
4346
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004347static int do_update_ref(struct repository *r, const char *refname)
4348{
4349 struct string_list_item *item;
4350 struct string_list list = STRING_LIST_INIT_DUP;
4351
4352 if (sequencer_get_update_refs_state(r->gitdir, &list))
4353 return -1;
4354
4355 for_each_string_list_item(item, &list) {
4356 if (!strcmp(item->string, refname)) {
4357 struct update_ref_record *rec = item->util;
4358 if (read_ref("HEAD", &rec->after))
4359 return -1;
4360 break;
4361 }
4362 }
4363
4364 write_update_refs_state(&list);
4365 string_list_clear(&list, 1);
Derrick Stoleea97d7912022-07-19 18:33:38 +00004366 return 0;
4367}
4368
Derrick Stolee46118842022-07-19 18:33:44 +00004369static int do_update_refs(struct repository *r, int quiet)
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004370{
4371 int res = 0;
4372 struct string_list_item *item;
4373 struct string_list refs_to_oids = STRING_LIST_INIT_DUP;
4374 struct ref_store *refs = get_main_ref_store(r);
Derrick Stolee46118842022-07-19 18:33:44 +00004375 struct strbuf update_msg = STRBUF_INIT;
4376 struct strbuf error_msg = STRBUF_INIT;
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004377
4378 if ((res = sequencer_get_update_refs_state(r->gitdir, &refs_to_oids)))
4379 return res;
4380
4381 for_each_string_list_item(item, &refs_to_oids) {
4382 struct update_ref_record *rec = item->util;
Derrick Stolee46118842022-07-19 18:33:44 +00004383 int loop_res;
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004384
Derrick Stolee46118842022-07-19 18:33:44 +00004385 loop_res = refs_update_ref(refs, "rewritten during rebase",
4386 item->string,
4387 &rec->after, &rec->before,
4388 0, UPDATE_REFS_MSG_ON_ERR);
4389 res |= loop_res;
4390
4391 if (quiet)
4392 continue;
4393
4394 if (loop_res)
4395 strbuf_addf(&error_msg, "\t%s\n", item->string);
4396 else
4397 strbuf_addf(&update_msg, "\t%s\n", item->string);
4398 }
4399
4400 if (!quiet &&
4401 (update_msg.len || error_msg.len)) {
4402 fprintf(stderr,
4403 _("Updated the following refs with %s:\n%s"),
4404 "--update-refs",
4405 update_msg.buf);
4406
4407 if (res)
4408 fprintf(stderr,
4409 _("Failed to update the following refs with %s:\n%s"),
4410 "--update-refs",
4411 error_msg.buf);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004412 }
4413
4414 string_list_clear(&refs_to_oids, 1);
Derrick Stolee46118842022-07-19 18:33:44 +00004415 strbuf_release(&update_msg);
4416 strbuf_release(&error_msg);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004417 return res;
4418}
4419
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004420static int is_final_fixup(struct todo_list *todo_list)
4421{
4422 int i = todo_list->current;
4423
4424 if (!is_fixup(todo_list->items[i].command))
4425 return 0;
4426
4427 while (++i < todo_list->nr)
4428 if (is_fixup(todo_list->items[i].command))
4429 return 0;
4430 else if (!is_noop(todo_list->items[i].command))
4431 break;
4432 return 1;
4433}
4434
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004435static enum todo_command peek_command(struct todo_list *todo_list, int offset)
4436{
4437 int i;
4438
4439 for (i = todo_list->current + offset; i < todo_list->nr; i++)
4440 if (!is_noop(todo_list->items[i].command))
4441 return todo_list->items[i].command;
4442
4443 return -1;
4444}
4445
Phillip Woodb7de1532022-01-26 13:05:44 +00004446void create_autostash(struct repository *r, const char *path)
Johannes Schindelin796c7972017-01-02 16:28:27 +01004447{
Denton Liu0816f1d2020-04-07 10:28:03 -04004448 struct strbuf buf = STRBUF_INIT;
4449 struct lock_file lock_file = LOCK_INIT;
4450 int fd;
4451
4452 fd = repo_hold_locked_index(r, &lock_file, 0);
4453 refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
4454 if (0 <= fd)
4455 repo_update_index_if_able(r, &lock_file);
4456 rollback_lock_file(&lock_file);
4457
4458 if (has_unstaged_changes(r, 1) ||
4459 has_uncommitted_changes(r, 1)) {
4460 struct child_process stash = CHILD_PROCESS_INIT;
Phillip Wood6ae80862022-01-26 13:05:46 +00004461 struct reset_head_opts ropts = { .flags = RESET_HEAD_HARD };
Denton Liu0816f1d2020-04-07 10:28:03 -04004462 struct object_id oid;
4463
Jeff Kingc972bf42020-07-28 16:25:12 -04004464 strvec_pushl(&stash.args,
Jeff Kingf6d89422020-07-28 16:26:31 -04004465 "stash", "create", "autostash", NULL);
Denton Liu0816f1d2020-04-07 10:28:03 -04004466 stash.git_cmd = 1;
4467 stash.no_stdin = 1;
4468 strbuf_reset(&buf);
4469 if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
4470 die(_("Cannot autostash"));
4471 strbuf_trim_trailing_newline(&buf);
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004472 if (repo_get_oid(r, buf.buf, &oid))
Denton Liu0816f1d2020-04-07 10:28:03 -04004473 die(_("Unexpected stash response: '%s'"),
4474 buf.buf);
4475 strbuf_reset(&buf);
4476 strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
4477
4478 if (safe_create_leading_directories_const(path))
4479 die(_("Could not create directory for '%s'"),
4480 path);
4481 write_file(path, "%s", oid_to_hex(&oid));
4482 printf(_("Created autostash: %s\n"), buf.buf);
Phillip Wood6ae80862022-01-26 13:05:46 +00004483 if (reset_head(r, &ropts) < 0)
Denton Liu0816f1d2020-04-07 10:28:03 -04004484 die(_("could not reset --hard"));
Ævar Arnfjörð Bjarmason9c5f3ee2022-11-19 14:07:31 +01004485 discard_index(r->index);
4486 if (repo_read_index(r) < 0)
Denton Liu0816f1d2020-04-07 10:28:03 -04004487 die(_("could not read index"));
4488 }
4489 strbuf_release(&buf);
4490}
4491
Denton Liu804fe312020-04-07 10:28:06 -04004492static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply)
Johannes Schindelin796c7972017-01-02 16:28:27 +01004493{
Johannes Schindelin796c7972017-01-02 16:28:27 +01004494 struct child_process child = CHILD_PROCESS_INIT;
4495 int ret = 0;
4496
Denton Liu12b6e132020-04-07 10:28:05 -04004497 if (attempt_apply) {
4498 child.git_cmd = 1;
4499 child.no_stdout = 1;
4500 child.no_stderr = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004501 strvec_push(&child.args, "stash");
4502 strvec_push(&child.args, "apply");
4503 strvec_push(&child.args, stash_oid);
Denton Liu12b6e132020-04-07 10:28:05 -04004504 ret = run_command(&child);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004505 }
Johannes Schindelin796c7972017-01-02 16:28:27 +01004506
Denton Liu12b6e132020-04-07 10:28:05 -04004507 if (attempt_apply && !ret)
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004508 fprintf(stderr, _("Applied autostash.\n"));
Johannes Schindelin796c7972017-01-02 16:28:27 +01004509 else {
4510 struct child_process store = CHILD_PROCESS_INIT;
4511
4512 store.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004513 strvec_push(&store.args, "stash");
4514 strvec_push(&store.args, "store");
4515 strvec_push(&store.args, "-m");
4516 strvec_push(&store.args, "autostash");
4517 strvec_push(&store.args, "-q");
4518 strvec_push(&store.args, stash_oid);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004519 if (run_command(&store))
Denton Liu804fe312020-04-07 10:28:06 -04004520 ret = error(_("cannot store %s"), stash_oid);
Johannes Schindelin796c7972017-01-02 16:28:27 +01004521 else
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004522 fprintf(stderr,
Denton Liu12b6e132020-04-07 10:28:05 -04004523 _("%s\n"
Johannes Schindelincdb866b2017-06-19 18:56:02 +01004524 "Your changes are safe in the stash.\n"
4525 "You can run \"git stash pop\" or"
Denton Liu12b6e132020-04-07 10:28:05 -04004526 " \"git stash drop\" at any time.\n"),
4527 attempt_apply ?
4528 _("Applying autostash resulted in conflicts.") :
4529 _("Autostash exists; creating a new stash entry."));
Johannes Schindelin796c7972017-01-02 16:28:27 +01004530 }
4531
Johannes Schindelin796c7972017-01-02 16:28:27 +01004532 return ret;
4533}
4534
Denton Liu804fe312020-04-07 10:28:06 -04004535static int apply_save_autostash(const char *path, int attempt_apply)
4536{
4537 struct strbuf stash_oid = STRBUF_INIT;
4538 int ret = 0;
4539
4540 if (!read_oneliner(&stash_oid, path,
4541 READ_ONELINER_SKIP_IF_EMPTY)) {
4542 strbuf_release(&stash_oid);
4543 return 0;
4544 }
4545 strbuf_trim(&stash_oid);
4546
4547 ret = apply_save_autostash_oid(stash_oid.buf, attempt_apply);
4548
Denton Liu0dd562e2020-04-07 10:28:04 -04004549 unlink(path);
Denton Liufacca7f2020-04-07 10:27:57 -04004550 strbuf_release(&stash_oid);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304551 return ret;
4552}
4553
Denton Liu12b6e132020-04-07 10:28:05 -04004554int save_autostash(const char *path)
4555{
4556 return apply_save_autostash(path, 0);
4557}
4558
4559int apply_autostash(const char *path)
4560{
4561 return apply_save_autostash(path, 1);
4562}
4563
Denton Liu804fe312020-04-07 10:28:06 -04004564int apply_autostash_oid(const char *stash_oid)
4565{
4566 return apply_save_autostash_oid(stash_oid, 1);
4567}
4568
Phillip Woodfc4a6732019-03-19 19:03:07 +00004569static int checkout_onto(struct repository *r, struct replay_opts *opts,
Phillip Wood7d3488e2019-04-17 15:30:39 +01004570 const char *onto_name, const struct object_id *onto,
Phillip Woodf3e27a02020-11-04 15:29:38 +00004571 const struct object_id *orig_head)
Alban Gruin4df66c42018-08-10 18:51:34 +02004572{
Phillip Wood38c541c2022-01-26 13:05:49 +00004573 struct reset_head_opts ropts = {
4574 .oid = onto,
4575 .orig_head = orig_head,
4576 .flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
4577 RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
4578 .head_msg = reflog_message(opts, "start", "checkout %s",
4579 onto_name),
Phillip Woodd188a602022-11-09 14:21:57 +00004580 .default_reflog_action = sequencer_reflog_action(opts)
Phillip Wood38c541c2022-01-26 13:05:49 +00004581 };
4582 if (reset_head(r, &ropts)) {
Denton Liube1bb602020-04-07 10:27:56 -04004583 apply_autostash(rebase_path_autostash());
Alban Gruin4df66c42018-08-10 18:51:34 +02004584 sequencer_remove_state(opts);
4585 return error(_("could not detach HEAD"));
4586 }
4587
Phillip Wood38c541c2022-01-26 13:05:49 +00004588 return 0;
Alban Gruin4df66c42018-08-10 18:51:34 +02004589}
4590
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004591static int stopped_at_head(struct repository *r)
Johannes Schindelin71f82462018-10-12 06:14:26 -07004592{
4593 struct object_id head;
4594 struct commit *commit;
4595 struct commit_message message;
4596
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004597 if (repo_get_oid(r, "HEAD", &head) ||
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004598 !(commit = lookup_commit(r, &head)) ||
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004599 repo_parse_commit(r, commit) || get_message(commit, &message))
Johannes Schindelin71f82462018-10-12 06:14:26 -07004600 fprintf(stderr, _("Stopped at HEAD\n"));
4601 else {
4602 fprintf(stderr, _("Stopped at %s\n"), message.label);
4603 free_message(commit, &message);
4604 }
4605 return 0;
4606
4607}
4608
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004609static int reread_todo_if_changed(struct repository *r,
4610 struct todo_list *todo_list,
4611 struct replay_opts *opts)
4612{
Phillip Wood2b88fe02021-09-23 15:26:21 +00004613 int offset;
4614 struct strbuf buf = STRBUF_INIT;
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004615
Phillip Wood2b88fe02021-09-23 15:26:21 +00004616 if (strbuf_read_file_or_whine(&buf, get_todo_path(opts)) < 0)
4617 return -1;
4618 offset = get_item_line_offset(todo_list, todo_list->current + 1);
4619 if (buf.len != todo_list->buf.len - offset ||
4620 memcmp(buf.buf, todo_list->buf.buf + offset, buf.len)) {
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004621 /* Reread the todo file if it has changed. */
4622 todo_list_release(todo_list);
4623 if (read_populate_todo(r, todo_list, opts))
4624 return -1; /* message was printed */
4625 /* `current` will be incremented on return */
4626 todo_list->current = -1;
4627 }
Phillip Wood2b88fe02021-09-23 15:26:21 +00004628 strbuf_release(&buf);
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004629
4630 return 0;
4631}
4632
Johannes Schindelincb5206e2018-04-25 14:28:33 +02004633static const char rescheduled_advice[] =
4634N_("Could not execute the todo command\n"
4635"\n"
4636" %.*s"
4637"\n"
4638"It has been rescheduled; To edit the command before continuing, please\n"
4639"edit the todo list first:\n"
4640"\n"
4641" git rebase --edit-todo\n"
4642" git rebase --continue\n");
4643
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004644static int pick_commits(struct repository *r,
4645 struct todo_list *todo_list,
4646 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304647{
Johannes Schindelin9055e402018-04-25 14:28:47 +02004648 int res = 0, reschedule = 0;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304649
Phillip Woodd188a602022-11-09 14:21:57 +00004650 opts->reflog_message = sequencer_reflog_action(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304651 if (opts->allow_ff)
4652 assert(!(opts->signoff || opts->no_commit ||
Elijah Newren39edfd52021-03-31 06:52:20 +00004653 opts->record_origin || should_edit(opts) ||
Phillip Wooda3894aa2020-08-17 18:40:03 +01004654 opts->committer_date_is_author_date ||
4655 opts->ignore_date));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004656 if (read_and_refresh_cache(r, opts))
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02004657 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304658
Johannes Schindelin004fefa2016-10-21 14:24:41 +02004659 while (todo_list->current < todo_list->nr) {
4660 struct todo_item *item = todo_list->items + todo_list->current;
Alban Gruin6ad656d2019-01-29 16:01:46 +01004661 const char *arg = todo_item_get_arg(todo_list, item);
Phillip Wooda47ba3c2019-08-19 02:18:22 -07004662 int check_todo = 0;
Alban Gruin6ad656d2019-01-29 16:01:46 +01004663
Johannes Schindelin004fefa2016-10-21 14:24:41 +02004664 if (save_todo(todo_list, opts))
Johannes Schindelin221675d2016-09-09 16:37:50 +02004665 return -1;
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004666 if (is_rebase_i(opts)) {
Johannes Schindelinef800692017-01-02 16:36:20 +01004667 if (item->command != TODO_COMMENT) {
4668 FILE *f = fopen(rebase_path_msgnum(), "w");
4669
4670 todo_list->done_nr++;
4671
4672 if (f) {
4673 fprintf(f, "%d\n", todo_list->done_nr);
4674 fclose(f);
4675 }
Elijah Newren899b49c2018-12-11 08:11:36 -08004676 if (!opts->quiet)
Alban Gruin4d55d632020-03-28 14:05:15 +01004677 fprintf(stderr, _("Rebasing (%d/%d)%s"),
Elijah Newren899b49c2018-12-11 08:11:36 -08004678 todo_list->done_nr,
4679 todo_list->total_nr,
4680 opts->verbose ? "\n" : "\r");
Johannes Schindelinef800692017-01-02 16:36:20 +01004681 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004682 unlink(rebase_path_message());
4683 unlink(rebase_path_author_script());
4684 unlink(rebase_path_stopped_sha());
4685 unlink(rebase_path_amend());
Nguyễn Thái Ngọc Duy34e77712019-06-27 16:28:52 +07004686 unlink(git_path_merge_head(r));
Elijah Newren52918282021-03-20 00:03:52 +00004687 unlink(git_path_auto_merge(r));
Nguyễn Thái Ngọc Duyfbd7a232018-02-11 16:43:28 +07004688 delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
Johannes Schindelin71f82462018-10-12 06:14:26 -07004689
SZEDER Gábord7d90882019-06-27 15:42:48 +02004690 if (item->command == TODO_BREAK) {
4691 if (!opts->verbose)
4692 term_clear_line();
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01004693 return stopped_at_head(r);
SZEDER Gábord7d90882019-06-27 15:42:48 +02004694 }
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004695 }
4696 if (item->command <= TODO_SQUASH) {
Johannes Schindelin8ab37ef2017-01-02 16:28:13 +01004697 if (is_rebase_i(opts))
Phillip Woodd188a602022-11-09 14:21:57 +00004698 opts->reflog_message = reflog_message(opts,
4699 command_to_string(item->command), NULL);
4700
Charvi Mendirattaae70e342021-01-29 23:50:45 +05304701 res = do_pick_commit(r, item, opts,
4702 is_final_fixup(todo_list),
Phillip Wooda47ba3c2019-08-19 02:18:22 -07004703 &check_todo);
Johannes Schindelin9d7bf3c2017-01-02 16:28:34 +01004704 if (is_rebase_i(opts) && res < 0) {
4705 /* Reschedule */
Johannes Schindelincb5206e2018-04-25 14:28:33 +02004706 advise(_(rescheduled_advice),
4707 get_item_line_length(todo_list,
4708 todo_list->current),
4709 get_item_line(todo_list,
4710 todo_list->current));
Johannes Schindelin9d7bf3c2017-01-02 16:28:34 +01004711 todo_list->current--;
4712 if (save_todo(todo_list, opts))
4713 return -1;
4714 }
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004715 if (item->command == TODO_EDIT) {
4716 struct commit *commit = item->commit;
SZEDER Gábord7d90882019-06-27 15:42:48 +02004717 if (!res) {
4718 if (!opts->verbose)
4719 term_clear_line();
Jeff King99429212017-03-16 20:19:42 -04004720 fprintf(stderr,
Brandon Williamsa42e1b42017-03-23 10:02:33 -07004721 _("Stopped at %s... %.*s\n"),
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004722 short_commit_name(commit),
Alban Gruin6ad656d2019-01-29 16:01:46 +01004723 item->arg_len, arg);
SZEDER Gábord7d90882019-06-27 15:42:48 +02004724 }
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004725 return error_with_patch(r, commit,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004726 arg, item->arg_len, opts, res, !res);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004727 }
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004728 if (is_rebase_i(opts) && !res)
4729 record_in_rewritten(&item->commit->object.oid,
4730 peek_command(todo_list, 1));
Johannes Schindelin6e98de72017-01-02 16:27:07 +01004731 if (res && is_fixup(item->command)) {
4732 if (res == 1)
4733 intend_to_amend();
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004734 return error_failed_squash(r, item->commit, opts,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004735 item->arg_len, arg);
Phillip Wooda9279c62018-06-19 13:46:51 +01004736 } else if (res && is_rebase_i(opts) && item->commit) {
4737 int to_amend = 0;
4738 struct object_id oid;
4739
4740 /*
4741 * If we are rewording and have either
4742 * fast-forwarded already, or are about to
4743 * create a new root commit, we want to amend,
4744 * otherwise we do not.
4745 */
4746 if (item->command == TODO_REWORD &&
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004747 !repo_get_oid(r, "HEAD", &oid) &&
Jeff King4a7e27e2018-08-28 17:22:40 -04004748 (oideq(&item->commit->object.oid, &oid) ||
Phillip Wooda9279c62018-06-19 13:46:51 +01004749 (opts->have_squash_onto &&
Jeff King4a7e27e2018-08-28 17:22:40 -04004750 oideq(&opts->squash_onto, &oid))))
Phillip Wooda9279c62018-06-19 13:46:51 +01004751 to_amend = 1;
4752
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004753 return res | error_with_patch(r, item->commit,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004754 arg, item->arg_len, opts,
Phillip Wooda9279c62018-06-19 13:46:51 +01004755 res, to_amend);
4756 }
Johannes Schindelin311af522017-01-02 16:26:47 +01004757 } else if (item->command == TODO_EXEC) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004758 char *end_of_arg = (char *)(arg + item->arg_len);
Johannes Schindelin311af522017-01-02 16:26:47 +01004759 int saved = *end_of_arg;
4760
SZEDER Gábord7d90882019-06-27 15:42:48 +02004761 if (!opts->verbose)
4762 term_clear_line();
Johannes Schindelin311af522017-01-02 16:26:47 +01004763 *end_of_arg = '\0';
Alban Gruin6ad656d2019-01-29 16:01:46 +01004764 res = do_exec(r, arg);
Johannes Schindelin311af522017-01-02 16:26:47 +01004765 *end_of_arg = saved;
Stephen Hicks54fd3242017-04-26 21:17:40 +02004766
Johannes Schindelind421afa2018-12-10 11:04:58 -08004767 if (res) {
4768 if (opts->reschedule_failed_exec)
4769 reschedule = 1;
Stephen Hicks54fd3242017-04-26 21:17:40 +02004770 }
Phillip Wooda47ba3c2019-08-19 02:18:22 -07004771 check_todo = 1;
Johannes Schindelin9055e402018-04-25 14:28:47 +02004772 } else if (item->command == TODO_LABEL) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004773 if ((res = do_label(r, arg, item->arg_len)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02004774 reschedule = 1;
4775 } else if (item->command == TODO_RESET) {
Alban Gruin6ad656d2019-01-29 16:01:46 +01004776 if ((res = do_reset(r, arg, item->arg_len, opts)))
Johannes Schindelin9055e402018-04-25 14:28:47 +02004777 reschedule = 1;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004778 } else if (item->command == TODO_MERGE) {
Phillip Wood2be6b6f2021-08-20 15:40:35 +00004779 if ((res = do_merge(r, item->commit, arg, item->arg_len,
4780 item->flags, &check_todo, opts)) < 0)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004781 reschedule = 1;
Johannes Schindelin537e7d62018-04-25 14:29:29 +02004782 else if (item->commit)
4783 record_in_rewritten(&item->commit->object.oid,
4784 peek_command(todo_list, 1));
4785 if (res > 0)
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004786 /* failed with merge conflicts */
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004787 return error_with_patch(r, item->commit,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004788 arg, item->arg_len,
4789 opts, res, 0);
Derrick Stoleea97d7912022-07-19 18:33:38 +00004790 } else if (item->command == TODO_UPDATE_REF) {
4791 struct strbuf ref = STRBUF_INIT;
4792 strbuf_add(&ref, arg, item->arg_len);
4793 if ((res = do_update_ref(r, ref.buf)))
4794 reschedule = 1;
4795 strbuf_release(&ref);
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004796 } else if (!is_noop(item->command))
Johannes Schindelin25c43662017-01-02 16:26:38 +01004797 return error(_("unknown command %d"), item->command);
4798
Johannes Schindelin9055e402018-04-25 14:28:47 +02004799 if (reschedule) {
4800 advise(_(rescheduled_advice),
4801 get_item_line_length(todo_list,
4802 todo_list->current),
4803 get_item_line(todo_list, todo_list->current));
4804 todo_list->current--;
4805 if (save_todo(todo_list, opts))
4806 return -1;
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02004807 if (item->commit)
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004808 return error_with_patch(r,
4809 item->commit,
Alban Gruin6ad656d2019-01-29 16:01:46 +01004810 arg, item->arg_len,
4811 opts, res, 0);
Phillip Wooddfa8bae2021-09-23 15:26:20 +00004812 } else if (is_rebase_i(opts) && check_todo && !res &&
4813 reread_todo_if_changed(r, todo_list, opts)) {
4814 return -1;
Johannes Schindelin9055e402018-04-25 14:28:47 +02004815 }
4816
Johannes Schindelin004fefa2016-10-21 14:24:41 +02004817 todo_list->current++;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304818 if (res)
4819 return res;
4820 }
4821
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004822 if (is_rebase_i(opts)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004823 struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004824 struct stat st;
Johannes Schindelin556907f2017-01-02 16:26:53 +01004825
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004826 /* Stopped in the middle, as planned? */
4827 if (todo_list->current < todo_list->nr)
4828 return 0;
Johannes Schindelin556907f2017-01-02 16:26:53 +01004829
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004830 if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
4831 starts_with(head_ref.buf, "refs/")) {
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004832 const char *msg;
brian m. carlson092bbcd2017-07-13 23:49:22 +00004833 struct object_id head, orig;
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004834 int res;
4835
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004836 if (repo_get_oid(r, "HEAD", &head)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004837 res = error(_("cannot read HEAD"));
4838cleanup_head_ref:
4839 strbuf_release(&head_ref);
4840 strbuf_release(&buf);
4841 return res;
4842 }
4843 if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
brian m. carlson092bbcd2017-07-13 23:49:22 +00004844 get_oid_hex(buf.buf, &orig)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004845 res = error(_("could not read orig-head"));
4846 goto cleanup_head_ref;
4847 }
Phillip Wood4ab867b2017-05-18 11:02:32 +01004848 strbuf_reset(&buf);
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004849 if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
4850 res = error(_("could not read 'onto'"));
4851 goto cleanup_head_ref;
4852 }
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004853 msg = reflog_message(opts, "finish", "%s onto %s",
4854 head_ref.buf, buf.buf);
brian m. carlsonae077772017-10-15 22:06:51 +00004855 if (update_ref(msg, head_ref.buf, &head, &orig,
Michael Haggerty91774af2017-11-05 09:42:06 +01004856 REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004857 res = error(_("could not update %s"),
4858 head_ref.buf);
4859 goto cleanup_head_ref;
4860 }
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004861 msg = reflog_message(opts, "finish", "returning to %s",
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004862 head_ref.buf);
Johannes Schindelin96e832a2017-01-02 16:28:09 +01004863 if (create_symref("HEAD", head_ref.buf, msg)) {
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004864 res = error(_("could not update HEAD to %s"),
4865 head_ref.buf);
4866 goto cleanup_head_ref;
4867 }
4868 strbuf_reset(&buf);
4869 }
4870
Johannes Schindelin556907f2017-01-02 16:26:53 +01004871 if (opts->verbose) {
4872 struct rev_info log_tree_opt;
4873 struct object_id orig, head;
4874
4875 memset(&log_tree_opt, 0, sizeof(log_tree_opt));
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004876 repo_init_revisions(r, &log_tree_opt, NULL);
Johannes Schindelin556907f2017-01-02 16:26:53 +01004877 log_tree_opt.diff = 1;
4878 log_tree_opt.diffopt.output_format =
4879 DIFF_FORMAT_DIFFSTAT;
4880 log_tree_opt.disable_stdin = 1;
4881
4882 if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004883 !repo_get_oid(r, buf.buf, &orig) &&
4884 !repo_get_oid(r, "HEAD", &head)) {
Brandon Williams66f414f2017-05-30 10:31:03 -07004885 diff_tree_oid(&orig, &head, "",
4886 &log_tree_opt.diffopt);
Johannes Schindelin556907f2017-01-02 16:26:53 +01004887 log_tree_diff_flush(&log_tree_opt);
4888 }
Ævar Arnfjörð Bjarmason2108fe42022-04-13 22:01:36 +02004889 release_revisions(&log_tree_opt);
Johannes Schindelin556907f2017-01-02 16:26:53 +01004890 }
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004891 flush_rewritten_pending();
4892 if (!stat(rebase_path_rewritten_list(), &st) &&
4893 st.st_size > 0) {
4894 struct child_process child = CHILD_PROCESS_INIT;
Emily Shaffer96af5642023-02-08 20:21:14 +01004895 struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004896
4897 child.in = open(rebase_path_rewritten_list(), O_RDONLY);
4898 child.git_cmd = 1;
Jeff Kingc972bf42020-07-28 16:25:12 -04004899 strvec_push(&child.args, "notes");
4900 strvec_push(&child.args, "copy");
4901 strvec_push(&child.args, "--for-rewrite=rebase");
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004902 /* we don't care if this copying failed */
4903 run_command(&child);
Johannes Schindelin79516042017-01-02 16:28:23 +01004904
Emily Shaffer96af5642023-02-08 20:21:14 +01004905 hook_opt.path_to_stdin = rebase_path_rewritten_list();
4906 strvec_push(&hook_opt.args, "rebase");
4907 run_hooks_opt("post-rewrite", &hook_opt);
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004908 }
Denton Liube1bb602020-04-07 10:27:56 -04004909 apply_autostash(rebase_path_autostash());
Johannes Schindelin25cb8df2017-01-02 16:28:16 +01004910
SZEDER Gábord7d90882019-06-27 15:42:48 +02004911 if (!opts->quiet) {
4912 if (!opts->verbose)
4913 term_clear_line();
Elijah Newren899b49c2018-12-11 08:11:36 -08004914 fprintf(stderr,
Alban Gruin4d55d632020-03-28 14:05:15 +01004915 _("Successfully rebased and updated %s.\n"),
Elijah Newren899b49c2018-12-11 08:11:36 -08004916 head_ref.buf);
SZEDER Gábord7d90882019-06-27 15:42:48 +02004917 }
Johannes Schindelin5da49662017-01-02 16:36:25 +01004918
Johannes Schindelin556907f2017-01-02 16:26:53 +01004919 strbuf_release(&buf);
Johannes Schindelin4b83ce92017-01-02 16:27:53 +01004920 strbuf_release(&head_ref);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004921
Derrick Stolee46118842022-07-19 18:33:44 +00004922 if (do_update_refs(r, opts->quiet))
Derrick Stolee89fc0b52022-07-19 18:33:40 +00004923 return -1;
Johannes Schindelin56dc3ab2017-01-02 16:26:43 +01004924 }
4925
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304926 /*
4927 * Sequence of picks finished successfully; cleanup by
4928 * removing the .git/sequencer directory
4929 */
Johannes Schindelin28635842016-10-21 14:24:55 +02004930 return sequencer_remove_state(opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304931}
4932
Elijah Newren39edfd52021-03-31 06:52:20 +00004933static int continue_single_pick(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304934{
René Scharfe0e906732022-10-30 12:51:14 +01004935 struct child_process cmd = CHILD_PROCESS_INIT;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304936
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00004937 if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00004938 !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304939 return error(_("no cherry-pick or revert in progress"));
Elijah Newren39edfd52021-03-31 06:52:20 +00004940
René Scharfe0e906732022-10-30 12:51:14 +01004941 cmd.git_cmd = 1;
4942 strvec_push(&cmd.args, "commit");
Elijah Newren39edfd52021-03-31 06:52:20 +00004943
4944 /*
4945 * continue_single_pick() handles the case of recovering from a
4946 * conflict. should_edit() doesn't handle that case; for a conflict,
4947 * we want to edit if the user asked for it, or if they didn't specify
4948 * and stdin is a tty.
4949 */
4950 if (!opts->edit || (opts->edit < 0 && !isatty(0)))
4951 /*
4952 * Include --cleanup=strip as well because we don't want the
4953 * "# Conflicts:" messages.
4954 */
René Scharfe0e906732022-10-30 12:51:14 +01004955 strvec_pushl(&cmd.args, "--no-edit", "--cleanup=strip", NULL);
Elijah Newren39edfd52021-03-31 06:52:20 +00004956
René Scharfe0e906732022-10-30 12:51:14 +01004957 return run_command(&cmd);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05304958}
4959
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004960static int commit_staged_changes(struct repository *r,
4961 struct replay_opts *opts,
Johannes Schindelin15ef6932018-04-27 22:48:30 +02004962 struct todo_list *todo_list)
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004963{
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01004964 unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02004965 unsigned int final_fixup = 0, is_clean;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004966
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004967 if (has_unstaged_changes(r, 1))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004968 return error(_("cannot rebase: You have unstaged changes."));
Johannes Schindelin52632202017-01-02 16:27:25 +01004969
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01004970 is_clean = !has_uncommitted_changes(r, 0);
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004971
4972 if (file_exists(rebase_path_amend())) {
4973 struct strbuf rev = STRBUF_INIT;
brian m. carlson092bbcd2017-07-13 23:49:22 +00004974 struct object_id head, to_amend;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004975
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02004976 if (repo_get_oid(r, "HEAD", &head))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004977 return error(_("cannot amend non-existing commit"));
4978 if (!read_oneliner(&rev, rebase_path_amend(), 0))
4979 return error(_("invalid file: '%s'"), rebase_path_amend());
brian m. carlson092bbcd2017-07-13 23:49:22 +00004980 if (get_oid_hex(rev.buf, &to_amend))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004981 return error(_("invalid contents: '%s'"),
4982 rebase_path_amend());
Jeff King9001dc22018-08-28 17:22:48 -04004983 if (!is_clean && !oideq(&head, &to_amend))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01004984 return error(_("\nYou have uncommitted changes in your "
4985 "working tree. Please, commit them\n"
4986 "first and then run 'git rebase "
4987 "--continue' again."));
Johannes Schindelin15ef6932018-04-27 22:48:30 +02004988 /*
4989 * When skipping a failed fixup/squash, we need to edit the
4990 * commit message, the current fixup list and count, and if it
4991 * was the last fixup/squash in the chain, we need to clean up
4992 * the commit message and if there was a squash, let the user
4993 * edit it.
4994 */
Johannes Schindelin10d2f352018-08-31 16:45:04 -07004995 if (!is_clean || !opts->current_fixup_count)
4996 ; /* this is not the final fixup */
Junio C Hamano87ae8a12018-09-24 10:30:45 -07004997 else if (!oideq(&head, &to_amend) ||
Johannes Schindelin10d2f352018-08-31 16:45:04 -07004998 !file_exists(rebase_path_stopped_sha())) {
4999 /* was a final fixup or squash done manually? */
5000 if (!is_fixup(peek_command(todo_list, 0))) {
5001 unlink(rebase_path_fixup_msg());
5002 unlink(rebase_path_squash_msg());
5003 unlink(rebase_path_current_fixups());
5004 strbuf_reset(&opts->current_fixups);
5005 opts->current_fixup_count = 0;
5006 }
5007 } else {
5008 /* we are in a fixup/squash chain */
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005009 const char *p = opts->current_fixups.buf;
5010 int len = opts->current_fixups.len;
5011
5012 opts->current_fixup_count--;
5013 if (!len)
5014 BUG("Incorrect current_fixups:\n%s", p);
5015 while (len && p[len - 1] != '\n')
5016 len--;
5017 strbuf_setlen(&opts->current_fixups, len);
5018 if (write_message(p, len, rebase_path_current_fixups(),
5019 0) < 0)
5020 return error(_("could not write file: '%s'"),
5021 rebase_path_current_fixups());
5022
5023 /*
5024 * If a fixup/squash in a fixup/squash chain failed, the
5025 * commit message is already correct, no need to commit
5026 * it again.
5027 *
5028 * Only if it is the final command in the fixup/squash
5029 * chain, and only if the chain is longer than a single
5030 * fixup/squash command (which was just skipped), do we
5031 * actually need to re-commit with a cleaned up commit
5032 * message.
5033 */
5034 if (opts->current_fixup_count > 0 &&
5035 !is_fixup(peek_command(todo_list, 0))) {
5036 final_fixup = 1;
5037 /*
5038 * If there was not a single "squash" in the
5039 * chain, we only need to clean up the commit
5040 * message, no need to bother the user with
5041 * opening the commit message in the editor.
5042 */
5043 if (!starts_with(p, "squash ") &&
5044 !strstr(p, "\nsquash "))
5045 flags = (flags & ~EDIT_MSG) | CLEANUP_MSG;
5046 } else if (is_fixup(peek_command(todo_list, 0))) {
5047 /*
5048 * We need to update the squash message to skip
5049 * the latest commit message.
5050 */
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005051 int res = 0;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005052 struct commit *commit;
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005053 const char *msg;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005054 const char *path = rebase_path_squash_msg();
Doan Tran Cong Danhb3757442019-11-08 16:43:48 +07005055 const char *encoding = get_commit_output_encoding();
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005056
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005057 if (parse_head(r, &commit))
5058 return error(_("could not parse HEAD"));
5059
5060 p = repo_logmsg_reencode(r, commit, NULL, encoding);
5061 if (!p) {
5062 res = error(_("could not parse commit %s"),
5063 oid_to_hex(&commit->object.oid));
5064 goto unuse_commit_buffer;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005065 }
Phillip Wood6ce7afe2023-08-03 13:09:35 +00005066 find_commit_subject(p, &msg);
5067 if (write_message(msg, strlen(msg), path, 0)) {
5068 res = error(_("could not write file: "
5069 "'%s'"), path);
5070 goto unuse_commit_buffer;
5071 }
5072 unuse_commit_buffer:
5073 repo_unuse_commit_buffer(r, commit, p);
5074 if (res)
5075 return res;
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005076 }
5077 }
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005078
5079 strbuf_release(&rev);
Johannes Schindelin789b3ef2017-03-23 17:07:11 +01005080 flags |= AMEND_MSG;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005081 }
5082
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005083 if (is_clean) {
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00005084 if (refs_ref_exists(get_main_ref_store(r),
5085 "CHERRY_PICK_HEAD") &&
5086 refs_delete_ref(get_main_ref_store(r), "",
5087 "CHERRY_PICK_HEAD", NULL, 0))
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005088 return error(_("could not remove CHERRY_PICK_HEAD"));
Phillip Woode5ee33e2021-08-12 13:42:09 +00005089 if (unlink(git_path_merge_msg(r)) && errno != ENOENT)
5090 return error_errno(_("could not remove '%s'"),
5091 git_path_merge_msg(r));
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005092 if (!final_fixup)
5093 return 0;
5094 }
5095
Jeff King20f4b042020-09-30 08:29:31 -04005096 if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005097 opts, flags))
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005098 return error(_("could not commit staged changes."));
5099 unlink(rebase_path_amend());
Nguyễn Thái Ngọc Duy34e77712019-06-27 16:28:52 +07005100 unlink(git_path_merge_head(r));
Elijah Newren52918282021-03-20 00:03:52 +00005101 unlink(git_path_auto_merge(r));
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005102 if (final_fixup) {
5103 unlink(rebase_path_fixup_msg());
5104 unlink(rebase_path_squash_msg());
5105 }
5106 if (opts->current_fixup_count > 0) {
5107 /*
5108 * Whether final fixup or not, we just cleaned up the commit
5109 * message...
5110 */
5111 unlink(rebase_path_current_fixups());
5112 strbuf_reset(&opts->current_fixups);
5113 opts->current_fixup_count = 0;
5114 }
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005115 return 0;
5116}
5117
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005118int sequencer_continue(struct repository *r, struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305119{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005120 struct todo_list todo_list = TODO_LIST_INIT;
5121 int res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305122
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005123 if (read_and_refresh_cache(r, opts))
Johannes Schindelin28635842016-10-21 14:24:55 +02005124 return -1;
5125
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005126 if (read_populate_opts(opts))
5127 return -1;
Johannes Schindelin9d93ccd2017-01-02 16:27:21 +01005128 if (is_rebase_i(opts)) {
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01005129 if ((res = read_populate_todo(r, &todo_list, opts)))
Johannes Schindelin15ef6932018-04-27 22:48:30 +02005130 goto release_todo_list;
Alban Gruin5a5445d2020-01-28 22:12:46 +01005131
5132 if (file_exists(rebase_path_dropped())) {
5133 if ((res = todo_list_check_against_backup(r, &todo_list)))
5134 goto release_todo_list;
5135
5136 unlink(rebase_path_dropped());
5137 }
5138
Phillip Woodd188a602022-11-09 14:21:57 +00005139 opts->reflog_message = reflog_message(opts, "continue", NULL);
Alban Gruinf6b94132019-11-29 00:02:03 +01005140 if (commit_staged_changes(r, opts, &todo_list)) {
5141 res = -1;
5142 goto release_todo_list;
5143 }
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005144 } else if (!file_exists(get_todo_path(opts)))
Elijah Newren39edfd52021-03-31 06:52:20 +00005145 return continue_single_pick(r, opts);
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01005146 else if ((res = read_populate_todo(r, &todo_list, opts)))
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005147 goto release_todo_list;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305148
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005149 if (!is_rebase_i(opts)) {
5150 /* Verify that the conflict has been resolved */
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00005151 if (refs_ref_exists(get_main_ref_store(r),
5152 "CHERRY_PICK_HEAD") ||
Han-Wen Nienhuysb8825ef2020-08-21 16:59:37 +00005153 refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
Elijah Newren39edfd52021-03-31 06:52:20 +00005154 res = continue_single_pick(r, opts);
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005155 if (res)
5156 goto release_todo_list;
5157 }
Nguyễn Thái Ngọc Duyffc00a42018-11-10 06:49:04 +01005158 if (index_differs_from(r, "HEAD", NULL, 0)) {
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07005159 res = error_dirty_index(r, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005160 goto release_todo_list;
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005161 }
5162 todo_list.current++;
Johannes Schindelinca98c6d2017-01-02 16:28:20 +01005163 } else if (file_exists(rebase_path_stopped_sha())) {
5164 struct strbuf buf = STRBUF_INIT;
5165 struct object_id oid;
5166
Denton Liu3442c3d2020-04-07 10:27:52 -04005167 if (read_oneliner(&buf, rebase_path_stopped_sha(),
5168 READ_ONELINER_SKIP_IF_EMPTY) &&
Junio C Hamano0512eab2020-09-24 22:49:12 -07005169 !get_oid_hex(buf.buf, &oid))
Johannes Schindelinca98c6d2017-01-02 16:28:20 +01005170 record_in_rewritten(&oid, peek_command(&todo_list, 0));
5171 strbuf_release(&buf);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305172 }
Johannes Schindelin4258a6d2017-01-02 16:27:30 +01005173
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005174 res = pick_commits(r, &todo_list, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005175release_todo_list:
5176 todo_list_release(&todo_list);
5177 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305178}
5179
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005180static int single_pick(struct repository *r,
5181 struct commit *cmit,
5182 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305183{
Phillip Wooda47ba3c2019-08-19 02:18:22 -07005184 int check_todo;
Charvi Mendirattaae70e342021-01-29 23:50:45 +05305185 struct todo_item item;
5186
5187 item.command = opts->action == REPLAY_PICK ?
5188 TODO_PICK : TODO_REVERT;
5189 item.commit = cmit;
Phillip Wooda47ba3c2019-08-19 02:18:22 -07005190
Phillip Woodd188a602022-11-09 14:21:57 +00005191 opts->reflog_message = sequencer_reflog_action(opts);
Charvi Mendirattaae70e342021-01-29 23:50:45 +05305192 return do_pick_commit(r, &item, opts, 0, &check_todo);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305193}
5194
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005195int sequencer_pick_revisions(struct repository *r,
5196 struct replay_opts *opts)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305197{
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005198 struct todo_list todo_list = TODO_LIST_INIT;
brian m. carlson1e43ed92017-05-06 22:10:09 +00005199 struct object_id oid;
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005200 int i, res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305201
Johannes Schindelin28635842016-10-21 14:24:55 +02005202 assert(opts->revs);
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005203 if (read_and_refresh_cache(r, opts))
Johannes Schindelin0d9c6dc2016-09-09 16:37:21 +02005204 return -1;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305205
Miklos Vajna21246db2013-04-11 15:06:52 +02005206 for (i = 0; i < opts->revs->pending.nr; i++) {
brian m. carlson1e43ed92017-05-06 22:10:09 +00005207 struct object_id oid;
Miklos Vajna21246db2013-04-11 15:06:52 +02005208 const char *name = opts->revs->pending.objects[i].name;
5209
5210 /* This happens when using --stdin. */
5211 if (!strlen(name))
5212 continue;
5213
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005214 if (!repo_get_oid(r, name, &oid)) {
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005215 if (!lookup_commit_reference_gently(r, &oid, 1)) {
5216 enum object_type type = oid_object_info(r,
Stefan Beller0df8e962018-04-25 11:20:59 -07005217 &oid,
brian m. carlsonabef9022018-03-12 02:27:46 +00005218 NULL);
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005219 return error(_("%s: can't cherry-pick a %s"),
Brandon Williamsdebca9d2018-02-14 10:59:24 -08005220 name, type_name(type));
Junio C Hamano7c0b0d82013-05-09 13:27:49 -07005221 }
Miklos Vajna21246db2013-04-11 15:06:52 +02005222 } else
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005223 return error(_("%s: bad revision"), name);
Miklos Vajna21246db2013-04-11 15:06:52 +02005224 }
5225
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305226 /*
5227 * If we were called as "git cherry-pick <commit>", just
5228 * cherry-pick/revert it, set CHERRY_PICK_HEAD /
5229 * REVERT_HEAD, and don't touch the sequencer state.
5230 * This means it is possible to cherry-pick in the middle
5231 * of a cherry-pick sequence.
5232 */
5233 if (opts->revs->cmdline.nr == 1 &&
5234 opts->revs->cmdline.rev->whence == REV_CMD_REV &&
5235 opts->revs->no_walk &&
5236 !opts->revs->cmdline.rev->flags) {
5237 struct commit *cmit;
5238 if (prepare_revision_walk(opts->revs))
Johannes Schindelinb9b946d2016-08-26 15:47:10 +02005239 return error(_("revision walk setup failed"));
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305240 cmit = get_revision(opts->revs);
Jeff Kingc5e358d2018-07-10 00:32:08 -04005241 if (!cmit)
5242 return error(_("empty commit set passed"));
5243 if (get_revision(opts->revs))
5244 BUG("unexpected extra commit from walk");
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005245 return single_pick(r, cmit, opts);
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305246 }
5247
5248 /*
5249 * Start a new cherry-pick/ revert sequence; but
5250 * first, make sure that an existing one isn't in
5251 * progress
5252 */
5253
Johannes Schindelin34b05282016-09-09 16:37:15 +02005254 if (walk_revs_populate_todo(&todo_list, opts) ||
Rohit Ashiwal6a1f9042019-07-02 14:41:25 +05305255 create_seq_dir(r) < 0)
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305256 return -1;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005257 if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
Johannes Schindelin93b3df62016-10-21 14:26:25 +02005258 return error(_("can't revert as initial commit"));
brian m. carlson1e43ed92017-05-06 22:10:09 +00005259 if (save_head(oid_to_hex(&oid)))
Johannes Schindelin311fd392016-09-09 16:37:47 +02005260 return -1;
Johannes Schindelin88d5a272016-09-09 16:37:53 +02005261 if (save_opts(opts))
5262 return -1;
Stephan Beyer1e412292016-12-07 22:51:32 +01005263 update_abort_safety_file();
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005264 res = pick_commits(r, &todo_list, opts);
Johannes Schindelin004fefa2016-10-21 14:24:41 +02005265 todo_list_release(&todo_list);
5266 return res;
Ramkumar Ramachandra043a4492012-01-11 23:45:57 +05305267}
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005268
Jeff King66e83d92018-08-22 20:50:51 -04005269void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005270{
Brandon Caseybab4d102013-02-12 02:17:35 -08005271 unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005272 struct strbuf sob = STRBUF_INIT;
Brandon Caseybab4d102013-02-12 02:17:35 -08005273 int has_footer;
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005274
5275 strbuf_addstr(&sob, sign_off_header);
William Hubbs39ab4d02019-02-04 12:48:50 -06005276 strbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005277 strbuf_addch(&sob, '\n');
Brandon Caseybab4d102013-02-12 02:17:35 -08005278
Jonathan Tan44dc7382017-04-26 13:50:03 -07005279 if (!ignore_footer)
5280 strbuf_complete_line(msgbuf);
5281
Brandon Caseybab4d102013-02-12 02:17:35 -08005282 /*
5283 * If the whole message buffer is equal to the sob, pretend that we
5284 * found a conforming footer with a matching sob
5285 */
5286 if (msgbuf->len - ignore_footer == sob.len &&
5287 !strncmp(msgbuf->buf, sob.buf, sob.len))
5288 has_footer = 3;
5289 else
5290 has_footer = has_conforming_footer(msgbuf, &sob, ignore_footer);
5291
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005292 if (!has_footer) {
5293 const char *append_newlines = NULL;
5294 size_t len = msgbuf->len - ignore_footer;
5295
Brandon Casey8c613fd2013-02-22 14:05:27 -08005296 if (!len) {
5297 /*
5298 * The buffer is completely empty. Leave foom for
5299 * the title and body to be filled in by the user.
5300 */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005301 append_newlines = "\n\n";
Brandon Casey8c613fd2013-02-22 14:05:27 -08005302 } else if (len == 1) {
5303 /*
5304 * Buffer contains a single newline. Add another
5305 * so that we leave room for the title and body.
5306 */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005307 append_newlines = "\n";
Brandon Casey8c613fd2013-02-22 14:05:27 -08005308 } else if (msgbuf->buf[len - 2] != '\n') {
5309 /*
5310 * Buffer ends with a single newline. Add another
5311 * so that there is an empty line between the message
5312 * body and the sob.
5313 */
5314 append_newlines = "\n";
5315 } /* else, the buffer already ends with two newlines. */
Brandon Casey33f2f9a2013-02-12 02:33:42 -08005316
5317 if (append_newlines)
5318 strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
5319 append_newlines, strlen(append_newlines));
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005320 }
Brandon Caseybab4d102013-02-12 02:17:35 -08005321
5322 if (has_footer != 3 && (!no_dup_sob || has_footer != 2))
5323 strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
5324 sob.buf, sob.len);
5325
Miklos Vajna5ed75e22012-09-14 08:52:03 +02005326 strbuf_release(&sob);
5327}
Johannes Schindelin62db5242017-07-14 16:44:58 +02005328
Johannes Schindelin1644c732018-04-25 14:29:03 +02005329struct labels_entry {
5330 struct hashmap_entry entry;
5331 char label[FLEX_ARRAY];
5332};
5333
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +02005334static int labels_cmp(const void *fndata UNUSED,
Jeff King02c3c592022-08-19 06:08:46 -04005335 const struct hashmap_entry *eptr,
Eric Wong939af162019-10-06 23:30:37 +00005336 const struct hashmap_entry *entry_or_key, const void *key)
Johannes Schindelin1644c732018-04-25 14:29:03 +02005337{
Eric Wong939af162019-10-06 23:30:37 +00005338 const struct labels_entry *a, *b;
5339
5340 a = container_of(eptr, const struct labels_entry, entry);
5341 b = container_of(entry_or_key, const struct labels_entry, entry);
5342
Johannes Schindelin1644c732018-04-25 14:29:03 +02005343 return key ? strcmp(a->label, key) : strcmp(a->label, b->label);
5344}
5345
5346struct string_entry {
5347 struct oidmap_entry entry;
5348 char string[FLEX_ARRAY];
5349};
5350
5351struct label_state {
5352 struct oidmap commit2label;
5353 struct hashmap labels;
5354 struct strbuf buf;
5355};
5356
5357static const char *label_oid(struct object_id *oid, const char *label,
5358 struct label_state *state)
5359{
5360 struct labels_entry *labels_entry;
5361 struct string_entry *string_entry;
5362 struct object_id dummy;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005363 int i;
5364
5365 string_entry = oidmap_get(&state->commit2label, oid);
5366 if (string_entry)
5367 return string_entry->string;
5368
5369 /*
5370 * For "uninteresting" commits, i.e. commits that are not to be
5371 * rebased, and which can therefore not be labeled, we use a unique
5372 * abbreviation of the commit name. This is slightly more complicated
Ævar Arnfjörð Bjarmasonc7c33f52023-03-28 15:58:57 +02005373 * than calling repo_find_unique_abbrev() because we also need to make
Johannes Schindelin1644c732018-04-25 14:29:03 +02005374 * sure that the abbreviation does not conflict with any other
5375 * label.
5376 *
5377 * We disallow "interesting" commits to be labeled by a string that
5378 * is a valid full-length hash, to ensure that we always can find an
5379 * abbreviation for any uninteresting commit's names that does not
5380 * clash with any other label.
5381 */
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005382 strbuf_reset(&state->buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005383 if (!label) {
5384 char *p;
5385
brian m. carlson4439c7a2019-08-18 20:04:16 +00005386 strbuf_grow(&state->buf, GIT_MAX_HEXSZ);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005387 label = p = state->buf.buf;
5388
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02005389 repo_find_unique_abbrev_r(the_repository, p, oid,
5390 default_abbrev);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005391
5392 /*
5393 * We may need to extend the abbreviated hash so that there is
5394 * no conflicting label.
5395 */
5396 if (hashmap_get_from_hash(&state->labels, strihash(p), p)) {
5397 size_t i = strlen(p) + 1;
5398
5399 oid_to_hex_r(p, oid);
brian m. carlson4439c7a2019-08-18 20:04:16 +00005400 for (; i < the_hash_algo->hexsz; i++) {
Johannes Schindelin1644c732018-04-25 14:29:03 +02005401 char save = p[i];
5402 p[i] = '\0';
5403 if (!hashmap_get_from_hash(&state->labels,
5404 strihash(p), p))
5405 break;
5406 p[i] = save;
5407 }
5408 }
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005409 } else {
Johannes Schindelin1644c732018-04-25 14:29:03 +02005410 struct strbuf *buf = &state->buf;
5411
Matthew Rogerscd552222019-11-17 23:16:10 +00005412 /*
5413 * Sanitize labels by replacing non-alpha-numeric characters
5414 * (including white-space ones) by dashes, as they might be
5415 * illegal in file names (and hence in ref names).
5416 *
5417 * Note that we retain non-ASCII UTF-8 characters (identified
5418 * via the most significant bit). They should be all acceptable
5419 * in file names. We do not validate the UTF-8 here, that's not
5420 * the job of this function.
5421 */
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005422 for (; *label; label++)
Matthew Rogerscd552222019-11-17 23:16:10 +00005423 if ((*label & 0x80) || isalnum(*label))
5424 strbuf_addch(buf, *label);
5425 /* avoid leading dash and double-dashes */
5426 else if (buf->len && buf->buf[buf->len - 1] != '-')
5427 strbuf_addch(buf, '-');
5428 if (!buf->len) {
5429 strbuf_addstr(buf, "rev-");
5430 strbuf_add_unique_abbrev(buf, oid, default_abbrev);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005431 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005432 label = buf->buf;
Johannes Schindelin867bc1d2019-11-17 23:16:09 +00005433
5434 if ((buf->len == the_hash_algo->hexsz &&
5435 !get_oid_hex(label, &dummy)) ||
5436 (buf->len == 1 && *label == '#') ||
5437 hashmap_get_from_hash(&state->labels,
5438 strihash(label), label)) {
5439 /*
5440 * If the label already exists, or if the label is a
5441 * valid full OID, or the label is a '#' (which we use
5442 * as a separator between merge heads and oneline), we
5443 * append a dash and a number to make it unique.
5444 */
5445 size_t len = buf->len;
5446
5447 for (i = 2; ; i++) {
5448 strbuf_setlen(buf, len);
5449 strbuf_addf(buf, "-%d", i);
5450 if (!hashmap_get_from_hash(&state->labels,
5451 strihash(buf->buf),
5452 buf->buf))
5453 break;
5454 }
5455
5456 label = buf->buf;
5457 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005458 }
5459
5460 FLEX_ALLOC_STR(labels_entry, label, label);
Eric Wongd22245a2019-10-06 23:30:27 +00005461 hashmap_entry_init(&labels_entry->entry, strihash(label));
Eric Wongb94e5c12019-10-06 23:30:29 +00005462 hashmap_add(&state->labels, &labels_entry->entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005463
5464 FLEX_ALLOC_STR(string_entry, string, label);
5465 oidcpy(&string_entry->entry.oid, oid);
5466 oidmap_put(&state->commit2label, string_entry);
5467
5468 return string_entry->string;
5469}
5470
5471static int make_script_with_merges(struct pretty_print_context *pp,
Alban Gruind358fc22019-03-05 20:17:56 +01005472 struct rev_info *revs, struct strbuf *out,
Johannes Schindelin1644c732018-04-25 14:29:03 +02005473 unsigned flags)
5474{
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005475 int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
Johannes Schindelin7543f6f2018-04-25 14:29:40 +02005476 int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
Johannes Schindeline1fac532019-07-31 08:18:49 -07005477 int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005478 int skipped_commit = 0;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005479 struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
5480 struct strbuf label = STRBUF_INIT;
5481 struct commit_list *commits = NULL, **tail = &commits, *iter;
5482 struct commit_list *tips = NULL, **tips_tail = &tips;
5483 struct commit *commit;
5484 struct oidmap commit2todo = OIDMAP_INIT;
5485 struct string_entry *entry;
5486 struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
5487 shown = OIDSET_INIT;
5488 struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT };
5489
5490 int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
5491 const char *cmd_pick = abbr ? "p" : "pick",
5492 *cmd_label = abbr ? "l" : "label",
5493 *cmd_reset = abbr ? "t" : "reset",
5494 *cmd_merge = abbr ? "m" : "merge";
5495
5496 oidmap_init(&commit2todo, 0);
5497 oidmap_init(&state.commit2label, 0);
Eric Wong939af162019-10-06 23:30:37 +00005498 hashmap_init(&state.labels, labels_cmp, NULL, 0);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005499 strbuf_init(&state.buf, 32);
5500
5501 if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
Doan Tran Cong Danhe02058a2019-11-18 18:57:47 +07005502 struct labels_entry *onto_label_entry;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005503 struct object_id *oid = &revs->cmdline.rev[0].item->oid;
5504 FLEX_ALLOC_STR(entry, string, "onto");
5505 oidcpy(&entry->entry.oid, oid);
5506 oidmap_put(&state.commit2label, entry);
Doan Tran Cong Danhe02058a2019-11-18 18:57:47 +07005507
5508 FLEX_ALLOC_STR(onto_label_entry, label, "onto");
5509 hashmap_entry_init(&onto_label_entry->entry, strihash("onto"));
5510 hashmap_add(&state.labels, &onto_label_entry->entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005511 }
5512
5513 /*
5514 * First phase:
5515 * - get onelines for all commits
5516 * - gather all branch tips (i.e. 2nd or later parents of merges)
5517 * - label all branch tips
5518 */
5519 while ((commit = get_revision(revs))) {
5520 struct commit_list *to_merge;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005521 const char *p1, *p2;
5522 struct object_id *oid;
5523 int is_empty;
5524
5525 tail = &commit_list_insert(commit, tail)->next;
5526 oidset_insert(&interesting, &commit->object.oid);
5527
5528 is_empty = is_original_commit_empty(commit);
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005529 if (!is_empty && (commit->object.flags & PATCHSAME)) {
5530 if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
5531 warning(_("skipped previously applied commit %s"),
5532 short_commit_name(commit));
5533 skipped_commit = 1;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005534 continue;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005535 }
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005536 if (is_empty && !keep_empty)
5537 continue;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005538
5539 strbuf_reset(&oneline);
5540 pretty_print_commit(pp, commit, &oneline);
5541
5542 to_merge = commit->parents ? commit->parents->next : NULL;
5543 if (!to_merge) {
5544 /* non-merge commit: easy case */
5545 strbuf_reset(&buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005546 strbuf_addf(&buf, "%s %s %s", cmd_pick,
5547 oid_to_hex(&commit->object.oid),
5548 oneline.buf);
Elijah Newren1b5735f2020-04-11 02:44:24 +00005549 if (is_empty)
5550 strbuf_addf(&buf, " %c empty",
5551 comment_line_char);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005552
5553 FLEX_ALLOC_STR(entry, string, buf.buf);
5554 oidcpy(&entry->entry.oid, &commit->object.oid);
5555 oidmap_put(&commit2todo, entry);
5556
5557 continue;
5558 }
5559
Johannes Schindelin1644c732018-04-25 14:29:03 +02005560 /* Create a label */
5561 strbuf_reset(&label);
5562 if (skip_prefix(oneline.buf, "Merge ", &p1) &&
5563 (p1 = strchr(p1, '\'')) &&
5564 (p2 = strchr(++p1, '\'')))
5565 strbuf_add(&label, p1, p2 - p1);
5566 else if (skip_prefix(oneline.buf, "Merge pull request ",
5567 &p1) &&
5568 (p1 = strstr(p1, " from ")))
5569 strbuf_addstr(&label, p1 + strlen(" from "));
5570 else
5571 strbuf_addbuf(&label, &oneline);
5572
Johannes Schindelin1644c732018-04-25 14:29:03 +02005573 strbuf_reset(&buf);
5574 strbuf_addf(&buf, "%s -C %s",
5575 cmd_merge, oid_to_hex(&commit->object.oid));
5576
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01005577 /* label the tips of merged branches */
5578 for (; to_merge; to_merge = to_merge->next) {
5579 oid = &to_merge->item->object.oid;
5580 strbuf_addch(&buf, ' ');
Johannes Schindelin1644c732018-04-25 14:29:03 +02005581
Johannes Schindelin2b6ad0f2017-12-21 15:52:45 +01005582 if (!oidset_contains(&interesting, oid)) {
5583 strbuf_addstr(&buf, label_oid(oid, NULL,
5584 &state));
5585 continue;
5586 }
5587
Johannes Schindelin1644c732018-04-25 14:29:03 +02005588 tips_tail = &commit_list_insert(to_merge->item,
5589 tips_tail)->next;
5590
5591 strbuf_addstr(&buf, label_oid(oid, label.buf, &state));
5592 }
5593 strbuf_addf(&buf, " # %s", oneline.buf);
5594
5595 FLEX_ALLOC_STR(entry, string, buf.buf);
5596 oidcpy(&entry->entry.oid, &commit->object.oid);
5597 oidmap_put(&commit2todo, entry);
5598 }
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005599 if (skipped_commit)
5600 advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
5601 _("use --reapply-cherry-picks to include skipped commits"));
Johannes Schindelin1644c732018-04-25 14:29:03 +02005602
5603 /*
5604 * Second phase:
5605 * - label branch points
5606 * - add HEAD to the branch tips
5607 */
5608 for (iter = commits; iter; iter = iter->next) {
5609 struct commit_list *parent = iter->item->parents;
5610 for (; parent; parent = parent->next) {
5611 struct object_id *oid = &parent->item->object.oid;
5612 if (!oidset_contains(&interesting, oid))
5613 continue;
René Scharfe6e8fc702018-10-03 15:06:49 +02005614 if (oidset_insert(&child_seen, oid))
Johannes Schindelin1644c732018-04-25 14:29:03 +02005615 label_oid(oid, "branch-point", &state);
5616 }
5617
Elijah Newren15beaaa2019-11-05 17:07:23 +00005618 /* Add HEAD as implicit "tip of branch" */
Johannes Schindelin1644c732018-04-25 14:29:03 +02005619 if (!iter->next)
5620 tips_tail = &commit_list_insert(iter->item,
5621 tips_tail)->next;
5622 }
5623
5624 /*
5625 * Third phase: output the todo list. This is a bit tricky, as we
5626 * want to avoid jumping back and forth between revisions. To
5627 * accomplish that goal, we walk backwards from the branch tips,
5628 * gathering commits not yet shown, reversing the list on the fly,
5629 * then outputting that list (labeling revisions as needed).
5630 */
Alban Gruind358fc22019-03-05 20:17:56 +01005631 strbuf_addf(out, "%s onto\n", cmd_label);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005632 for (iter = tips; iter; iter = iter->next) {
5633 struct commit_list *list = NULL, *iter2;
5634
5635 commit = iter->item;
5636 if (oidset_contains(&shown, &commit->object.oid))
5637 continue;
5638 entry = oidmap_get(&state.commit2label, &commit->object.oid);
5639
5640 if (entry)
Alban Gruind358fc22019-03-05 20:17:56 +01005641 strbuf_addf(out, "\n%c Branch %s\n", comment_line_char, entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005642 else
Alban Gruind358fc22019-03-05 20:17:56 +01005643 strbuf_addch(out, '\n');
Johannes Schindelin1644c732018-04-25 14:29:03 +02005644
5645 while (oidset_contains(&interesting, &commit->object.oid) &&
5646 !oidset_contains(&shown, &commit->object.oid)) {
5647 commit_list_insert(commit, &list);
5648 if (!commit->parents) {
5649 commit = NULL;
5650 break;
5651 }
5652 commit = commit->parents->item;
5653 }
5654
5655 if (!commit)
Alban Gruind358fc22019-03-05 20:17:56 +01005656 strbuf_addf(out, "%s %s\n", cmd_reset,
Johannes Schindeline1fac532019-07-31 08:18:49 -07005657 rebase_cousins || root_with_onto ?
5658 "onto" : "[new root]");
Johannes Schindelin1644c732018-04-25 14:29:03 +02005659 else {
5660 const char *to = NULL;
5661
5662 entry = oidmap_get(&state.commit2label,
5663 &commit->object.oid);
5664 if (entry)
5665 to = entry->string;
Johannes Schindelin7543f6f2018-04-25 14:29:40 +02005666 else if (!rebase_cousins)
5667 to = label_oid(&commit->object.oid, NULL,
5668 &state);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005669
5670 if (!to || !strcmp(to, "onto"))
Alban Gruind358fc22019-03-05 20:17:56 +01005671 strbuf_addf(out, "%s onto\n", cmd_reset);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005672 else {
5673 strbuf_reset(&oneline);
5674 pretty_print_commit(pp, commit, &oneline);
Alban Gruind358fc22019-03-05 20:17:56 +01005675 strbuf_addf(out, "%s %s # %s\n",
5676 cmd_reset, to, oneline.buf);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005677 }
5678 }
5679
5680 for (iter2 = list; iter2; iter2 = iter2->next) {
5681 struct object_id *oid = &iter2->item->object.oid;
5682 entry = oidmap_get(&commit2todo, oid);
5683 /* only show if not already upstream */
5684 if (entry)
Alban Gruind358fc22019-03-05 20:17:56 +01005685 strbuf_addf(out, "%s\n", entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005686 entry = oidmap_get(&state.commit2label, oid);
5687 if (entry)
Alban Gruind358fc22019-03-05 20:17:56 +01005688 strbuf_addf(out, "%s %s\n",
5689 cmd_label, entry->string);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005690 oidset_insert(&shown, oid);
5691 }
5692
5693 free_commit_list(list);
5694 }
5695
5696 free_commit_list(commits);
5697 free_commit_list(tips);
5698
5699 strbuf_release(&label);
5700 strbuf_release(&oneline);
5701 strbuf_release(&buf);
5702
5703 oidmap_free(&commit2todo, 1);
5704 oidmap_free(&state.commit2label, 1);
Elijah Newren6da1a252020-11-02 18:55:05 +00005705 hashmap_clear_and_free(&state.labels, struct labels_entry, entry);
Johannes Schindelin1644c732018-04-25 14:29:03 +02005706 strbuf_release(&state.buf);
5707
5708 return 0;
5709}
5710
Alban Gruind358fc22019-03-05 20:17:56 +01005711int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
5712 const char **argv, unsigned flags)
Johannes Schindelin62db5242017-07-14 16:44:58 +02005713{
5714 char *format = NULL;
5715 struct pretty_print_context pp = {0};
Johannes Schindelin62db5242017-07-14 16:44:58 +02005716 struct rev_info revs;
5717 struct commit *commit;
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005718 int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
Liam Beguind8ae6c82017-12-05 12:52:34 -05005719 const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
Johannes Schindelin1644c732018-04-25 14:29:03 +02005720 int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
Jonathan Tan0fcb4f62020-04-11 02:44:27 +00005721 int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005722 int skipped_commit = 0;
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005723 int ret = 0;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005724
Nguyễn Thái Ngọc Duyf11c9582018-11-10 06:48:56 +01005725 repo_init_revisions(r, &revs, NULL);
Johannes Schindelin62db5242017-07-14 16:44:58 +02005726 revs.verbose_header = 1;
Johannes Schindelin1644c732018-04-25 14:29:03 +02005727 if (!rebase_merges)
5728 revs.max_parents = 1;
Jonathan Tan0fcb4f62020-04-11 02:44:27 +00005729 revs.cherry_mark = !reapply_cherry_picks;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005730 revs.limited = 1;
5731 revs.reverse = 1;
5732 revs.right_only = 1;
5733 revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
5734 revs.topo_order = 1;
5735
5736 revs.pretty_given = 1;
5737 git_config_get_string("rebase.instructionFormat", &format);
5738 if (!format || !*format) {
5739 free(format);
5740 format = xstrdup("%s");
5741 }
5742 get_commit_format(format, &revs);
5743 free(format);
5744 pp.fmt = revs.commit_format;
5745 pp.output_encoding = get_log_output_encoding();
5746
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005747 if (setup_revisions(argc, argv, &revs, NULL) > 1) {
5748 ret = error(_("make_script: unhandled options"));
5749 goto cleanup;
5750 }
Johannes Schindelin62db5242017-07-14 16:44:58 +02005751
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005752 if (prepare_revision_walk(&revs) < 0) {
5753 ret = error(_("make_script: error preparing revisions"));
5754 goto cleanup;
5755 }
Johannes Schindelin62db5242017-07-14 16:44:58 +02005756
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005757 if (rebase_merges) {
5758 ret = make_script_with_merges(&pp, &revs, out, flags);
5759 goto cleanup;
5760 }
Johannes Schindelin1644c732018-04-25 14:29:03 +02005761
Johannes Schindelin62db5242017-07-14 16:44:58 +02005762 while ((commit = get_revision(&revs))) {
Elijah Newrend48e5e22020-02-15 21:36:24 +00005763 int is_empty = is_original_commit_empty(commit);
Phillip Wood76ea2352018-03-20 10:03:14 +00005764
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005765 if (!is_empty && (commit->object.flags & PATCHSAME)) {
5766 if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
5767 warning(_("skipped previously applied commit %s"),
5768 short_commit_name(commit));
5769 skipped_commit = 1;
Phillip Wood76ea2352018-03-20 10:03:14 +00005770 continue;
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005771 }
Elijah Newrenb9cbd292020-04-11 02:44:25 +00005772 if (is_empty && !keep_empty)
5773 continue;
Alban Gruind358fc22019-03-05 20:17:56 +01005774 strbuf_addf(out, "%s %s ", insn,
Liam Beguind8ae6c82017-12-05 12:52:34 -05005775 oid_to_hex(&commit->object.oid));
Alban Gruind358fc22019-03-05 20:17:56 +01005776 pretty_print_commit(&pp, commit, out);
Elijah Newren1b5735f2020-04-11 02:44:24 +00005777 if (is_empty)
5778 strbuf_addf(out, " %c empty", comment_line_char);
Alban Gruind358fc22019-03-05 20:17:56 +01005779 strbuf_addch(out, '\n');
Johannes Schindelin62db5242017-07-14 16:44:58 +02005780 }
Josh Steadmon767a4ca2021-08-30 14:46:02 -07005781 if (skipped_commit)
5782 advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
5783 _("use --reapply-cherry-picks to include skipped commits"));
Ævar Arnfjörð Bjarmason0139c582022-04-13 22:01:40 +02005784cleanup:
5785 release_revisions(&revs);
5786 return ret;
Johannes Schindelin62db5242017-07-14 16:44:58 +02005787}
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005788
Liam Beguin0cce4a22017-12-05 12:52:33 -05005789/*
5790 * Add commands after pick and (series of) squash/fixup commands
5791 * in the todo list.
5792 */
Johannes Schindelin17919c32021-09-07 21:05:12 +00005793static void todo_list_add_exec_commands(struct todo_list *todo_list,
5794 struct string_list *commands)
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005795{
Alban Gruin683153a2019-03-05 20:17:54 +01005796 struct strbuf *buf = &todo_list->buf;
5797 size_t base_offset = buf->len;
5798 int i, insert, nr = 0, alloc = 0;
5799 struct todo_item *items = NULL, *base_items = NULL;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005800
René Scharfeca56dad2021-03-13 17:17:22 +01005801 CALLOC_ARRAY(base_items, commands->nr);
Alban Gruin683153a2019-03-05 20:17:54 +01005802 for (i = 0; i < commands->nr; i++) {
5803 size_t command_len = strlen(commands->items[i].string);
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005804
Alban Gruin683153a2019-03-05 20:17:54 +01005805 strbuf_addstr(buf, commands->items[i].string);
5806 strbuf_addch(buf, '\n');
5807
5808 base_items[i].command = TODO_EXEC;
5809 base_items[i].offset_in_buf = base_offset;
Phillip Woode57d2c52023-01-12 16:50:01 +00005810 base_items[i].arg_offset = base_offset;
5811 base_items[i].arg_len = command_len;
Alban Gruin683153a2019-03-05 20:17:54 +01005812
5813 base_offset += command_len + 1;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005814 }
5815
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005816 /*
5817 * Insert <commands> after every pick. Here, fixup/squash chains
5818 * are considered part of the pick, so we insert the commands *after*
5819 * those chains if there are any.
Alban Gruin683153a2019-03-05 20:17:54 +01005820 *
Elijah Newren15beaaa2019-11-05 17:07:23 +00005821 * As we insert the exec commands immediately after rearranging
Alban Gruin683153a2019-03-05 20:17:54 +01005822 * any fixups and before the user edits the list, a fixup chain
5823 * can never contain comments (any comments are empty picks that
5824 * have been commented out because the user did not specify
5825 * --keep-empty). So, it is safe to insert an exec command
5826 * without looking at the command following a comment.
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005827 */
Alban Gruin683153a2019-03-05 20:17:54 +01005828 insert = 0;
5829 for (i = 0; i < todo_list->nr; i++) {
5830 enum todo_command command = todo_list->items[i].command;
5831 if (insert && !is_fixup(command)) {
5832 ALLOC_GROW(items, nr + commands->nr, alloc);
5833 COPY_ARRAY(items + nr, base_items, commands->nr);
5834 nr += commands->nr;
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005835
Alban Gruin683153a2019-03-05 20:17:54 +01005836 insert = 0;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005837 }
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005838
Alban Gruin683153a2019-03-05 20:17:54 +01005839 ALLOC_GROW(items, nr + 1, alloc);
5840 items[nr++] = todo_list->items[i];
5841
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005842 if (command == TODO_PICK || command == TODO_MERGE)
Alban Gruin683153a2019-03-05 20:17:54 +01005843 insert = 1;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005844 }
Liam Beguin0cce4a22017-12-05 12:52:33 -05005845
Johannes Schindelin1ace63b2018-08-09 02:41:11 -07005846 /* insert or append final <commands> */
Elijah Newrencc9dcde2021-11-30 03:58:39 +00005847 if (insert) {
Alban Gruin683153a2019-03-05 20:17:54 +01005848 ALLOC_GROW(items, nr + commands->nr, alloc);
5849 COPY_ARRAY(items + nr, base_items, commands->nr);
5850 nr += commands->nr;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005851 }
5852
Alban Gruin683153a2019-03-05 20:17:54 +01005853 free(base_items);
5854 FREE_AND_NULL(todo_list->items);
5855 todo_list->items = items;
5856 todo_list->nr = nr;
5857 todo_list->alloc = alloc;
5858}
5859
Alban Gruin616d7742019-01-29 16:01:48 +01005860static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_list,
5861 struct strbuf *buf, int num, unsigned flags)
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005862{
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005863 struct todo_item *item;
Alban Gruin616d7742019-01-29 16:01:48 +01005864 int i, max = todo_list->nr;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005865
Alban Gruin616d7742019-01-29 16:01:48 +01005866 if (num > 0 && num < max)
5867 max = num;
5868
5869 for (item = todo_list->items, i = 0; i < max; i++, item++) {
Alban Gruin68e70902020-03-30 14:42:35 +02005870 char cmd;
5871
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005872 /* if the item is not a command write it and continue */
5873 if (item->command >= TODO_COMMENT) {
Alban Gruin616d7742019-01-29 16:01:48 +01005874 strbuf_addf(buf, "%.*s\n", item->arg_len,
Alban Gruincbef27d2019-01-29 16:01:47 +01005875 todo_item_get_arg(todo_list, item));
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005876 continue;
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005877 }
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005878
5879 /* add command to the buffer */
Alban Gruin68e70902020-03-30 14:42:35 +02005880 cmd = command_to_char(item->command);
5881 if ((flags & TODO_LIST_ABBREVIATE_CMDS) && cmd)
5882 strbuf_addch(buf, cmd);
Liam Beguind8ae6c82017-12-05 12:52:34 -05005883 else
Alban Gruin616d7742019-01-29 16:01:48 +01005884 strbuf_addstr(buf, command_to_string(item->command));
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005885
5886 /* add commit id */
5887 if (item->commit) {
Liam Beguin313a48e2017-12-05 12:52:32 -05005888 const char *oid = flags & TODO_LIST_SHORTEN_IDS ?
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005889 short_commit_name(item->commit) :
5890 oid_to_hex(&item->commit->object.oid);
5891
Charvi Mendiratta9e3cebd2021-01-29 23:50:47 +05305892 if (item->command == TODO_FIXUP) {
5893 if (item->flags & TODO_EDIT_FIXUP_MSG)
5894 strbuf_addstr(buf, " -c");
5895 else if (item->flags & TODO_REPLACE_FIXUP_MSG) {
5896 strbuf_addstr(buf, " -C");
5897 }
5898 }
5899
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02005900 if (item->command == TODO_MERGE) {
5901 if (item->flags & TODO_EDIT_MERGE_MSG)
Alban Gruin616d7742019-01-29 16:01:48 +01005902 strbuf_addstr(buf, " -c");
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02005903 else
Alban Gruin616d7742019-01-29 16:01:48 +01005904 strbuf_addstr(buf, " -C");
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02005905 }
5906
Alban Gruin616d7742019-01-29 16:01:48 +01005907 strbuf_addf(buf, " %s", oid);
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005908 }
Johannes Schindelin4c68e7d2018-04-25 14:28:54 +02005909
Liam Beguin8dccc7a2017-12-05 12:52:30 -05005910 /* add all the rest */
Johannes Schindelinc7b4d792017-12-23 00:56:00 +01005911 if (!item->arg_len)
Alban Gruin616d7742019-01-29 16:01:48 +01005912 strbuf_addch(buf, '\n');
Johannes Schindelinc7b4d792017-12-23 00:56:00 +01005913 else
Alban Gruin616d7742019-01-29 16:01:48 +01005914 strbuf_addf(buf, " %.*s\n", item->arg_len,
Alban Gruincbef27d2019-01-29 16:01:47 +01005915 todo_item_get_arg(todo_list, item));
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005916 }
Johannes Schindelin3546c8d2017-07-14 16:45:11 +02005917}
Johannes Schindelin94399942017-07-14 16:45:21 +02005918
Alban Gruin616d7742019-01-29 16:01:48 +01005919int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
5920 const char *file, const char *shortrevisions,
5921 const char *shortonto, int num, unsigned flags)
Johannes Schindelin94399942017-07-14 16:45:21 +02005922{
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01005923 int res;
Alban Gruin616d7742019-01-29 16:01:48 +01005924 struct strbuf buf = STRBUF_INIT;
Johannes Schindelin94399942017-07-14 16:45:21 +02005925
Alban Gruin616d7742019-01-29 16:01:48 +01005926 todo_list_to_strbuf(r, todo_list, &buf, num, flags);
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01005927 if (flags & TODO_LIST_APPEND_TODO_HELP)
Elijah Newrend48e5e22020-02-15 21:36:24 +00005928 append_todo_help(count_commands(todo_list),
Alban Gruinaf1fc3a2019-03-05 20:18:02 +01005929 shortrevisions, shortonto, &buf);
Johannes Schindelin94399942017-07-14 16:45:21 +02005930
Alban Gruin616d7742019-01-29 16:01:48 +01005931 res = write_message(buf.buf, buf.len, file, 0);
Alban Gruincbef27d2019-01-29 16:01:47 +01005932 strbuf_release(&buf);
Johannes Schindelin94399942017-07-14 16:45:21 +02005933
5934 return res;
5935}
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005936
5937/* skip picking commits whose parents are unchanged */
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005938static int skip_unnecessary_picks(struct repository *r,
5939 struct todo_list *todo_list,
5940 struct object_id *base_oid)
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005941{
Alban Gruind4ed5d72018-08-10 18:51:36 +02005942 struct object_id *parent_oid;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005943 int i;
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005944
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005945 for (i = 0; i < todo_list->nr; i++) {
5946 struct todo_item *item = todo_list->items + i;
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005947
5948 if (item->command >= TODO_NOOP)
5949 continue;
5950 if (item->command != TODO_PICK)
5951 break;
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02005952 if (repo_parse_commit(r, item->commit)) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005953 return error(_("could not parse commit '%s'"),
5954 oid_to_hex(&item->commit->object.oid));
5955 }
5956 if (!item->commit->parents)
5957 break; /* root commit */
5958 if (item->commit->parents->next)
5959 break; /* merge commit */
5960 parent_oid = &item->commit->parents->item->object.oid;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005961 if (!oideq(parent_oid, base_oid))
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005962 break;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005963 oidcpy(base_oid, &item->commit->object.oid);
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005964 }
5965 if (i > 0) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005966 const char *done_path = rebase_path_done();
5967
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005968 if (todo_list_write_to_file(r, todo_list, done_path, NULL, NULL, i, 0)) {
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005969 error_errno(_("could not write to '%s'"), done_path);
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005970 return -1;
5971 }
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005972
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005973 MOVE_ARRAY(todo_list->items, todo_list->items + i, todo_list->nr - i);
5974 todo_list->nr -= i;
5975 todo_list->current = 0;
Alban Gruin34065542019-11-24 18:43:29 +01005976 todo_list->done_nr += i;
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01005977
5978 if (is_fixup(peek_command(todo_list, 0)))
5979 record_in_rewritten(base_oid, peek_command(todo_list, 0));
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005980 }
5981
Johannes Schindelincdac2b02017-07-14 16:45:25 +02005982 return 0;
5983}
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02005984
Derrick Stolee900b50c2022-07-19 18:33:39 +00005985struct todo_add_branch_context {
5986 struct todo_item *items;
5987 size_t items_nr;
5988 size_t items_alloc;
5989 struct strbuf *buf;
5990 struct commit *commit;
5991 struct string_list refs_to_oids;
5992};
5993
5994static int add_decorations_to_list(const struct commit *commit,
5995 struct todo_add_branch_context *ctx)
5996{
5997 const struct name_decoration *decoration = get_name_decoration(&commit->object);
Derrick Stoleeaa37f3e2022-07-19 18:33:43 +00005998 const char *head_ref = resolve_ref_unsafe("HEAD",
5999 RESOLVE_REF_READING,
6000 NULL,
6001 NULL);
Derrick Stolee900b50c2022-07-19 18:33:39 +00006002
6003 while (decoration) {
6004 struct todo_item *item;
6005 const char *path;
6006 size_t base_offset = ctx->buf->len;
6007
Derrick Stoleeaa37f3e2022-07-19 18:33:43 +00006008 /*
6009 * If the branch is the current HEAD, then it will be
6010 * updated by the default rebase behavior.
6011 */
6012 if (head_ref && !strcmp(head_ref, decoration->name)) {
6013 decoration = decoration->next;
6014 continue;
6015 }
6016
Derrick Stolee900b50c2022-07-19 18:33:39 +00006017 ALLOC_GROW(ctx->items,
6018 ctx->items_nr + 1,
6019 ctx->items_alloc);
6020 item = &ctx->items[ctx->items_nr];
6021 memset(item, 0, sizeof(*item));
6022
6023 /* If the branch is checked out, then leave a comment instead. */
6024 if ((path = branch_checked_out(decoration->name))) {
6025 item->command = TODO_COMMENT;
6026 strbuf_addf(ctx->buf, "# Ref %s checked out at '%s'\n",
6027 decoration->name, path);
6028 } else {
6029 struct string_list_item *sti;
6030 item->command = TODO_UPDATE_REF;
6031 strbuf_addf(ctx->buf, "%s\n", decoration->name);
6032
6033 sti = string_list_insert(&ctx->refs_to_oids,
6034 decoration->name);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006035 sti->util = init_update_ref_record(decoration->name);
Derrick Stolee900b50c2022-07-19 18:33:39 +00006036 }
6037
6038 item->offset_in_buf = base_offset;
6039 item->arg_offset = base_offset;
6040 item->arg_len = ctx->buf->len - base_offset;
6041 ctx->items_nr++;
6042
6043 decoration = decoration->next;
6044 }
6045
6046 return 0;
6047}
6048
6049/*
6050 * For each 'pick' command, find out if the commit has a decoration in
6051 * refs/heads/. If so, then add a 'label for-update-refs/' command.
6052 */
6053static int todo_list_add_update_ref_commands(struct todo_list *todo_list)
6054{
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006055 int i, res;
Derrick Stolee900b50c2022-07-19 18:33:39 +00006056 static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
6057 static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
6058 static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
6059 struct decoration_filter decoration_filter = {
6060 .include_ref_pattern = &decorate_refs_include,
6061 .exclude_ref_pattern = &decorate_refs_exclude,
6062 .exclude_ref_config_pattern = &decorate_refs_exclude_config,
6063 };
6064 struct todo_add_branch_context ctx = {
6065 .buf = &todo_list->buf,
6066 .refs_to_oids = STRING_LIST_INIT_DUP,
6067 };
6068
6069 ctx.items_alloc = 2 * todo_list->nr + 1;
6070 ALLOC_ARRAY(ctx.items, ctx.items_alloc);
6071
6072 string_list_append(&decorate_refs_include, "refs/heads/");
6073 load_ref_decorations(&decoration_filter, 0);
6074
6075 for (i = 0; i < todo_list->nr; ) {
6076 struct todo_item *item = &todo_list->items[i];
6077
6078 /* insert ith item into new list */
6079 ALLOC_GROW(ctx.items,
6080 ctx.items_nr + 1,
6081 ctx.items_alloc);
6082
6083 ctx.items[ctx.items_nr++] = todo_list->items[i++];
6084
6085 if (item->commit) {
6086 ctx.commit = item->commit;
6087 add_decorations_to_list(item->commit, &ctx);
6088 }
6089 }
6090
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006091 res = write_update_refs_state(&ctx.refs_to_oids);
6092
Derrick Stolee900b50c2022-07-19 18:33:39 +00006093 string_list_clear(&ctx.refs_to_oids, 1);
Derrick Stolee89fc0b52022-07-19 18:33:40 +00006094
6095 if (res) {
6096 /* we failed, so clean up the new list. */
6097 free(ctx.items);
6098 return res;
6099 }
6100
Derrick Stolee900b50c2022-07-19 18:33:39 +00006101 free(todo_list->items);
6102 todo_list->items = ctx.items;
6103 todo_list->nr = ctx.items_nr;
6104 todo_list->alloc = ctx.items_alloc;
6105
6106 return 0;
6107}
6108
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01006109int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
Alban Gruinb97e1872018-08-28 14:10:36 +02006110 const char *shortrevisions, const char *onto_name,
Phillip Woodf3e27a02020-11-04 15:29:38 +00006111 struct commit *onto, const struct object_id *orig_head,
Phillip Wood7d3488e2019-04-17 15:30:39 +01006112 struct string_list *commands, unsigned autosquash,
Derrick Stolee900b50c2022-07-19 18:33:39 +00006113 unsigned update_refs,
Phillip Wood7d3488e2019-04-17 15:30:39 +01006114 struct todo_list *todo_list)
Alban Gruinb97e1872018-08-28 14:10:36 +02006115{
Antti Keränen5da69c02020-08-13 20:42:57 +03006116 char shortonto[GIT_MAX_HEXSZ + 1];
6117 const char *todo_file = rebase_path_todo();
Alban Gruin94bcad72019-03-05 20:17:57 +01006118 struct todo_list new_todo = TODO_LIST_INIT;
Johannes Schindelinb6992262020-01-23 12:28:18 +00006119 struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT;
Phillip Wood7d3488e2019-04-17 15:30:39 +01006120 struct object_id oid = onto->object.oid;
Alban Gruin1451d0f2019-03-05 20:18:04 +01006121 int res;
Alban Gruinb97e1872018-08-28 14:10:36 +02006122
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02006123 repo_find_unique_abbrev_r(r, shortonto, &oid,
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02006124 DEFAULT_ABBREV);
Alban Gruinb97e1872018-08-28 14:10:36 +02006125
Alban Gruinb97e1872018-08-28 14:10:36 +02006126 if (buf->len == 0) {
Alban Gruin94bcad72019-03-05 20:17:57 +01006127 struct todo_item *item = append_new_todo(todo_list);
6128 item->command = TODO_NOOP;
6129 item->commit = NULL;
6130 item->arg_len = item->arg_offset = item->flags = item->offset_in_buf = 0;
6131 }
Alban Gruinb97e1872018-08-28 14:10:36 +02006132
Derrick Stolee900b50c2022-07-19 18:33:39 +00006133 if (update_refs && todo_list_add_update_ref_commands(todo_list))
6134 return -1;
6135
Alban Gruin94bcad72019-03-05 20:17:57 +01006136 if (autosquash && todo_list_rearrange_squash(todo_list))
Alban Gruinb97e1872018-08-28 14:10:36 +02006137 return -1;
6138
Alban Gruin683153a2019-03-05 20:17:54 +01006139 if (commands->nr)
Alban Gruin94bcad72019-03-05 20:17:57 +01006140 todo_list_add_exec_commands(todo_list, commands);
Alban Gruinb97e1872018-08-28 14:10:36 +02006141
Alban Gruin94bcad72019-03-05 20:17:57 +01006142 if (count_commands(todo_list) == 0) {
Denton Liube1bb602020-04-07 10:27:56 -04006143 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006144 sequencer_remove_state(opts);
Alban Gruinb97e1872018-08-28 14:10:36 +02006145
6146 return error(_("nothing to do"));
6147 }
6148
Alban Gruin1451d0f2019-03-05 20:18:04 +01006149 res = edit_todo_list(r, todo_list, &new_todo, shortrevisions,
6150 shortonto, flags);
6151 if (res == -1)
6152 return -1;
6153 else if (res == -2) {
Denton Liube1bb602020-04-07 10:27:56 -04006154 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006155 sequencer_remove_state(opts);
Alban Gruinb97e1872018-08-28 14:10:36 +02006156
Alban Gruinb97e1872018-08-28 14:10:36 +02006157 return -1;
Alban Gruin1451d0f2019-03-05 20:18:04 +01006158 } else if (res == -3) {
Denton Liube1bb602020-04-07 10:27:56 -04006159 apply_autostash(rebase_path_autostash());
Alban Gruinb97e1872018-08-28 14:10:36 +02006160 sequencer_remove_state(opts);
Alban Gruin94bcad72019-03-05 20:17:57 +01006161 todo_list_release(&new_todo);
Alban Gruinb97e1872018-08-28 14:10:36 +02006162
6163 return error(_("nothing to do"));
Alban Gruin5a5445d2020-01-28 22:12:46 +01006164 } else if (res == -4) {
Phillip Wood7d3488e2019-04-17 15:30:39 +01006165 checkout_onto(r, opts, onto_name, &onto->object.oid, orig_head);
Alban Gruin94bcad72019-03-05 20:17:57 +01006166 todo_list_release(&new_todo);
6167
Alban Gruinb97e1872018-08-28 14:10:36 +02006168 return -1;
6169 }
6170
Johannes Schindelinb6992262020-01-23 12:28:18 +00006171 /* Expand the commit IDs */
6172 todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0);
6173 strbuf_swap(&new_todo.buf, &buf2);
6174 strbuf_release(&buf2);
Johannes Schindelin170eea92023-05-13 08:11:26 +00006175 /* Nothing is done yet, and we're reparsing, so let's reset the count */
6176 new_todo.total_nr = 0;
Johannes Schindelinb6992262020-01-23 12:28:18 +00006177 if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0)
6178 BUG("invalid todo list after expanding IDs:\n%s",
6179 new_todo.buf.buf);
6180
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006181 if (opts->allow_ff && skip_unnecessary_picks(r, &new_todo, &oid)) {
6182 todo_list_release(&new_todo);
Alban Gruinb97e1872018-08-28 14:10:36 +02006183 return error(_("could not skip unnecessary pick commands"));
Alban Gruin6bfeb7f2019-03-05 20:18:00 +01006184 }
6185
Alban Gruin94bcad72019-03-05 20:17:57 +01006186 if (todo_list_write_to_file(r, &new_todo, todo_file, NULL, NULL, -1,
6187 flags & ~(TODO_LIST_SHORTEN_IDS))) {
6188 todo_list_release(&new_todo);
6189 return error_errno(_("could not write '%s'"), todo_file);
6190 }
6191
Alban Gruin393adf72019-11-24 18:43:32 +01006192 res = -1;
Alban Gruinb97e1872018-08-28 14:10:36 +02006193
Phillip Wood7d3488e2019-04-17 15:30:39 +01006194 if (checkout_onto(r, opts, onto_name, &oid, orig_head))
Alban Gruin393adf72019-11-24 18:43:32 +01006195 goto cleanup;
Nguyễn Thái Ngọc Duy29d51e22018-11-03 15:32:29 +01006196
Nguyễn Thái Ngọc Duy005af332018-11-10 06:48:57 +01006197 if (require_clean_work_tree(r, "rebase", "", 1, 1))
Alban Gruin393adf72019-11-24 18:43:32 +01006198 goto cleanup;
Alban Gruinb97e1872018-08-28 14:10:36 +02006199
Alban Gruin393adf72019-11-24 18:43:32 +01006200 todo_list_write_total_nr(&new_todo);
6201 res = pick_commits(r, &new_todo, opts);
6202
6203cleanup:
6204 todo_list_release(&new_todo);
6205
6206 return res;
Alban Gruinb97e1872018-08-28 14:10:36 +02006207}
6208
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006209struct subject2item_entry {
6210 struct hashmap_entry entry;
6211 int i;
6212 char subject[FLEX_ARRAY];
6213};
6214
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +02006215static int subject2item_cmp(const void *fndata UNUSED,
Eric Wong939af162019-10-06 23:30:37 +00006216 const struct hashmap_entry *eptr,
6217 const struct hashmap_entry *entry_or_key,
6218 const void *key)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006219{
Eric Wong939af162019-10-06 23:30:37 +00006220 const struct subject2item_entry *a, *b;
6221
6222 a = container_of(eptr, const struct subject2item_entry, entry);
6223 b = container_of(entry_or_key, const struct subject2item_entry, entry);
6224
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006225 return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);
6226}
6227
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006228define_commit_slab(commit_todo_item, struct todo_item *);
6229
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306230static int skip_fixupish(const char *subject, const char **p) {
Charvi Mendirattabae5b4a2021-01-29 23:50:49 +05306231 return skip_prefix(subject, "fixup! ", p) ||
6232 skip_prefix(subject, "amend! ", p) ||
6233 skip_prefix(subject, "squash! ", p);
6234}
6235
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006236/*
6237 * Rearrange the todo list that has both "pick commit-id msg" and "pick
6238 * commit-id fixup!/squash! msg" in it so that the latter is put immediately
6239 * after the former, and change "pick" to "fixup"/"squash".
6240 *
6241 * Note that if the config has specified a custom instruction format, each log
6242 * message will have to be retrieved from the commit (as the oneline in the
6243 * script cannot be trusted) in order to normalize the autosquash arrangement.
6244 */
Alban Gruin79d7e882019-03-05 20:17:59 +01006245int todo_list_rearrange_squash(struct todo_list *todo_list)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006246{
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006247 struct hashmap subject2item;
Alban Gruinf2a04902019-03-05 20:17:55 +01006248 int rearranged = 0, *next, *tail, i, nr = 0, alloc = 0;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006249 char **subjects;
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006250 struct commit_todo_item commit_todo;
Alban Gruinf2a04902019-03-05 20:17:55 +01006251 struct todo_item *items = NULL;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006252
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006253 init_commit_todo_item(&commit_todo);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006254 /*
6255 * The hashmap maps onelines to the respective todo list index.
6256 *
6257 * If any items need to be rearranged, the next[i] value will indicate
6258 * which item was moved directly after the i'th.
6259 *
6260 * In that case, last[i] will indicate the index of the latest item to
6261 * be moved to appear after the i'th.
6262 */
Eric Wong939af162019-10-06 23:30:37 +00006263 hashmap_init(&subject2item, subject2item_cmp, NULL, todo_list->nr);
Alban Gruinf2a04902019-03-05 20:17:55 +01006264 ALLOC_ARRAY(next, todo_list->nr);
6265 ALLOC_ARRAY(tail, todo_list->nr);
6266 ALLOC_ARRAY(subjects, todo_list->nr);
6267 for (i = 0; i < todo_list->nr; i++) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006268 struct strbuf buf = STRBUF_INIT;
Alban Gruinf2a04902019-03-05 20:17:55 +01006269 struct todo_item *item = todo_list->items + i;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006270 const char *commit_buffer, *subject, *p;
6271 size_t subject_len;
6272 int i2 = -1;
6273 struct subject2item_entry *entry;
6274
6275 next[i] = tail[i] = -1;
Johannes Schindelin2f6b1d12018-04-25 14:28:25 +02006276 if (!item->commit || item->command == TODO_DROP) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006277 subjects[i] = NULL;
6278 continue;
6279 }
6280
6281 if (is_fixup(item->command)) {
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006282 clear_commit_todo_item(&commit_todo);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006283 return error(_("the script was already rearranged."));
6284 }
6285
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02006286 repo_parse_commit(the_repository, item->commit);
6287 commit_buffer = repo_logmsg_reencode(the_repository,
6288 item->commit, NULL,
6289 "UTF-8");
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006290 find_commit_subject(commit_buffer, &subject);
6291 format_subject(&buf, subject, " ");
6292 subject = subjects[i] = strbuf_detach(&buf, &subject_len);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 15:58:48 +02006293 repo_unuse_commit_buffer(the_repository, item->commit,
6294 commit_buffer);
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306295 if (skip_fixupish(subject, &p)) {
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006296 struct commit *commit2;
6297
6298 for (;;) {
6299 while (isspace(*p))
6300 p++;
Charvi Mendiratta1f969602021-02-09 00:55:20 +05306301 if (!skip_fixupish(p, &p))
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006302 break;
6303 }
6304
Eric Wongf23a4652019-10-06 23:30:36 +00006305 entry = hashmap_get_entry_from_hash(&subject2item,
6306 strhash(p), p,
6307 struct subject2item_entry,
6308 entry);
6309 if (entry)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006310 /* found by title */
6311 i2 = entry->i;
6312 else if (!strchr(p, ' ') &&
6313 (commit2 =
6314 lookup_commit_reference_by_name(p)) &&
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006315 *commit_todo_item_at(&commit_todo, commit2))
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006316 /* found by commit name */
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006317 i2 = *commit_todo_item_at(&commit_todo, commit2)
Alban Gruinf2a04902019-03-05 20:17:55 +01006318 - todo_list->items;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006319 else {
6320 /* copy can be a prefix of the commit subject */
6321 for (i2 = 0; i2 < i; i2++)
6322 if (subjects[i2] &&
6323 starts_with(subjects[i2], p))
6324 break;
6325 if (i2 == i)
6326 i2 = -1;
6327 }
6328 }
6329 if (i2 >= 0) {
6330 rearranged = 1;
Charvi Mendirattabae5b4a2021-01-29 23:50:49 +05306331 if (starts_with(subject, "fixup!")) {
6332 todo_list->items[i].command = TODO_FIXUP;
6333 } else if (starts_with(subject, "amend!")) {
6334 todo_list->items[i].command = TODO_FIXUP;
6335 todo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;
6336 } else {
6337 todo_list->items[i].command = TODO_SQUASH;
6338 }
Johannes Schindelin02471e72020-05-09 19:23:39 +00006339 if (tail[i2] < 0) {
6340 next[i] = next[i2];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006341 next[i2] = i;
Johannes Schindelin02471e72020-05-09 19:23:39 +00006342 } else {
6343 next[i] = next[tail[i2]];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006344 next[tail[i2]] = i;
Johannes Schindelin02471e72020-05-09 19:23:39 +00006345 }
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006346 tail[i2] = i;
6347 } else if (!hashmap_get_from_hash(&subject2item,
6348 strhash(subject), subject)) {
6349 FLEX_ALLOC_MEM(entry, subject, subject, subject_len);
6350 entry->i = i;
Eric Wongd22245a2019-10-06 23:30:27 +00006351 hashmap_entry_init(&entry->entry,
6352 strhash(entry->subject));
Eric Wong26b455f2019-10-06 23:30:32 +00006353 hashmap_put(&subject2item, &entry->entry);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006354 }
Johannes Altmanninger3e367a52022-09-24 17:29:04 -05006355
6356 *commit_todo_item_at(&commit_todo, item->commit) = item;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006357 }
6358
6359 if (rearranged) {
Alban Gruinf2a04902019-03-05 20:17:55 +01006360 for (i = 0; i < todo_list->nr; i++) {
6361 enum todo_command command = todo_list->items[i].command;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006362 int cur = i;
6363
6364 /*
6365 * Initially, all commands are 'pick's. If it is a
6366 * fixup or a squash now, we have rearranged it.
6367 */
6368 if (is_fixup(command))
6369 continue;
6370
6371 while (cur >= 0) {
Alban Gruinf2a04902019-03-05 20:17:55 +01006372 ALLOC_GROW(items, nr + 1, alloc);
6373 items[nr++] = todo_list->items[cur];
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006374 cur = next[cur];
6375 }
6376 }
6377
Alban Gruinf2a04902019-03-05 20:17:55 +01006378 FREE_AND_NULL(todo_list->items);
6379 todo_list->items = items;
6380 todo_list->nr = nr;
6381 todo_list->alloc = alloc;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006382 }
6383
6384 free(next);
6385 free(tail);
Alban Gruinf2a04902019-03-05 20:17:55 +01006386 for (i = 0; i < todo_list->nr; i++)
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006387 free(subjects[i]);
6388 free(subjects);
Elijah Newren6da1a252020-11-02 18:55:05 +00006389 hashmap_clear_and_free(&subject2item, struct subject2item_entry, entry);
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006390
Nguyễn Thái Ngọc Duy3cc02872018-05-19 07:28:23 +02006391 clear_commit_todo_item(&commit_todo);
Alban Gruinf2a04902019-03-05 20:17:55 +01006392
6393 return 0;
Johannes Schindelinc44a4c62017-07-14 16:45:31 +02006394}
Phillip Wood901ba7b2019-12-06 16:06:11 +00006395
6396int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
6397{
Han-Wen Nienhuysc8e41592020-08-21 16:59:35 +00006398 if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
Phillip Wood430b75f2019-12-06 16:06:12 +00006399 struct object_id cherry_pick_head, rebase_head;
6400
6401 if (file_exists(git_path_seq_dir()))
6402 *whence = FROM_CHERRY_PICK_MULTI;
6403 if (file_exists(rebase_path()) &&
Ævar Arnfjörð Bjarmason4a93b892023-03-28 15:58:58 +02006404 !repo_get_oid(r, "REBASE_HEAD", &rebase_head) &&
6405 !repo_get_oid(r, "CHERRY_PICK_HEAD", &cherry_pick_head) &&
Phillip Wood430b75f2019-12-06 16:06:12 +00006406 oideq(&rebase_head, &cherry_pick_head))
6407 *whence = FROM_REBASE_PICK;
6408 else
6409 *whence = FROM_CHERRY_PICK_SINGLE;
6410
Phillip Wood901ba7b2019-12-06 16:06:11 +00006411 return 1;
6412 }
6413
6414 return 0;
6415}
Derrick Stoleeaa7f2fd2022-07-19 18:33:35 +00006416
6417int sequencer_get_update_refs_state(const char *wt_dir,
6418 struct string_list *refs)
6419{
6420 int result = 0;
6421 FILE *fp = NULL;
6422 struct strbuf ref = STRBUF_INIT;
6423 struct strbuf hash = STRBUF_INIT;
6424 struct update_ref_record *rec = NULL;
6425
6426 char *path = rebase_path_update_refs(wt_dir);
6427
6428 fp = fopen(path, "r");
6429 if (!fp)
6430 goto cleanup;
6431
6432 while (strbuf_getline(&ref, fp) != EOF) {
6433 struct string_list_item *item;
6434
6435 CALLOC_ARRAY(rec, 1);
6436
6437 if (strbuf_getline(&hash, fp) == EOF ||
6438 get_oid_hex(hash.buf, &rec->before)) {
6439 warning(_("update-refs file at '%s' is invalid"),
6440 path);
6441 result = -1;
6442 goto cleanup;
6443 }
6444
6445 if (strbuf_getline(&hash, fp) == EOF ||
6446 get_oid_hex(hash.buf, &rec->after)) {
6447 warning(_("update-refs file at '%s' is invalid"),
6448 path);
6449 result = -1;
6450 goto cleanup;
6451 }
6452
6453 item = string_list_insert(refs, ref.buf);
6454 item->util = rec;
6455 rec = NULL;
6456 }
6457
6458cleanup:
6459 if (fp)
6460 fclose(fp);
6461 free(path);
6462 free(rec);
6463 strbuf_release(&ref);
6464 strbuf_release(&hash);
6465 return result;
6466}