Skip to content

Commit cd14979

Browse files
authored
commit amend: Detect rebase with unresolved conflicts (#710)
If commit amend is called during a rebase operation with unresolved conflicts, the user probably didn't want to do that. Offer to abort the operation. Resolves #700
1 parent 2983c40 commit cd14979

File tree

4 files changed

+122
-3
lines changed

4 files changed

+122
-3
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
kind: Changed
22
body: >-
33
commit amend:
4-
To prevent mistakes, when 'gs commit amend' is called from the trunk branch,
5-
confirm user intent, providing an option to create a new branch instead.
4+
Confirm user intent when called from the trunk branch,
5+
providing an option to create a new branch instead.
6+
This prevents accidental changes to the trunk branch.
67
time: 2025-06-22T15:24:32.431866-07:00
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Changed
2+
body: >-
3+
commit amend:
4+
Confirm user intent when called during a rebase operation with unresolved conflicts.
5+
This prevents accidental amendments that could complicate the rebase process.
6+
time: 2025-06-22T16:57:42.741195-07:00

commit_amend.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,58 @@ func (cmd *commitAmendCmd) Run(
119119
}
120120
}
121121

122+
// Check if we're in the middle of a rebase with unmerged paths
123+
var rebasing bool
124+
if _, err := wt.RebaseState(ctx); err == nil {
125+
rebasing = true
126+
127+
// If we're in the middle of a rebase,
128+
// and there are unmerged paths,
129+
// what the user likely wants is 'git add' and 'gs rebase continue'.
130+
//
131+
// (If there are no unmerged paths, amending is fine.)
132+
var numUnmerged int
133+
for _, err := range wt.ListFilesPaths(ctx, &git.ListFilesOptions{Unmerged: true}) {
134+
if err == nil {
135+
numUnmerged++
136+
}
137+
}
138+
139+
if numUnmerged > 0 {
140+
if !ui.Interactive(view) {
141+
log.Warnf("You are in the middle of a rebase with unmerged paths.")
142+
log.Warnf(`You probably want resolve the conflicts and run "git add", then "gs rebase continue" instead.`)
143+
} else {
144+
var continueAmend bool
145+
fields := []ui.Field{
146+
ui.NewList[bool]().
147+
WithTitle("Do you want to amend the commit?").
148+
WithDescription("You are in the middle of a rebase with unmerged paths.\n"+
149+
"You might want to resolve the conflicts and run 'git add', then 'gs rebase continue' instead.").
150+
WithItems(
151+
ui.ListItem[bool]{
152+
Title: "Yes",
153+
Description: func(bool) string { return "Continue with commit amend" },
154+
Value: true,
155+
},
156+
ui.ListItem[bool]{
157+
Title: "No",
158+
Description: func(bool) string { return "Abort the operation" },
159+
Value: false,
160+
},
161+
).
162+
WithValue(&continueAmend),
163+
}
164+
if err := ui.Run(view, fields...); err != nil {
165+
return fmt.Errorf("run prompt: %w", err)
166+
}
167+
if !continueAmend {
168+
return errors.New("operation aborted")
169+
}
170+
}
171+
}
172+
}
173+
122174
if err := wt.Commit(ctx, git.CommitRequest{
123175
Message: cmd.Message,
124176
AllowEmpty: cmd.AllowEmpty,
@@ -130,7 +182,7 @@ func (cmd *commitAmendCmd) Run(
130182
return fmt.Errorf("commit: %w", err)
131183
}
132184

133-
if _, err := wt.RebaseState(ctx); err == nil {
185+
if rebasing {
134186
log.Debug("A rebase is in progress, skipping restack")
135187
return nil
136188
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# commit amend during rebase with unmerged paths should suggest 'git add'
2+
3+
as 'Test <[email protected]>'
4+
at '2025-06-22T21:28:29Z'
5+
6+
cd repo
7+
git init
8+
git commit --allow-empty -m 'Initial commit'
9+
gs repo init
10+
11+
# Create a conflict scenario.
12+
git add conflict.txt
13+
gs branch create feature -m 'Add conflict.txt with content A'
14+
15+
gs trunk
16+
mv conflict-main.txt conflict.txt
17+
git add conflict.txt
18+
git commit -m 'Add conflict.txt with content B'
19+
20+
gs bco feature
21+
! gs branch restack
22+
23+
# Interactive mode should prompt with suggestion to run 'git add'
24+
env ROBOT_INPUT=$WORK/golden/robot.txt ROBOT_OUTPUT=$WORK/robot.actual
25+
26+
! gs commit amend --no-edit -a -m 'Another amend attempt'
27+
cmp $WORK/robot.actual $WORK/golden/robot.txt
28+
29+
git status --porcelain
30+
cmp stdout $WORK/golden/status-conflicted.txt
31+
32+
cp $WORK/other/conflict-resolved.txt conflict.txt
33+
git add conflict.txt
34+
gs rebase continue --no-edit
35+
36+
git graph --branches
37+
cmp stdout $WORK/golden/graph-after-rebase.txt
38+
39+
-- repo/conflict.txt --
40+
Content A
41+
-- repo/conflict-main.txt --
42+
Content B
43+
-- other/conflict-resolved.txt --
44+
Content A and B
45+
-- golden/robot.txt --
46+
===
47+
> Do you want to amend the commit?:
48+
> ▶ Yes
49+
> Continue with commit amend
50+
> No
51+
> Abort the operation
52+
> You are in the middle of a rebase with unmerged paths.
53+
> You might want to resolve the conflicts and run 'git add', then 'gs rebase continue' instead.
54+
"No"
55+
-- golden/status-conflicted.txt --
56+
AA conflict.txt
57+
-- golden/graph-after-rebase.txt --
58+
* f8fc3c9 (HEAD -> feature) Add conflict.txt with content A
59+
* 2f55407 (main) Add conflict.txt with content B
60+
* f8331be Initial commit

0 commit comments

Comments
 (0)