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 patch-C
|
o patch-B
|
o patch-A
|
@ default
Create New Patch
We want to insert a patch between patch-B and patch-C. So we update to patch-B and create a new patch branch with our change:
$ hg update patch-B
7 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ echo "B1" >b1
$ hg add b1
$ hg pnew --text "inserted patch" patch-B1
marked working directory as branch patch-B1
created new head
Now we update the dependency info for patch-C:
$ cat >.hg/pgraph <<-eof
patch-C: patch-B1
patch-B1: patch-B
patch-B: patch-A
patch-A: default
eof
Here’s the new graph:
$ hg pgraph --status
o patch-C
| * needs merge with patch-B1
| * needs update of diff base to tip of patch-B1
@ patch-B1
|
o patch-B
|
o patch-A
|
o default
So now we need to merge patch-B1 into patch-C to properly establish the new dependency (keeping the repo for another scenario):
$ hg update patch-C
4 files updated, 0 files merged, 3 files removed, 0 files unresolved
needs merge with patch-B1
needs update of diff base to tip of patch-B1
use 'hg pmerge'
$ hg pmerge
updating to patch-B1
4 files updated, 0 files merged, 3 files removed, 0 files unresolved
patch-C: merging from patch-B1
marked working directory as branch patch-C
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 patch-B1 (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
@ patch-C
|
o patch-B1
|
o patch-B
|
o patch-A
|
o default
$ hg glog --rev patch-B:tip
@ 10 patch-C: c based on b1 - john
|
o 9 patch-C: merge of patch-B1 - john
|\
| o 8 patch-B1: start new patch on patch-B - john
| |
o | 7 patch-C: update patch description - john
| |
o | 6 patch-C: update patch dependencies - john
| |
o | 5 patch-C: changes for C - john
|/
o 4 patch-B: second try in B - john
|
Results
$ hg pdiff patch-B1
# 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 patch-C
# HG changeset patch
# User john
# Date 0 0
yet another patch
diff --git a/b1 b/b1
--- a/b1
+++ b/b1
@@ -2,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 patch-B1 again, folding the changes it introduces into patch-C. This is very simple. We just make patch-C depend on patch-B again:
$ cat >.hg/pgraph <<-eof
patch-C: patch-B
patch-B: patch-A
patch-A: default
eof
By not listing patch-B1 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
@ patch-C
| * needs update of diff base to tip of patch-B
o patch-B
|
o patch-A
|
o default
But it’s still there as a branch, of course:
$ hg branches
patch-C 10:22e5a4e588e0
patch-B1 8:b2089dcc79c9 (inactive)
patch-B 4:ece9ac1bb19f (inactive)
patch-A 2:f74eb14d1d12 (inactive)
default 0:527edfea671a (inactive)
There is no pending merge here, as patch-C is already fully merged with patch-B (formerly through patch-B1). But we do need to make the dependency change permanent:
$ hg pmerge
patch-C: updating dependencies
For this final history:
$ hg glog --rev patch-B:tip
@ 11 patch-C: update patch dependencies - john
|
o 10 patch-C: c based on b1 - john
|
o 9 patch-C: merge of patch-B1 - john
|\
| o 8 patch-B1: start new patch on patch-B - john
| |
o | 7 patch-C: update patch description - john
| |
o | 6 patch-C: update patch dependencies - john
| |
o | 5 patch-C: changes for C - john
|/
o 4 patch-B: second try in B - john
|
Since we already merged the changes introduced by patch-B1 into patch-C, they now automatically appear in patch-C (relative to patch-B):
$ hg pdiff patch-C 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
o patch-B1
|
| @ patch-C
|/
o patch-B
|
o patch-A
|
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 patch-B1
2 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg commit --close-branch -m "closed"
created new head
and get:
$ hg pgraph --tips
o patch-C
|
o patch-B
|
o patch-A
|
o default
Deleting a Patch
This time, let’s get rid of patch-B1, truly deleting the changes it introduces. It’s a multi-step process around patch-B1:
- 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 patch-B1):
$ cd ../delete
$ hg pgraph # ensure the patch graph is up to date
created graph description from current tips
o patch-C
|
o patch-B1
|
o patch-B
|
o patch-A
|
@ default
$ hg update patch-B1
10 files updated, 0 files merged, 0 files removed, 0 files unresolved
Backout Changes
hg pbackout
We back out all the changes introduced by patch-B1:
$ hg pbackout
backing out to patch-B
created new head
This commits a backout changeset:
$ hg log --rev tip
10 patch-B1: backout patch branch patch-B1 - john
Aside: If we display the graph now, patch-B1 appears as a new root since we backed out its dependency info, too:
$ hg pgraph --status
o patch-C
| * needs merge with patch-B1
| * needs update of diff base to tip of patch-B1
@ patch-B1
|
o patch-B
|
o patch-A
|
o default
Merge Into Children
Then we merge the backout into patch-C:
$ hg update patch-C
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
needs merge with patch-B1
needs update of diff base to tip of patch-B1
use 'hg pmerge'
$ hg pmerge
updating to patch-B1
1 files updated, 0 files merged, 4 files removed, 0 files unresolved
patch-C: merging from patch-B1
marked working directory as branch patch-C
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) patch-B1:
$ hg up patch-B1
1 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg commit --close-branch -m "closed"
created new head
$ cat >.hg/pgraph <<-eof
patch-C: patch-B
patch-B: patch-A
patch-A: default
eof
$ hg pgraph --status
o patch-C
| * needs update of diff base to tip of patch-B
o patch-B
|
o patch-A
|
o default
$ hg pmerge --all
updating to patch-C
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
patch-C: updating dependencies
$ hg pgraph --tips
@ patch-C
|
o patch-B
|
o patch-A
|
o default
Results
Which leaves us with a diff for patch-C that does not contain the changes we had in patch-B1:
$ hg pdiff patch-C
# 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 patch-B:tip
@ 13 patch-C: update patch dependencies - john
|
| o 12 patch-B1: closed - john
| |
o | 11 patch-C: merge of patch-B1 - john
|\|
| o 10 patch-B1: backout patch branch patch-B1 - john
| |
o | 9 patch-C: merge of patch-B1 - john
|\|
| o 8 patch-B1: start new patch on patch-B - john
| |
o | 7 patch-C: update patch description - john
| |
o | 6 patch-C: update patch dependencies - john
| |
o | 5 patch-C: changes for C - john
|/
o 4 patch-B: second try in B - john
|
Deleting a Patch With Conflicts
We do this again, but this time with the version of patch-C that already depends on changes in patch-B1:
$ cd ../delete-conflict
$ hg pgraph # ensure the patch graph is up to date
created graph description from current tips
o patch-C
|
o patch-B1
|
o patch-B
|
o patch-A
|
@ default
$ hg update patch-B1
10 files updated, 0 files merged, 0 files removed, 0 files unresolved
Backout Changes
Again, we back out patch-B1, which works ok:
$ hg pbackout
backing out to patch-B
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 patch-C
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
needs merge with patch-B1
needs update of diff base to tip of patch-B1
use 'hg pmerge'
$ hg pmerge
updating to patch-B1
1 files updated, 0 files merged, 4 files removed, 0 files unresolved
patch-C: merging from patch-B1
marked working directory as branch patch-C
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).