This repository was archived by the owner on Oct 13, 2026. It is now read-only.
Repository navigation
test(scenarios): show that squash-merging a pull loses the sync point #56
Draft
roschaefer
wants to merge
1
commit into
main
Choose a base branch
from
test/squash-merged-pull
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Scenario: squash-merged-pull | ||
|
|
||
| A known bug: the remote's change was pulled on a feature branch, and the | ||
| feature branch was squash-merged into `main`. Since then, the tool | ||
| misreads `main`. | ||
|
|
||
| - **Monorepo (`vendor/a`)**: added at `seed` on `main`. On `feature`, | ||
| `git subtree pull --squash` brought in `upstream change`. `feature` was | ||
| squash-merged into `main` and deleted. Then a local commit on `main` | ||
| added `local.txt`. | ||
| - **Remote**: `seed`, then `upstream change`. It has never seen | ||
| `local.txt`. | ||
|
|
||
| Only the local side changed since `upstream change`, so the right state is | ||
| `push`. But the pull's squash commit, which records the sync point, was | ||
| only reachable through the pull's merge commit on `feature`. A squash | ||
| merge keeps the content and drops that history, so `main` still sees the | ||
| sync point from `git subtree add`. Measured against it, both sides changed. | ||
|
|
||
| ## Output | ||
|
|
||
| `scenario_squash_merged_pull` in [`setup.bash`](setup.bash) | ||
| builds this state. [How scenarios work](../README.md). | ||
|
|
||
| <!-- | ||
| ```scrut {fail_fast: true, output_stream: combined} | ||
| $ source "$TESTDIR/../readme-setup.sh" && build_scenario scenario_squash_merged_pull | ||
| ``` | ||
| --> | ||
|
|
||
| `status` reports `diverged` instead of `push`: | ||
|
|
||
| ```scrut | ||
| $ git subtrees status | ||
| ok vendor/a -> $UPSTREAM (diverged) | ||
| local.txt | 1 + | ||
| 1 file changed, 1 insertion(+) | ||
| ``` | ||
|
|
||
| `push` is rejected, since the history it rebuilds starts at the old sync | ||
| point: | ||
|
|
||
| ```scrut | ||
| $ git subtrees push | ||
| git push using: vendor/a main | ||
| To $UPSTREAM | ||
| ! [rejected] bd16e2c5cc3967a824b55916f9d66708a8fda514 -> main (non-fast-forward) | ||
| error: failed to push some refs to '$UPSTREAM' | ||
| hint: Updates were rejected because the tip of your current branch is behind | ||
| hint: its remote counterpart. If you want to integrate the remote changes, | ||
| hint: use 'git pull' before pushing again. | ||
| hint: See the 'Note about fast-forwards' in 'git push --help' for details. | ||
| !! vendor/a: push failed | ||
| !! Failed: vendor/a | ||
| [1] | ||
| ``` | ||
|
|
||
| `pull` recovers: it merges `upstream change` again, which changes no file, | ||
| and records a new sync point: | ||
|
|
||
| ```scrut | ||
| $ git subtrees pull | ||
| ok vendor/a fetched | ||
| Merge made by the 'ort' strategy. | ||
| ok vendor/a: pulled | ||
| ``` | ||
|
|
||
| But the push after it rebuilds the squash-merged commit too, so the remote | ||
| gets `feature (squash-merged)`, which repeats `upstream change`, next to | ||
| the original: | ||
|
|
||
| ```scrut | ||
| $ git subtrees push | ||
| git push using: vendor/a main | ||
| To $UPSTREAM | ||
| 6045a98..90babaf 90babaf10d3e73b0251a158cb615b5c563b07c80 -> main | ||
| ok vendor/a: pushed | ||
| ``` | ||
|
|
||
| ```scrut | ||
| $ git -C "$UPSTREAM" log --graph --format='%s' main | ||
| * Merge commit '00a22274fa7c6e2d9b734b9eefe569b3f8cdd6f8' | ||
| |\ | ||
| | * upstream change | ||
| * | local change | ||
| * | feature (squash-merged) | ||
| |/ | ||
| * seed | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # See README.md in this directory. | ||
| scenario_squash_merged_pull() { | ||
| local monorepo="$1" upstream="$2" | ||
| make_bare_repo "$upstream" | ||
| seed_bare_repo "$upstream" "seed" | ||
| init_monorepo "$monorepo" | ||
| add_subtree "$monorepo" "$upstream" "vendor/a" | ||
| seed_bare_repo "$upstream" "upstream change" | ||
| ( | ||
| cd "$monorepo" | ||
| git switch -q -c feature | ||
| git fetch -q vendor/a | ||
| git subtree pull -q --prefix=vendor/a vendor/a main --squash -m "pull vendor/a" >/dev/null 2>&1 | ||
| git switch -q main | ||
| git merge -q --squash feature >/dev/null | ||
| git commit -q -m "feature (squash-merged)" | ||
| git branch -q -D feature | ||
| echo "local change" >vendor/a/local.txt | ||
| git add vendor/a/local.txt | ||
| git commit -q -m "local change" | ||
| ) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: roschaefer/git-subtrees
Length of output: 6961
🏁 Script executed:
Repository: roschaefer/git-subtrees
Length of output: 29207
Skip the known failing regression case until the status logic is fixed.
The scenario documents
(diverged)at the reviewed head. The assertion requires(push), sobats --recursive testfails. The CI workflow defines no expected-failure exception.Suggested fix
@test "status: reports push after a pull on a squash-merged branch" { + skip "known bug: status reports diverged after a squash-merged pull" scenario_squash_merged_pull "$monorepo" "$upstream" cd "$monorepo" run cmd_status📝 Committable suggestion
🤖 Prompt for AI Agents