rebase: add --[no-]edit to --continue
Allow skipping the editor when continuing after resolving conflicts, via --no-edit or the rebase.noEdit configuration variable. The --edit option overrides rebase.noEdit when both are set. Signed-off-by: Hugo Sales <hugo@hsal.es> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Hugo Sales committed
Jul 21, 2026 at 15:04 UTC
179eccf0d01729c19a3238905b951b1880aa4ba1
5 files changed
+126
-7
Documentation/config/rebase.adoc
+6
@@ -62,6 +62,12 @@ instead of:
62
+
63
Defaults to false.
64
65
+rebase.noEdit::
66
+ When set to true, `git rebase --continue` uses the commit message
67
+ without launching $EDITOR, as if `--no-edit` were given. The
68
+ `--edit` option to `git rebase --continue` overrides this setting.
69
+ Defaults to false.
70
+
71
rebase.rescheduleFailedExec::
72
Automatically reschedule `exec` commands that failed. This only makes
73
sense in interactive mode (or when an `--exec` option was provided).
Documentation/git-rebase.adoc
+14
-3
@@ -181,6 +181,16 @@ including not with each other:
181
182
--continue::
183
Restart the rebasing process after having resolved a merge conflict.
184
++
185
+-e::
186
+--edit::
187
+--no-edit::
188
+ With `--continue`, edit or do not edit the commit message,
189
+ respectively. By default, the configured $EDITOR is opened so you
190
+ can update the commit message after resolving conflicts.
191
+ `--no-edit` reuses the existing message without launching an
192
+ editor. The `rebase.noEdit` configuration variable can be used to
193
+ enable `--no-edit` by default; `--edit` overrides that setting.
194
195
--skip::
196
Restart the rebasing process by skipping the current patch.
@@ -783,9 +793,10 @@ Commit Rewording
793
When a conflict occurs while rebasing, rebase stops and asks the user
794
to resolve. Since the user may need to make notable changes while
795
resolving conflicts, after conflicts are resolved and the user has run
786
-`git rebase --continue`, the rebase should open an editor and ask the
787
-user to update the commit message. The 'merge' backend does this, while
788
-the 'apply' backend blindly applies the original commit message.
796
+`git rebase --continue`, the rebase opens an editor and asks the
797
+user to update the commit message, unless `rebase.noEdit` is set or
798
+`--no-edit` is passed to `--continue`. The 'merge' backend does this,
799
+while the 'apply' backend blindly applies the original commit message.
800
801
Miscellaneous differences
802
~~~~~~~~~~~~~~~~~~~~~~~~~
builtin/rebase.c
+26
-3
@@ -43,7 +43,7 @@ static char const * const builtin_rebase_usage[] = {
43
"[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
44
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
45
"--root [<branch>]"),
46
- "git rebase --continue | --abort | --skip | --edit-todo",
46
+ "git rebase --continue [--[no-]edit] | --abort | --skip | --edit-todo",
47
NULL
48
};
49
@@ -135,6 +135,8 @@ struct rebase_options {
135
int config_autosquash;
136
int config_rebase_merges;
137
int config_update_refs;
138
+ int config_no_edit;
139
+ int edit;
140
};
141
142
#define REBASE_OPTIONS_INIT { \
@@ -156,6 +158,8 @@ struct rebase_options {
158
.update_refs = -1, \
159
.config_update_refs = -1, \
160
.strategy_opts = STRING_LIST_INIT_NODUP,\
161
+ .config_no_edit = -1, \
162
+ .edit = -1, \
163
}
164
165
static void rebase_options_release(struct rebase_options *opts)
@@ -215,6 +219,13 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
219
replay.have_squash_onto = 1;
220
}
221
222
+ if (opts->action == ACTION_CONTINUE) {
223
+ if (opts->edit >= 0)
224
+ replay.edit = opts->edit;
225
+ else if (opts->config_no_edit > 0)
226
+ replay.edit = 0;
227
+ }
228
+
229
return replay;
230
}
231
@@ -839,6 +850,11 @@ static int rebase_config(const char *var, const char *value,
850
return 0;
851
}
852
853
+ if (!strcmp(var, "rebase.noedit")) {
854
+ opts->config_no_edit = git_config_bool(var, value);
855
+ return 0;
856
+ }
857
+
858
if (!strcmp(var, "rebase.forkpoint")) {
859
opts->fork_point = git_config_bool(var, value) ? -1 : 0;
860
return 0;
@@ -1168,6 +1184,8 @@ int cmd_rebase(int argc,
1184
ACTION_CONTINUE),
1185
OPT_CMDMODE(0, "skip", &options.action,
1186
N_("skip current patch and continue"), ACTION_SKIP),
1187
+ OPT_BOOL('e', "edit", &options.edit,
1188
+ N_("edit the commit message")),
1189
OPT_CMDMODE(0, "abort", &options.action,
1190
N_("abort and check out the original branch"),
1191
ACTION_ABORT),
@@ -1308,10 +1326,15 @@ int cmd_rebase(int argc,
1326
"which is no longer supported; use 'merges' instead"));
1327
1328
if (options.action != ACTION_NONE && total_argc != 2) {
1311
- usage_with_options(builtin_rebase_usage,
1312
- builtin_rebase_options);
1329
+ if (options.action != ACTION_CONTINUE ||
1330
+ options.edit < 0 || total_argc != 3)
1331
+ usage_with_options(builtin_rebase_usage,
1332
+ builtin_rebase_options);
1333
}
1334
1335
+ if (options.edit >= 0 && options.action != ACTION_CONTINUE)
1336
+ die(_("--edit and --no-edit can only be used with --continue"));
1337
+
1338
if (argc > 2)
1339
usage_with_options(builtin_rebase_usage,
1340
builtin_rebase_options);
sequencer.c
+28
-1
@@ -2211,6 +2211,25 @@ static int should_edit(struct replay_opts *opts) {
2211
return opts->edit;
2212
}
2213
2214
+static int should_edit_rebase_continue(struct replay_opts *opts)
2215
+{
2216
+ if (opts->edit < 0)
2217
+ return 1;
2218
+ return opts->edit;
2219
+}
2220
+
2221
+static void finalize_continue_edit_flags(struct replay_opts *opts,
2222
+ unsigned int *flags)
2223
+{
2224
+ if (*flags & CLEANUP_MSG)
2225
+ return;
2226
+
2227
+ if (should_edit_rebase_continue(opts))
2228
+ *flags |= EDIT_MSG;
2229
+ else
2230
+ *flags &= ~EDIT_MSG;
2231
+}
2232
+
2233
static void refer_to_commit(struct repository *r, struct strbuf *msgbuf,
2234
const struct commit *commit,
2235
bool use_commit_reference)
@@ -5261,7 +5280,7 @@ static int commit_staged_changes(struct repository *r,
5280
struct todo_list *todo_list)
5281
{
5282
struct replay_ctx *ctx = opts->ctx;
5264
- unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
5283
+ unsigned int flags = ALLOW_EMPTY;
5284
unsigned int final_fixup = 0, is_clean;
5285
struct strbuf rev = STRBUF_INIT;
5286
const char *reflog_action = reflog_message(opts, "continue", NULL);
@@ -5426,6 +5445,8 @@ static int commit_staged_changes(struct repository *r,
5445
}
5446
}
5447
5448
+ finalize_continue_edit_flags(opts, &flags);
5449
+
5450
if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
5451
reflog_action, opts, flags)) {
5452
ret = error(_("could not commit staged changes."));
@@ -5483,6 +5504,12 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
5504
res = -1;
5505
goto release_todo_list;
5506
}
5507
+
5508
+ /*
5509
+ * Command-line --[no-]edit applies only to this
5510
+ * --continue invocation, not to subsequent picks.
5511
+ */
5512
+ opts->edit = -1;
5513
} else if (!file_exists(get_todo_path(opts)))
5514
return continue_single_pick(r, opts);
5515
else if ((res = read_populate_todo(r, &todo_list, opts)))
t/t3436-rebase-more-options.sh
+52
@@ -201,6 +201,58 @@ test_expect_success '--ignore-date is an alias for --reset-author-date' '
201
test_atime_is_ignored -2
202
'
203
204
+test_expect_success '--no-edit on continue uses existing commit message' '
205
+ git checkout commit2 &&
206
+ test_must_fail git rebase -m --onto commit2^^ commit2^ &&
207
+ echo resolved >foo &&
208
+ git add foo &&
209
+ write_script fail-if-editor-invoked <<-\EOF &&
210
+ echo editor invoked >&2
211
+ exit 1
212
+ EOF
213
+ GIT_EDITOR=./fail-if-editor-invoked git rebase --continue --no-edit &&
214
+ git log --format=%s -1 >actual &&
215
+ echo commit2 >expect &&
216
+ test_cmp expect actual
217
+'
218
+
219
+test_expect_success '--no-edit cannot be used when starting a rebase' '
220
+ test_must_fail git rebase --no-edit -m main side 2>err &&
221
+ test_grep "only be used with --continue" err
222
+'
223
+
224
+test_expect_success 'rebase.noEdit skips editor on continue' '
225
+ git config rebase.noEdit true &&
226
+ git checkout commit2 &&
227
+ test_must_fail git rebase -m --onto commit2^^ commit2^ &&
228
+ echo resolved >foo &&
229
+ git add foo &&
230
+ write_script fail-if-editor-invoked <<-\EOF &&
231
+ echo editor invoked >&2
232
+ exit 1
233
+ EOF
234
+ GIT_EDITOR=./fail-if-editor-invoked git rebase --continue &&
235
+ git log --format=%s -1 >actual &&
236
+ echo commit2 >expect &&
237
+ test_cmp expect actual
238
+'
239
+
240
+test_expect_success '--edit on continue overrides rebase.noEdit' '
241
+ git config rebase.noEdit true &&
242
+ git checkout commit2 &&
243
+ test_must_fail git rebase -m --onto commit2^^ commit2^ &&
244
+ echo resolved >foo &&
245
+ git add foo &&
246
+ (
247
+ set_fake_editor &&
248
+ FAKE_COMMIT_MESSAGE="edited on continue" \
249
+ git rebase --continue --edit
250
+ ) &&
251
+ test_write_lines "edited on continue" "" >expect &&
252
+ git log --format=%B -1 >actual &&
253
+ test_cmp expect actual
254
+'
255
+
256
# This must be the last test in this file
257
test_expect_success '$EDITOR and friends are unchanged' '
258
test_editor_unchanged