Summary
When a stack branch's branch.<name>.remote is . (the local repository), gh stack push resolves the push remote to an empty string, pushes nothing, and reports success:
$ gh stack push
Pushing 2 branches to ....
✓ Pushed 2 branches
To create PRs for this stack, run `gh stack submit`
$ git ls-remote --heads origin | grep probe
# nothing — no ref was created
Note the blank remote name between "to" and the ellipsis. Exit status is 0.
gh stack submit then fails PR creation, but the error describes a state problem rather than the push failure that caused it, and the run still ends on a success line:
$ gh stack submit --auto
Checking stack state...
Pushing to ....
⚠ failed to create PR for probe-one: creating PR: GraphQL: Head sha can't be blank,
Base sha can't be blank, No commits between main and probe-one,
Head ref must be a branch (createPullRequest)
✓ Pushed and synced 2 branches
This is a single-remote repository. origin is the only remote, and it is correct.
Root cause
branch.<name>.remote = . is a normal git configuration meaning "the upstream is a local branch". Anyone with branch.autoSetupMerge = always in their git config gets it automatically on every git switch -c from a local branch — which is exactly how a stack is built, so every branch in the stack has it.
Remote auto-detection appears to read branch.<name>.remote, find ., and yield an empty remote name rather than falling back to the single remote / origin.
Isolated by toggling it:
branch.autoSetupMerge |
branch.<name>.remote |
gh stack push |
branches pushed |
always |
. |
Pushing 2 branches to .... |
0 |
| unset |
unset |
Pushing 2 branches to origin... |
2 |
Also fixed by setting remote.pushDefault = origin; unsetting it reproduces the failure again, deterministically.
Reproduction
git config --global branch.autoSetupMerge always # or set it locally
git switch main
git switch -c probe-one && echo p1 > p1.txt && git add . && git commit -m "p1"
git switch -c probe-two && echo p2 > p2.txt && git add . && git commit -m "p2"
git switch probe-one
git config --get branch.probe-one.remote # -> .
gh stack init probe-one probe-two
gh stack push # "Pushing 2 branches to ...." / "✓ Pushed 2 branches"
git ls-remote --heads origin | grep probe # -> nothing
Public repo with two stacks set up for this: https://github.com/xn/gh-stack-repro
Expected
- Fail loudly when the push remote cannot be resolved, rather than pushing to an empty remote name.
- Never print
✓ Pushed N branches unless refs actually moved — report per-branch results, and exit non-zero when nothing was pushed.
- Treat
branch.<name>.remote = . as "no usable remote for this branch" and fall back to the single remote / origin / remote.pushDefault.
Workaround
gh stack push --remote origin, or git config remote.pushDefault origin.
Environment
gh 2.97.0
gh-stack v0.1.0
- git 2.50.1
- macOS 26.4.1, darwin/arm64
Related
Same GraphQL error signature as #219 and #381, but a different root cause — those are about which repository the API calls target in multi-remote/fork clones. This one is a single-remote clone where the push target itself resolves to empty and no ref is ever created. #45 is a third variant (SSH host alias); ruled out here — the failure reproduces with a plain https:// remote and a pristine global config.
Summary
When a stack branch's
branch.<name>.remoteis.(the local repository),gh stack pushresolves the push remote to an empty string, pushes nothing, and reports success:Note the blank remote name between "to" and the ellipsis. Exit status is 0.
gh stack submitthen fails PR creation, but the error describes a state problem rather than the push failure that caused it, and the run still ends on a success line:This is a single-remote repository.
originis the only remote, and it is correct.Root cause
branch.<name>.remote = .is a normal git configuration meaning "the upstream is a local branch". Anyone withbranch.autoSetupMerge = alwaysin their git config gets it automatically on everygit switch -cfrom a local branch — which is exactly how a stack is built, so every branch in the stack has it.Remote auto-detection appears to read
branch.<name>.remote, find., and yield an empty remote name rather than falling back to the single remote /origin.Isolated by toggling it:
branch.autoSetupMergebranch.<name>.remotegh stack pushalways.Pushing 2 branches to ....Pushing 2 branches to origin...Also fixed by setting
remote.pushDefault = origin; unsetting it reproduces the failure again, deterministically.Reproduction
Public repo with two stacks set up for this: https://github.com/xn/gh-stack-repro
Expected
✓ Pushed N branchesunless refs actually moved — report per-branch results, and exit non-zero when nothing was pushed.branch.<name>.remote = .as "no usable remote for this branch" and fall back to the single remote /origin/remote.pushDefault.Workaround
gh stack push --remote origin, orgit config remote.pushDefault origin.Environment
gh2.97.0gh-stackv0.1.0Related
Same GraphQL error signature as #219 and #381, but a different root cause — those are about which repository the API calls target in multi-remote/fork clones. This one is a single-remote clone where the push target itself resolves to empty and no ref is ever created. #45 is a third variant (SSH host alias); ruled out here — the failure reproduces with a plain
https://remote and a pristine global config.