You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(restack): pass --update-refs to git rebase by default (#119)
All rebase invocations now pass `--update-refs` or `--no-update-refs`
explicitly so that the flag always overrides any ambient `rebase.updateRefs`
git config setting.
- Untracked bookmark branches pointing into the rebased chain are kept in
sync automatically (default behaviour via `--update-refs`).
- Adds `--no-update-refs` flag to `restack`, `submit`, and `sync` as
a per-invocation escape hatch for users who want to preserve bookmark
branches.
- When linked worktrees are detected (`--worktrees` with at least one
branch actually checked out elsewhere), `--update-refs` is suppressed
automatically. Git silently skips refs checked out in other worktrees
rather than refusing, which would corrupt the stack with no warning.
- The resolved setting is persisted to cascade state so `gh stack
continue` resumes remaining branches with the same behaviour after a
conflict.
- Adds a cached Git version check (requires 2.38+) with a clear error
message when the requirement is not met.
Closes#112.
|`--no-restack`| Skip restacking branches (might not work well!) |
328
-
|`-D, --dry-run`| Show what would be done |
329
-
|`-w, --worktrees`| Rebase branches checked out in linked worktrees in-place |
332
+
|`--no-restack`| Skip restacking branches (might not work well!) |
333
+
|`-D, --dry-run`| Show what would be done |
334
+
|`-w, --worktrees`| Rebase branches checked out in linked worktrees in-place |
335
+
|`--no-update-refs`| Do not pass `--update-refs` to git (preserves untracked bookmark branches) |
330
336
331
337
### undo
332
338
@@ -371,6 +377,10 @@ If a rebase conflict occurs in a worktree branch, **gh-stack** will tell you whi
371
377
>
372
378
> The `--worktrees` flag is opt-in. Without it, **gh-stack** behaves exactly as before. If none of your stack branches are checked out in linked worktrees, the flag is a harmless no-op.
373
379
380
+
> [!NOTE]
381
+
>
382
+
> When linked worktrees are detected, **gh-stack** automatically passes `--no-update-refs` to git. This prevents silent stack corruption: git's `--update-refs` silently skips any ref that is checked out in a linked worktree, which would leave the chain in a broken state. If no branches are checked out in linked worktrees (even with `--worktrees` set), **gh-stack** passes `--update-refs` normally so that any untracked bookmark branches pointing into the stack are kept in sync.
383
+
374
384
## How It Works
375
385
376
386
**gh-stack** stores metadata in your local `.git/config`:
Copy file name to clipboardExpand all lines: cmd/restack.go
+31-12Lines changed: 31 additions & 12 deletions
Original file line number
Diff line number
Diff line change
@@ -27,15 +27,17 @@ var restackCmd = &cobra.Command{
27
27
}
28
28
29
29
var (
30
-
restackOnlyFlagbool
31
-
restackDryRunFlagbool
32
-
restackWorktreesFlagbool
30
+
restackOnlyFlagbool
31
+
restackDryRunFlagbool
32
+
restackWorktreesFlagbool
33
+
restackNoUpdateRefsFlagbool
33
34
)
34
35
35
36
funcinit() {
36
37
restackCmd.Flags().BoolVarP(&restackOnlyFlag, "current", "c", false, "only restack current branch, not descendants")
37
38
restackCmd.Flags().BoolVarP(&restackDryRunFlag, "dry-run", "D", false, "show what would be done")
38
39
restackCmd.Flags().BoolVarP(&restackWorktreesFlag, "worktrees", "w", false, "rebase branches checked out in linked worktrees in-place")
40
+
restackCmd.Flags().BoolVar(&restackNoUpdateRefsFlag, "no-update-refs", false, "do not pass --update-refs to git (preserves untracked bookmark branches pointing into the stack)")
Copy file name to clipboardExpand all lines: cmd/submit.go
+17-14Lines changed: 17 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -38,13 +38,14 @@ If a rebase conflict occurs, resolve it and run 'gh stack continue'.`,
38
38
}
39
39
40
40
var (
41
-
submitDryRunFlagbool
42
-
submitCurrentOnlyFlagbool
43
-
submitUpdateOnlyFlagbool
44
-
submitPushOnlyFlagbool
45
-
submitYesFlagbool
46
-
submitWebFlagbool
47
-
submitFromFlagstring
41
+
submitDryRunFlagbool
42
+
submitCurrentOnlyFlagbool
43
+
submitUpdateOnlyFlagbool
44
+
submitPushOnlyFlagbool
45
+
submitYesFlagbool
46
+
submitWebFlagbool
47
+
submitFromFlagstring
48
+
submitNoUpdateRefsFlagbool
48
49
)
49
50
50
51
// prAction describes what we will do for a branch in the PR phase after push.
@@ -86,6 +87,7 @@ func init() {
86
87
submitCmd.Flags().BoolVar(&submitWebFlag, "web", false, "open created/updated PRs in web browser")
87
88
submitCmd.Flags().StringVarP(&submitFromFlag, "from", "f", "", "submit from this branch toward leaves (default: entire stack; bare --from = current branch)")
submitCmd.Flags().BoolVar(&submitNoUpdateRefsFlag, "no-update-refs", false, "do not pass --update-refs to git (preserves untracked bookmark branches pointing into the stack)")
syncCmd.Flags().BoolVarP(&syncDryRunFlag, "dry-run", "D", false, "show what would be done")
36
37
syncCmd.Flags().BoolVarP(&syncWorktreesFlag, "worktrees", "w", false, "rebase branches checked out in linked worktrees in-place")
38
+
syncCmd.Flags().BoolVar(&syncNoUpdateRefsFlag, "no-update-refs", false, "do not pass --update-refs to git (preserves untracked bookmark branches pointing into the stack)")
0 commit comments