gh stack unstack --local vs Regular unstack: What's the Difference?
The --local flag forces gh stack unstack to only remove the stack entry from your local .git/gh-stack file without contacting GitHub, while the default command orchestrates a coordinated removal from both the remote GitHub Stacks API and local tracking.
The gh-stack extension for the GitHub CLI provides powerful stack management capabilities for pull request workflows. When you need to dissolve a stack, understanding the difference between gh stack unstack --local and the regular unstack command is crucial for maintaining repository hygiene. This guide examines the implementation details in the github/gh-stack repository to explain exactly how these two modes diverge in their remote API interactions and local file system behavior.
How the Regular unstack Command Works
The standard gh stack unstack command follows a remote-first dissolution strategy. According to the implementation in cmd/unstack.go, the command first attempts to contact the GitHub Stacks API via client.Unstack to dissolve the remote stack representation.
This operation includes safety checks: if some pull requests are queued for merge or have auto-merge enabled, the remote stack cannot be fully dissolved. In these cases, the command preserves the local tracking entry so you can continue working with the still-existing remote stack.
Only after successfully dissolving the remote stack does the command remove the entry from your local .git/gh-stack file using sf.RemoveStack. This ensures your local state remains synchronized with GitHub's representation.
Handling Untracked Stack Numbers
When you provide a specific stack number that isn't tracked in your local file, the regular command falls back to runRemoteUnstack. This function performs a remote-first lookup and unstack operation, allowing you to dissolve stacks that exist on GitHub but may have been created on another machine.
How unstack --local Changes the Behavior
Adding the --local flag fundamentally restricts the command to your local file system. In cmd/unstack.go, the code path checks this flag early and bypasses all GitHub API calls entirely.
Instead of runRemoteUnstack, the command uses lookupStackByNumber with the local-only constraint. If the stack isn't found in your local .git/gh-stack file, the operation aborts immediately with an error message stating the stack is not tracked locally. The flag explicitly prevents the fallback to remote lookups that the standard command employs.
With --local, the stack entry is simply deleted from the local JSON file using the same sf.RemoveStack method, but the remote stack on GitHub remains completely untouched and continues to exist independently of your local repository state.
Key Differences at a Glance
- Remote API Interaction: The regular command calls the GitHub Stacks API via
client.Unstackto dissolve remote stacks, while--localnever contacts GitHub. - Local Tracking Removal: Both modes eventually call
sf.RemoveStack, but the regular command only does so after successful remote dissolution, whereas--localoperates immediately on the local file. - Partial Unstack Handling: The regular command preserves local tracking when remote dissolution fails (due to queued PRs or auto-merge), allowing continued interaction with the remote stack. With
--local, no remote check occurs, meaning the remote stack persists unchanged while local tracking disappears. - Missing Stack Behavior: Without the flag, untracked stack numbers trigger a remote lookup via
runRemoteUnstack. With--local, missing local entries produce an immediate error.
Practical Code Examples
Remove the current stack both locally and on GitHub:
gh stack unstack
Remove a specific stack by number, coordinating remote and local removal:
gh stack unstack 7
Remove only the local tracking while preserving the GitHub stack:
gh stack unstack --local
Attempt to locally unstack a number not tracked locally (this fails):
gh stack unstack --local 9
# Error: stack #9 is not tracked locally
Implementation Details in the Source Code
The logic divergence resides primarily in cmd/unstack.go. The runRemoteUnstack function (lines 68-81) encapsulates the remote-first approach, calling the GitHub API client defined in internal/github/client_interface.go before manipulating local state.
When --local is passed, the code bypasses runRemoteUnstack and instead relies on lookupStackByNumber with strict local constraints (lines 82-88). The local stack file operations are handled by internal/stack/stack.go, which provides the RemoveStack method used in both code paths.
The command also respects modify session guards via internal/modify/state.go, ensuring no active modification session exists before allowing unstack operations in either mode.
Summary
- Regular
unstack: Coordinates removal from GitHub via API first, then cleans local.git/gh-stackfile; handles partial dissolutions by preserving local tracking when remote removal fails. unstack --local: Restricts operation to local file only, never contacting GitHub; fails immediately if the stack isn't tracked locally.- Both commands use
sf.RemoveStackfrominternal/stack/stack.gofor local file manipulation. - The regular command supports remote fallback for untracked stack numbers via
runRemoteUnstack, while--localenforces strict local presence requirements.
Frequently Asked Questions
Does gh stack unstack --local delete the stack on GitHub?
No. The --local flag explicitly prevents any GitHub API calls. According to the implementation in cmd/unstack.go, this mode only manipulates the local .git/gh-stack file using sf.RemoveStack, leaving the remote stack intact and accessible through the GitHub web interface or other API clients.
What happens if I run unstack --local on a stack number that exists only on GitHub?
The command aborts with an error. When --local is specified, the code strictly enforces local presence through lookupStackByNumber. If the stack number isn't found in your local tracking file, you receive a "stack #N is not tracked locally" error, unlike the regular command which would fall back to remote operations.
Why would I use the regular unstack instead of --local?
Use the regular command when you want to fully dissolve a stack and remove it from both GitHub and your local tracking. This ensures consistency between your local state and the remote repository, and respects GitHub's constraints regarding queued or auto-merging pull requests by preserving local tracking if remote dissolution fails.
Can I recover a stack after running unstack --local?
Yes, but only the local tracking entry is gone. Since the --local flag never touches the GitHub Stacks API, the remote stack remains fully intact on GitHub. You can re-establish local tracking by fetching the stack information again, assuming you know the stack number or can locate it in the GitHub UI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →