Inserting and Deleting Patches
Inserting a Patch
Scenario
First, we pick up the base scenario:
$ hg clone scenario-base insert
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd insert
$ hg pgraph
created graph description from current tips
o patchC
|
o patchB
|
o patchA
|
@ default
Create New Patch
We want to insert a patch between patchB and patchC. So we update to patchB and create a new patch branch with our change:
$ hg update patchB
7 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ echo "B1" >b1
$ hg add b1
$ hg pnew --text "inserted patch" patchB1
marked working directory as branch patchB1
(branches are permanent and global, did you want a bookmark?)
created new head
Now we update the dependency info for patchC:
$ cat >.hg/pgraph <<-eof
patchC: patchB1
patchB1: patchB
patchB: patchA
patchA: default
eof
Here’s the new graph:
$ hg pgraph --status
o patchC
| * needs merge with patchB1
| * needs update of diff base to tip of patchB1
@ patchB1
|
o patchB
|
o patchA
|
o default
So now we need to merge patchB1 into patchC to properly establish the new dependency (keeping the repo for another scenario):
$ hg update patchC
4 files updated, 0 files merged, 3 files removed, 0 files unresolved
needs merge with patchB1
needs update of diff base to tip of patchB1
use 'hg pmerge'
$ hg pmerge
updating to patchB1
4 files updated, 0 files merged, 3 files removed, 0 files unresolved
patchC: merging from patchB1
marked working directory as branch patchC
(branches are permanent and global, did you want a bookmark?)
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg clone . ../delete
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
And can commit something that depends on the file introduced by patchB1 (again, keeping the repo):
$ echo "More" >>b1
$ hg commit --message "c based on b1"
$ hg clone . ../delete-conflict
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Big Picture
$ hg pgraph
@ patchC
|
o patchB1
|
o patchB
|
o patchA
|
o default
$ hg glog --rev patchB:tip
@ 10 patchC: c based on b1 - john
|
o 9 patchC: merge of patchB1 - john
|\
| o 8 patchB1: start new patch on patchB - john
| |
o | 7 patchC: update patch description - john
| |
o | 6 patchC: update patch dependencies - john
| |
o | 5 patchC: changes for C - john
|/
o 4 patchB: second try in B - john
|
Results
$ hg pdiff patchB1
# HG changeset patch
# User john
# Date 0 0
inserted patch
_
diff --git a/b1 b/b1
new file mode 100644
--- /dev/null
+++ b/b1
@@ -0,0 +1,1 @@
+B1
$ hg pdiff patchC
# HG changeset patch
# User john
# Date 0 0
yet another patch
_
diff --git a/b1 b/b1
--- a/b1
+++ b/b1
@@ -1,0 +2,1 @@
+More
diff --git a/file-from-C b/file-from-C
new file mode 100644
--- /dev/null
+++ b/file-from-C
@@ -0,0 +1,1 @@
+Three
diff --git a/main-file-1 b/main-file-1
--- a/main-file-1
+++ b/main-file-1
@@ -5,1 +5,1 @@
-Three
+Drei
Folding a Patch Into Another
Let’s get rid of patchB1 again, folding the changes it introduces into patchC. This is very simple. We just make patchC depend on patchB again:
$ cat >.hg/pgraph <<-eof
patchC: patchB
patchB: patchA
patchA: default
eof
By not listing patchB1 in the graph description anymore, we automatically demoted it from patch back to plain branch in our view of the patch graph. So it’s gone here:
$ hg pgraph --status
@ patchC
| * needs update of diff base to tip of patchB
o patchB
|
o patchA
|
o default
But it’s still there as a branch, of course:
$ hg branches
patchC 10:c5b4d9f3c70a
patchB1 8:bf69d431636e (inactive)
patchB 4:572fc1ab3a17 (inactive)
patchA 2:4cac083bb95c (inactive)
default 0:527edfea671a (inactive)
There is no pending merge here, as patchC is already fully merged with patchB (formerly through patchB1). But we do need to make the dependency change permanent:
$ hg pmerge
patchC: updating dependencies
For this final history:
$ hg glog --rev patchB:tip
@ 11 patchC: update patch dependencies - john
|
o 10 patchC: c based on b1 - john
|
o 9 patchC: merge of patchB1 - john
|\
| o 8 patchB1: start new patch on patchB - john
| |
o | 7 patchC: update patch description - john
| |
o | 6 patchC: update patch dependencies - john
| |
o | 5 patchC: changes for C - john
|/
o 4 patchB: second try in B - john
|
Since we already merged the changes introduced by patchB1 into patchC, they now automatically appear in patchC (relative to patchB):
$ hg pdiff patchC b1
# HG changeset patch
# User john
# Date 0 0
yet another patch
_
diff --git a/b1 b/b1
new file mode 100644
--- /dev/null
+++ b/b1
@@ -0,0 +1,2 @@
+B1
+More
However, much as the patch is still there as a branch, it’s also still there in the patch graph inferred from all the branch tips:
$ hg pgraph --tips
@ patchC
|
| o patchB1
|/
o patchB
|
o patchA
|
o default
And this is what people will get as their default .hg/pgraph
file when they pull from us. To get rid of the patch there as well, we simply close its branch:
$ hg up patchB1
2 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg commit --close-branch -m "closed"
and get:
$ hg pgraph --tips
o patchC
|
o patchB
|
o patchA
|
o default
Deleting a Patch
This time, let’s get rid of patchB1, truly deleting the changes it introduces. It’s a multi-step process around patchB1:
- Backout its changes.
- Merge the backout into its children.
- In the graph description, remove it and relink its children to its parent.
We first do this in the scenario with no conflicts (no changes depend on changes in patchB1):
$ cd ../delete
$ hg pgraph # ensure the patch graph is up to date
created graph description from current tips
o patchC
|
o patchB1
|
o patchB
|
o patchA
|
@ default
$ hg update patchB1
10 files updated, 0 files merged, 0 files removed, 0 files unresolved
Backout Changes
hg pbackout
We back out all the changes introduced by patchB1:
$ hg pbackout
backing out to patchB
created new head
This commits a backout changeset:
$ hg log --rev tip
10 patchB1: backout patch branch patchB1 - john
Aside: If we display the graph now, patchB1 appears as a new root since we backed out its dependency info, too:
$ hg pgraph --status
o patchC
| * needs merge with patchB1
| * needs update of diff base to tip of patchB1
@ patchB1
|
o patchB
|
o patchA
|
o default
Merge Into Children
Then we merge the backout into patchC:
$ hg update patchC
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
needs merge with patchB1
needs update of diff base to tip of patchB1
use 'hg pmerge'
$ hg pmerge
updating to patchB1
1 files updated, 0 files merged, 4 files removed, 0 files unresolved
patchC: merging from patchB1
marked working directory as branch patchC
(branches are permanent and global, did you want a bookmark?)
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
Remove From Patch Graph
And now we do as when folding the (now empty) patchB1:
$ hg up patchB1
1 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg commit --close-branch -m "closed"
$ cat >.hg/pgraph <<-eof
patchC: patchB
patchB: patchA
patchA: default
eof
$ hg pgraph --status
o patchC
| * needs update of diff base to tip of patchB
o patchB
|
o patchA
|
o default
$ hg pmerge --all
updating to patchC
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
patchC: updating dependencies
$ hg pgraph --tips
@ patchC
|
o patchB
|
o patchA
|
o default
Results
Which leaves us with a diff for patchC that does not contain the changes we had in patchB1:
$ hg pdiff patchC
# HG changeset patch
# User john
# Date 0 0
yet another patch
_
diff --git a/file-from-C b/file-from-C
new file mode 100644
--- /dev/null
+++ b/file-from-C
@@ -0,0 +1,1 @@
+Three
diff --git a/main-file-1 b/main-file-1
--- a/main-file-1
+++ b/main-file-1
@@ -5,1 +5,1 @@
-Three
+Drei
Big Picture
$ hg glog --rev patchB:tip
@ 13 patchC: update patch dependencies - john
|
| o 12 patchB1: closed - john
| |
o | 11 patchC: merge of patchB1 - john
|\|
| o 10 patchB1: backout patch branch patchB1 - john
| |
o | 9 patchC: merge of patchB1 - john
|\|
| o 8 patchB1: start new patch on patchB - john
| |
o | 7 patchC: update patch description - john
| |
o | 6 patchC: update patch dependencies - john
| |
o | 5 patchC: changes for C - john
|/
o 4 patchB: second try in B - john
|
Deleting a Patch With Conflicts
We do this again, but this time with the version of patchC that already depends on changes in patchB1:
$ cd ../delete-conflict
$ hg pgraph # ensure the patch graph is up to date
created graph description from current tips
o patchC
|
o patchB1
|
o patchB
|
o patchA
|
@ default
$ hg update patchB1
10 files updated, 0 files merged, 0 files removed, 0 files unresolved
Backout Changes
Again, we back out patchB1, which works ok:
$ hg pbackout
backing out to patchB
created new head
Merge Into Children
But the merge now prompts us for what to do about the conflict (we choose to keep the file b1):
$ hg update patchC
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
needs merge with patchB1
needs update of diff base to tip of patchB1
use 'hg pmerge'
$ hg pmerge
updating to patchB1
1 files updated, 0 files merged, 4 files removed, 0 files unresolved
patchC: merging from patchB1
marked working directory as branch patchC
(branches are permanent and global, did you want a bookmark?)
remote changed b1 which local deleted
use (c)hanged version or leave (d)eleted? c
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
etc. (as above).