Collaboration
Sequential Changes
Setup Base Repo
This is the simple case: if people make sequential changes, we don’t ever get merge conflicts. Let’s first set up a repo with two patches:
$ hg init mine
$ cd mine
$ echo 1 >one
$ echo 1 >conflict # need this later
$ hg ci -Am one1
adding conflict
adding one
Patch p1:
$ echo 2 >>one
$ hg pnew p1
marked working directory as branch p1
(branches are permanent and global, did you want a bookmark?)
Patch p2:
$ echo 3 >>one
$ hg pnew p2
marked working directory as branch p2
(branches are permanent and global, did you want a bookmark?)
Yielding:
$ hg pgraph
@ p2
|
o p1
|
o default
Initial Clone
Let’s now see what happens if someone clones from us:
$ cd ..
$ hg clone mine collab
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd collab
$ cat >>.hg/hgrc <<-eof
[ui]
username = collab
eof
He sees a bunch of branches:
$ hg branches
p2 2:d0e98bfc8352
p1 1:297e6182bd2b (inactive)
default 0:3d6f92b7a7da (inactive)
But he does not have a patch graph file (because we don’t commit this file):
$ ls .hg/pgraph
ls: cannot access .hg/pgraph: No such file or directory
But he can see the patch graph, as inferred from the recorded dependencies:
$ hg pgraph
created graph description from current tips
o p2
|
o p1
|
@ default
and pbranch has automatically created the patch graph file from the inferred graph now:
$ cat .hg/pgraph
p2: p1
p1: default
Updates
He can now update the patches. Here, he updates p1:
$ hg up p1
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ echo 1 >>two
$ hg ci -Am two1
adding two
Then pmerges the change forward:
$ hg up p2
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
needs merge with p1
needs update of diff base to tip of p1
use 'hg pmerge'
$ hg pmerge
updating to p1
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
p2: merging from p1
marked working directory as branch p2
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
So p1 now contains an additional file two
:
$ hg pdiff p1 | grep -F two
diff --git a/two b/two
+++ b/two
And p2 does not (meaning it has the merge):
$ hg pdiff p2 | grep -F two
Now we pull his updates:
$ cd ../mine
$ hg pull ../collab
pulling from ../collab
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files
(run 'hg update' to get a working copy)
$ hg update tip
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
our patch status is clean:
$ hg pgraph --status
@ p2
|
o p1
|
o default
and the diffs look OK:
$ hg pdiff p1 | grep -F two
diff --git a/two b/two
+++ b/two
$ hg pdiff p2 | grep -F two
New Patches
What if he adds a patch? Let’s see:
$ cd ../collab
He introduces a new branch p3 based on p1:
$ hg up p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ echo 4 >>one
$ hg pnew p3
marked working directory as branch p3
(branches are permanent and global, did you want a bookmark?)
created new head
yielding:
$ hg pgraph
o p2
|
| @ p3
|/
o p1
|
o default
$ hg pdiff p3
# HG changeset patch
# User collab
# Date 0 0
_
diff --git a/one b/one
--- a/one
+++ b/one
@@ -2,0 +3,1 @@
+4
When we pull this:
$ cd ../mine
$ hg pull ../collab
pulling from ../collab
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads)
inferred graph has changed; use 'hg pgraph --tips' to view
we get a hint that the inferred patch graph changed. As we can verify:
hg pgraph—tips
$ hg pgraph --tips
@ p2
|
| o p3
|/
o p1
|
o default
But we don’t have p3 in our .hg/pgraph
yet:
$ cat .hg/pgraph
p1: default
p2: p1
which means our default graph does not list p3:
$ hg pgraph
@ p2
|
o p1
|
o default
The reason is .hg/pgraph
is a file designed for editing by hand, comments and all. So pbranch never updates it automatically.
We could now add p3 to .hg/pgraph
manually, or just start over from the inferred graph:
hg pgraph—as-text
$ hg pgraph --tips --as-text >.hg/pgraph
$ cat .hg/pgraph
p2: p1
p3: p1
p1: default
to get the desired outcome:
$ hg pgraph --status
@ p2
|
| o p3
|/
o p1
|
o default
and:
$ hg pdiff p3
# HG changeset patch
# User collab
# Date 0 0
_
diff --git a/one b/one
--- a/one
+++ b/one
@@ -2,0 +3,1 @@
+4
Parallel Changes
Let’s see what happens when two people update the same base patch in parallel. This raises issues beyond plain merge conflicts in that patches based on the modified patch will have merge conflicts in their .hgpatchinfo/*.dep
files. So let’s see how pbranch handles this.
Make Conflicting Changes To p1
First, we modify p1:
$ cd ../mine
$ hg up p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ echo mine >>conflict
$ hg ci -m one-mine
and merge this into the other patches:
$ hg pmerge --all
p3: merging from p1
marked working directory as branch p3
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
updating to p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
p2: merging from p1
marked working directory as branch p2
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Now, our collaborator does something similar:
$ cd ../collab
$ hg up p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ echo collab >>conflict
$ hg ci -m one-collab
$ hg pmerge --all
p3: merging from p1
marked working directory as branch p3
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
updating to p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
p2: merging from p1
marked working directory as branch p2
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Pull Conflicting Change
We pull this:
$ cd ../mine
$ hg pull ../collab
pulling from ../collab
searching for changes
adding changesets
adding manifests
adding file changes
added 3 changesets with 3 changes to 3 files (+2 heads)
(run 'hg heads .' to see heads, 'hg merge' to merge)
and look at the patch status:
$ hg pgraph --status
@ p2
| * needs merge of 2 heads
| * needs merge with p1
| * needs update of diff base to tip of p1
| o p3
|/ * needs merge of 2 heads
| * needs merge with p1
| * needs update of diff base to tip of p1
o p1
| * needs merge of 2 heads
o default
p1 now has two heads. This is expected as we did parallel changes in p1. But p2 and p3 each have two heads as well. These latter are caused by the forward merges of the conflicting change in both repos by hg pmerge
.
Merge Resolving Conflict
The heads in p1 we therefore resolve normally:
$ hg up p1
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
needs merge of 2 heads
use 'hg pmerge'
$ hg pmerge
p1: merging from alternate head ea2bb5cf4441
merging conflict
warning: conflicts during merge.
merging conflict incomplete! (edit conflicts, then use 'hg resolve --mark')
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
abort: use 'hg resolve' to retry unresolved file merges, then do 'hg pmerge' again
$ hg resolve --list
U conflict
$ echo "resolved" >conflict
$ hg resolve --mark conflict
$ hg ci -m resolved
yielding this status:
$ hg pgraph --status
o p2
| * needs merge of 2 heads
| * needs merge with p1
| * needs update of diff base to tip of p1
| o p3
|/ * needs merge of 2 heads
| * needs merge with p1
| * needs update of diff base to tip of p1
@ p1
|
o default
Carry The Merge Forward
If we run pmerge now, the following happens:
for p in [p2, p3]:
merge p1 into tip of p # so we get the merge of "conflict" we already did
merge heads
resolve the conflict in ".hgpatchinfo/%s.dep" % p by overwriting the .dep
Here it is:
$ hg pmerge --all
p3: merging from p1
marked working directory as branch p3
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
p3: merging from alternate head 5482c93964fa
merging .hgpatchinfo/p3.dep
warning: conflicts during merge.
merging .hgpatchinfo/p3.dep incomplete! (edit conflicts, then use 'hg resolve --mark')
merging conflict
warning: conflicts during merge.
merging conflict incomplete! (edit conflicts, then use 'hg resolve --mark')
0 files updated, 0 files merged, 0 files removed, 2 files unresolved
resolving conflict; already merged in rev 13
p3: resolving .hgpatchinfo/p3.dep
updating to p1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
p2: merging from p1
marked working directory as branch p2
(branches are permanent and global, did you want a bookmark?)
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
p2: merging from alternate head 7d89066a5a9c
merging .hgpatchinfo/p2.dep
warning: conflicts during merge.
merging .hgpatchinfo/p2.dep incomplete! (edit conflicts, then use 'hg resolve --mark')
merging conflict
warning: conflicts during merge.
merging conflict incomplete! (edit conflicts, then use 'hg resolve --mark')
0 files updated, 0 files merged, 0 files removed, 2 files unresolved
resolving conflict; already merged in rev 15
p2: resolving .hgpatchinfo/p2.dep
And we get the desired state:
$ hg pgraph --status
@ p2
|
| o p3
|/
o p1
|
o default
And diffs:
$ hg pdiff --tips p1
# HG changeset patch
# User john
# Date 0 0
_
diff --git a/conflict b/conflict
--- a/conflict
+++ b/conflict
@@ -1,1 +1,1 @@
-1
+resolved
diff --git a/one b/one
--- a/one
+++ b/one
@@ -1,0 +2,1 @@
+2
diff --git a/two b/two
new file mode 100644
--- /dev/null
+++ b/two
@@ -0,0 +1,1 @@
+1
$ hg pdiff --tips p2
# HG changeset patch
# User john
# Date 0 0
_
diff --git a/one b/one
--- a/one
+++ b/one
@@ -2,0 +3,1 @@
+3
$ hg pdiff --tips p3
# HG changeset patch
# User john
# Date 0 0
_
diff --git a/one b/one
--- a/one
+++ b/one
@@ -2,0 +3,1 @@
+4