Renaming a stacked branch with `git branch -m` strands the stack: metadata keeps the old name
- Ngôn ngữ chính
- Go
- Star
- 1.5k
- Fork
- 70
- Merge trung bình
- 1 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 7
Mô tả
### Summary
`gh stack` matches the current branch against `.git/gh-stack` by exact string
(`resolveStack` → `FindAllStacksForBranch` → `Stack.Contains`, cmd/utils.go:395,
internal/stack/stack.go:241). Renaming a stacked branch with `git branch -m` is not
observed, so the stack file keeps pointing at a name that no longer exists and every
stack command bails out with the same generic message.
`gh stack modify` already renames a branch in git and in the stack file together
(internal/modify/apply.go:190-228, verified: both `.git/gh-stack` and the git branch are
updated), so the invariant is understood. This issue is about a rename performed outside
gh-stack, which is how most people rename a branch.
Related but distinct: #137 reaches the same stranded state through `sync --prune`
(branch deleted, stack entry left behind), and #193 is the same family of "git operations
performed outside gh-stack aren't observed".
### Reproduction
Requires an `origin` remote, but the repository need not exist.
```sh
git init repro && cd repro
git commit --allow-empty -m initial
git remote add origin https://github.com/you/does-not-exist.git
git switch -c feat/test
git commit --allow-empty -m wip
gh stack init feat/test # ✓ Adopted 1 branch: main ← feat/test
gh stack view --short # ✓ works
git branch -m feat/test-1
gh stack view # ✗ broken from here on
```
`gh stack init` with no arguments errors with "interactive input required", so the branch
name is passed explicitly to keep the repro scriptable.
### Observed
`.git/gh-stack` is byte-identical before and after the rename; it still records
`"branch": "feat/test"`.
| Command | Output |
| --- | --- |
| `gh stack view` | `✗ current branch "feat/test-1" is not part of a stack` |
| `gh stack add feat/test-2` | same |
| `gh stack unstack` / `unstack --local` | same |
| `gh stack checkout feat/test` (old name) | `✗ failed to checkout feat/test: failed to run git: error: pathspec 'feat/test' did not match any file(s) known to git` |
| `gh stack checkout feat/test-1` (new name) | `✗ no locally tracked stack found for "feat/test-1"` |
`gh stack unstack --local` would remove the entry, but a stack that has not been
submitted has no stack number (`Number int \`json:"number,omitempty"\``,
internal/stack/stack.go:46), so it cannot be targeted:
```
$ gh stack unstack 1 --local
✗ stack #1 is not tracked locally
```
With no `gh stack list` (#150) and an interactive-only checkout picker, the ways out are
renaming the branch back (verified: this fully restores the stack) or editing
`.git/gh-stack` by hand.
### Expected
1. **Diagnose instead of denying.** Before printing "is not part of a stack"
(cmd/utils.go:234-243), check whether a recorded stack references a branch that no
longer exists. `git.BranchExists` is already used throughout (cmd/sync.go:413,
cmd/modify.go:315, …). `checkout` should also stop surfacing git's raw
`pathspec ... did not match` error.
2. **Leave an escape hatch.** Removing or repairing a stack whose branches are missing
should not require a stack number — this is the part #137 also runs into.
3. **Offer to repair.** git records the rename in the reflog:
```
feat/test-1@{0}: Branch: renamed refs/heads/feat/test to refs/heads/feat/test-1
```
so the stack file can be updated after confirming with the user. Reflog entries expire,
so this complements 1 rather than replacing it.
I have a patch implementing 1 and 3 and will open a PR referencing this issue.
### Environment
- `gh stack` v0.1.0
- macOS 24.6.0 (Darwin, arm64)
Hướng dẫn đóng góp
Hướng nghiên cứu
Bắt đầu trong cmd/utils.go với lỗi về branch hiện tại, sau đó lần theo resolveStack, FindAllStacksForBranch và Stack.Contains trong internal/stack/stack.go. Xem lại việc sử dụng git.BranchExists và xử lý việc đổi tên trong internal/modify/apply.go, bao gồm cả cơ chế sửa chữa dựa trên reflog được mô tả trong issue. Công việc hoàn tất khi một branch bị đổi tên bên ngoài được chẩn đoán và có thể được sửa chữa hoặc xóa mà không cần số stack.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- git, go
- Lĩnh vực
- cli, developer-experience
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 35/100