What Is the Difference Between `gh stack submit` and `gh stack push`?
gh stack push only synchronizes local branches to the remote repository, whereas gh stack submit performs that push operation and additionally creates or updates Pull Requests and the GitHub stack that groups them.
The github/gh-stack extension introduces structured branch management for GitHub CLI users. Understanding the difference between gh stack submit and gh stack push is essential for effective workflow management, as these commands serve distinct stages of the stacked pull request lifecycle.
Core Functional Differences
gh stack push: Remote Synchronization Only
This command focuses exclusively on moving local commits to the remote. According to the source code in cmd/push.go, its short description reads: Short: "Push active branches in the current stack to the remote" (lines 21-23).
The implementation in the runPush function (lines 81-115) performs the following:
- Identifies the active stack containing the current branch
- Skips branches marked as merged or queued
- Pushes remaining active branches using force-with-lease protection
- Updates the local stack file with new base SHAs
- Displays a hint suggesting
gh stack submitfor PR creation
Crucially, this command never changes the checked-out branch and does not interact with GitHub's PR or Stacks API.
gh stack submit: Full Stack Publication
Described in cmd/submit.go (lines 33-35) as Short: "Create a stack of PRs on GitHub", this command orchestrates complete stack publication.
The runSubmit function executes a multi-stage workflow:
- Performs all
pushoperations (pushing branches with force-with-lease) - Launches an interactive TUI (or runs in
--automode) for drafting PR titles, bodies, and draft status - Creates new PRs or updates base branches of existing ones
- Creates or updates the remote stack via the GitHub Stacks API, handling edge cases like adopting existing stacks or recovering from modify states
- Persists changes to the local stack file
Like push, it leaves the current checkout unchanged.
Source Code Architecture
The architectural separation is clear in the implementation files.
In cmd/push.go, the logic remains minimal:
func runPush(cfg *config.Config, opts *pushOptions) error {
// … load stack, discover active branches …
activeBranches := activeBranchNames(s)
// … fetch remote refs, then push with force‑with‑lease …
if err := git.Push(remote, activeBranches, true, false); err != nil { … }
// … update stored base SHAs and persist the stack file …
updateBaseSHAs(s)
if err := stack.Save(gitDir, sf); err != nil { … }
}
In contrast, cmd/submit.go (lines 27-31 and 47-52) extends this foundation:
func runSubmit(cfg *config.Config, opts *submitOptions) error {
// … load stack, resolve remote …
// 1️⃣ Push all branches (same logic as push)
// 2️⃣ Create or update PRs (ensurePR / createPR)
// 3️⃣ Update PR bases if needed
// 4️⃣ Create or update the remote stack (syncStack)
// … persist changes and report success …
}
When to Use Each Command
Use gh stack push when:
- You have rebased branches and need to update remote refs without opening PRs
- You want to resolve push conflicts before creating pull requests
- You need quick synchronization with
--force-with-leasesafety
Use gh stack submit when:
- You are ready to create the initial stack of PRs on GitHub
- You need to synchronize PR bases after adding new commits to the stack
- You want to use the interactive editor (
--autofor non-interactive) to customize PR titles and draft status
Command Examples
Push branches only after rebasing:
# Push active branches with force-with-lease protection
gh stack push
# Push to a specific remote
gh stack push --remote upstream
Submit the complete stack:
# Interactive mode with TUI for PR details
gh stack submit
# Auto-generated PR titles (non-interactive)
gh stack submit --auto
# Create PRs as ready for review (not drafts)
gh stack submit --open
Both commands can execute from any branch within a stack without changing your checkout.
Summary
gh stack pushperforms only remote branch synchronization using force-with-lease, updates local base SHAs, and skips merged branches.gh stack submitexecutes the push operation plus creates/updates PRs, manages PR base branches, and synchronizes the remote GitHub stack via API.- Neither command changes the currently checked-out branch.
- Push is ideal for syncing work-in-progress; submit is required for GitHub PR creation and stack management.
Frequently Asked Questions
Does gh stack submit run gh stack push automatically?
Yes. According to the implementation in cmd/submit.go, the submit command performs all push operations first—including the force-with-lease protected push and base SHA updates—before proceeding to PR and stack creation.
Can I use gh stack push to update existing PRs?
No. The push command only updates remote branch refs. It does not interact with the GitHub API or modify PR metadata, titles, or base branches. Use gh stack submit to update PR bases and metadata.
Will either command switch my current branch?
No. Both commands operate entirely on the stack file and remote refs without modifying your working directory checkout. You can run them from any branch within the stack.
What happens to merged branches when running these commands?
Both commands automatically skip branches that are marked as merged or queued. The active branch detection logic filters these out before pushing to the remote, ensuring you only synchronize relevant work-in-progress branches.
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 →