Merging stacked change requests¶
Experimental feature
Stack merging is experimental.
You must enable the merge experiment
before using the merge commands.
git config spice.experiment.merge true
git-spice can merge submitted Change Requests (CRs) from the command line. For stacked CRs, git-spice merges them bottom-up: merging CRs at the bottom of the stack, restacking and resubmitting their upstack as needed until all CRs have been merged.
Merging: 2 of 5 changes
■■■■■■■■■■■■■■■■■■■■◆◆◆◆◆◆◆◆◆◆××××××××××□□□□□□□□□□
merged: 2 waiting: 1 pending: 1 failed: 1
Press Ctrl-C to cancel merge operation.
Why does git-spice need to restack while merging?
Many repositories merge CRs with squash-merges. These replace commits in the merged branch with new commits on trunk. Git does not consider the new commit equivalent to the originals, so branches upstack from the merged branch point to a stale history. These need to be retargeted to trunk, restacked, and updated before they can merge.
See also Squash-merges restack the upstack to read more about the underlying limitation.
Merge commands¶
Use
$ gs branch checkout feat1
$ gs branch merge
# merges feat1 into mainTo merge a branch and all its downstack branches down to trunk
use
$ gs branch checkout feat2
$ gs downstack merge
# merges feat1, feat2 into mainTo merge a branch, all its downstack branches, and all upstack branches
use
$ gs branch checkout feat2
$ gs stack merge
# merges feat1, feat2, feat3, feat4 into mainWhen is a CR ready to merge?¶
Before git-spice requests a merge, it waits for the CR to be ready.
By default, the definition of "ready to merge" for a CR depends on the forge and repository settings. This can include CI checks, required approvals, or other requirements.
git-spice will poll the forge until the CR is reported as mergeable,
waiting up to 30 minutes for the CR to become ready.
The wait time can be changed
with the
If a CR is not ready to merge after the configured timeout, that CR is assumed to be blocked and it, and its upstack branches, will not be merged.
Custom merge readiness¶
If a repository's configured definition of "ready to merge" is not sufficient,
git-spice offers a
If set, git-spice will run the configured command to poll for a CR's readiness. The configuration value can be set to a shell command or a script/executable.
Its exit status determines whether the CR is ready to merge:
- exit status
0means the CR is ready - exit status
1means git-spice should try again later - exit status
2means the CR is blocked and waiting won't help; the CR and its upstack branches will not be merged
Example: Wait for GitHub mergeability and review
For example, this command waits until GitHub reports a PR mergeable, with at least one approval and no blocking reviews.git config \
spice.merge.ready.command \
"$HOME/bin/merge-ready.sh"
#!/usr/bin/env bash
set -euo pipefail
readonly PR="${GIT_SPICE_GITHUB_PR_NUMBER}"
MERGEABLE="$(
gh pr view "$PR" \
--json mergeable \
--jq .mergeable
)"
case "$MERGEABLE" in
MERGEABLE)
;;
UNKNOWN)
# GitHub may return UNKNOWN while it computes whether the PR can merge.
# Treat that as temporary and let git-spice poll again.
exit 1
;;
CONFLICTING)
exit 2
;;
esac
REVIEW="$(
gh pr view "$PR" \
--json reviewDecision \
--jq .reviewDecision
)"
case "$REVIEW" in
APPROVED)
exit 0
;;
"" | REVIEW_REQUIRED)
# GitHub may return an empty reviewDecision
# when no review requirement applies or no review decision is available.
# For this policy, both empty and REVIEW_REQUIRED mean keep waiting.
exit 1
;;
CHANGES_REQUESTED)
exit 2
;;
esac
exit 1
See Command environment
for the variables passed to
Merging multiple stacks¶
All three merge commands accept --branch.
Repeat --branch to include multiple branches in the selection.
This has different effects depending on the command.
$ gs branch merge --branch feat1 --branch feat2
# merges feat1, feat2 into main$ gs downstack merge --branch feat2 --branch feat3
# merges feat1, feat2, feat3 into main$ gs stack merge --branch feat2 --branch feat4
# merges all branches into mainCustom merge processes¶
git-spice uses the Forge's merge APIs to merge CRs.
This is not always desirable, as some repositories have custom merge processes.
git-spice supports custom merge workflows
with the
For example, a GitHub repository may require
a contributor to comment /merge on a PR to request a merge.
To support this, configure git-spice like this:
git config \
spice.merge.command \
'gh pr comment "$GIT_SPICE_GITHUB_PR_NUMBER" --body /merge'If the script is more complex, the configuration can be pointed to a script or executable instead.
git config \
spice.merge.command \
"$HOME/bin/request-merge.sh"#!/usr/bin/env bash
set -euo pipefail
NUM="${GIT_SPICE_GITHUB_PR_NUMBER}"
LABEL=ready-to-merge
COMMENT="@myfancybot merge"
gh pr edit "$NUM" --add-label "$LABEL"
gh pr comment "$NUM" --body "$COMMENT"
git-spice waits for the CR to be ready to merge
before running the configured command,
and waits for the CR to finish merging before moving upstack.
If the merge workflow is slow,
the
If the command exits with a non-zero exit code, the merge is considered to have failed and the upstack branches are not merged.
See Command environment
for the variables passed to
Command environment¶
GIT_SPICE_FORGE_IDGIT_SPICE_BRANCHGIT_SPICE_BASE_BRANCHGIT_SPICE_TRUNK_BRANCHGIT_SPICE_CHANGE_URLGIT_SPICE_HEAD_SHA
Depending on the forge, the following additional variables may be set:
| Environment variable | Forge |
|---|---|
GIT_SPICE_GITHUB_PR_NUMBER |
|
GIT_SPICE_GITLAB_MR_IID |
|
GIT_SPICE_BITBUCKET_PR_ID |
|
GIT_SPICE_FORGEJO_PR_NUMBER |
|
GIT_SPICE_GITEA_PR_NUMBER |