Scenario: concurrent-pulls
Two developers pull the same splice on main at different times. Each
pull writes a commit that changes the same line of .splice, the synced
commit, and the same lines of the files the upstream changed. When the
second developer merges the first one's work, Git reports conflicts in
both.
- Upstream:
seed,upstream 1,upstream 2. - Alice's monorepo, pushed as
origin/main: cloned atseed, then pulledupstream 1. - Bob's monorepo, this one: cloned at
seed, then pulledupstream 2, without pulling the monorepo first.
To avoid this, pull the monorepo before you pull a splice. To get out of
it, resolve the conflict as below, or redo the pull.
If .splice is committed with conflict markers anyway,
every command stops until it's fixed.
Output
setup.bash builds this state:
$ build_scenario scenario_concurrent_pulls
$ git log --graph --format=%s HEAD origin/main
* splice: pull vendor/a from main at 4c1905d
| * splice: pull vendor/a from main at 72efaac
|/
* splice: clone vendor/a from main at bde4164
* initial commit
$ git merge origin/main
Auto-merging vendor/a/.splice
CONFLICT (content): Merge conflict in vendor/a/.splice
Auto-merging vendor/a/file.txt
CONFLICT (content): Merge conflict in vendor/a/file.txt
Automatic merge failed; fix conflicts and then commit the result.
[1]
$ git status --short
UU vendor/a/.splice
UU vendor/a/file.txt
Both sides changed the synced commit (expand shows the tabs as spaces):
$ expand vendor/a/.splice
[splice]
id = 224f2c2563d3b6f7
<<<<<<< HEAD
commit = 4c1905de64f0df0a488c0b63482302ec229fdce9
=======
commit = 72efaacc5c6b50e5d2a6fe51a30af958c8adae51
>>>>>>> origin/main
[upstream "origin"]
url = https://git.example.com/a.git
While the merge is in progress, pull and merge refuse to start.
status, log, diff and push read the last commit, not the
conflicted files, so they still show the state from before the merge.
status adds that the folder has uncommitted changes, the conflicted
files:
$ git splice pull vendor/a
!! a cherry-pick or merge is in progress -- conclude it first
[1]
$ git splice status
On branch main
up to date vendor/a uncommitted changes
Resolving
Keep the newer sync point: the one whose history contains the other's.
The fetched upstream branch shows both, newest first: Bob's upstream 2
contains Alice's upstream 1:
$ git log --format='%h %s' splices/a/main
4c1905d upstream 2
72efaac upstream 1
bde4164 seed
Only the upstream changed the folder on both sides, so the whole folder
is resolved to Bob's side, --ours, which has the newer sync point. Had
Alice also changed files in the folder herself, those would need resolving
by hand, but .splice would still take the newer sync point:
$ git checkout --ours -- vendor/a && git add vendor/a
git diff --check finds leftover conflict markers, and git config
refuses a .splice it can't read:
$ git diff --cached --check && git config --file vendor/a/.splice --list
splice.id=224f2c2563d3b6f7
splice.commit=4c1905de64f0df0a488c0b63482302ec229fdce9
upstream.origin.url=https://git.example.com/a.git
$ git commit -q --no-edit && git splice status
On branch main
up to date vendor/a