Differences between revisions 11 and 26 (spanning 15 versions)
Revision 11 as of 2010-07-04 10:23:41
Size: 4068
Editor: JohanSamyn
Comment:
Revision 26 as of 2012-11-06 14:55:56
Size: 6846
Editor: abuehl
Comment: remove reference to deleted page "commit"
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
== Backout ==
#pragma section-numbers 2
= Backout =
Line 7: Line 7:
<<TableOfContents>>
Line 10: Line 12:
<<BR>><<BR>>

==== Here's some more detail from Matt about the inner workings (and slightly adapted by experience) ====
(see also [[http://mercurial.markmail.org/thread/r5u476t2gnkfl3kk|this email thread]])

Let <startrev> be the revision we're at when we start the backout.<<BR>>

== Inner Workings ==
Here's some more detail from Matt about the inner workings (and slightly adapted by experience) (see also [[http://mercurial.markmail.org/thread/r5u476t2gnkfl3kk|this email thread]])

/!\ Note that this page no longer tells the whole truth. The default behaviour [[http://www.selenic.com/hg/rev/52971985be14|changed]] in 1.7 as discussed [[http://markmail.org/thread/z7vkmj5fqb7gd3ce|here]].

Let `<startrev>` be the revision we're at when we start the backout.
Line 17: Line 21:
Line 18: Line 23:
 * `hg revert --all -r <parent of rev-to-backout>`
 * `hg commit`
 * `hg update -C -r <startrev>`
 1. `hg revert --all -r <parent of rev-to-backout>`
 1. `hg commit`
 1. `hg update -C -r <startrev>`
Line 22: Line 28:
 5.#5 `hg merge ` (with <startrev>)
5. `hg merge ` (merges <startrev> with the newly committed rev from 3.)
Line 24: Line 32:
 6.#6 `hg commit ` (the result of merging)
6. `hg commit ` (the result of merging)
Line 26: Line 36:
 * `hg commit ` yourself to complete it, or
* `hg commit ` yourself to complete it, and/or
Line 28: Line 39:
Step 4 assures the parents of the committed merge changeset are in the right order. That is : parent1 = <startrev>, and parent2 = <the new backout rev>.
<<BR>><<BR>>

==
== An example: ====

Step 4 assures the parents of the committed merge changeset are in the right order. That is : `parent1 = <startrev>` and `parent2 = <the new backout rev>`.

== An example: ==
Line 36: Line 47:
$ echi line2 >> file.txt $ echo line2 >> file.txt
Line 40: Line 51:
Line 46: Line 58:
Line 54: Line 67:
Line 69: Line 83:
Line 73: Line 88:
Line 92: Line 108:
Line 115: Line 132:
And file.txt looks like: And file.txt looks like this, nicely eliminating the 'line1a' from rev 1.
Line 122: Line 140:
<<BR>><<BR>>
When we try this using the separate steps, and we omit step 4, we get a slightly different graph. Note the reversed order of the parents in changeset 5:0eeac5ff9c76.
<<BR>><<BR>> When we try this using the separate steps, and we omit step 4, we get a slightly different graph. Note the reversed order of the parents in changeset 5:0eeac5ff9c76.
Line 127: Line 145:
| | parent: 4:cbca219e80e1
| | parent: 3:f82e9468d652
| | parent: 4:cbca219e80e1      | <---
| | parent: 3:f82e9468d652      |
Line 133: Line 151:
| | summary: backout | | summary: Backed out changeset 0cf85b44002c
Line 147: Line 165:
<<BR>><<BR>>
See also: [[Update]], [[Revert]], [[Commit]], [[Merge]]
== Backout of a Merge Changeset ==

{{{#!wiki warning
'''Warning'''

Backing out a merge will lead to trouble if you ever want to redo the merge. The only safe way to deal with a bad merge is to abandon the branch.
}}}

Imagine a situation where we merge two changesets. The first changeset has `a b` in a given file, the other has `x y` in the same file. The merge gives an conflict which we resolves:

{{{#!dot
    digraph G {
      graph[rankdir=LR]
      node[shape=box]

      a -> b -> c
      x -> y -> c

      a [label="a"]
      b [label="a b"]
      c [label="a b Y X"]
      x [label="x"]
      y [label="x y"]
    }
}}}
We work a little on the top branch to add `c` in the file. We then discover that the merge was bad. We back it out:

{{{#!dot
    digraph G {
      graph[rankdir=LR]
      node[shape=box]

      a -> b -> c -> d -> e
      x -> y -> c

      a [label="a"]
      b [label="a b"]
      c [label="a b Y X"]
      d [label="a b c Y X"]
      e [label="a b c", color=red]
      x [label="x"]
      y [label="x y"]
    }
}}}
The new red changeset is the backout, it has removed the `Y` and `X` lines from the bad merge, but it kept the new `c` line that was added after the merge.

We make some more changes on the bottom branch and merge it again:

{{{#!dot
    digraph G {
      graph[rankdir=LR]
      node[shape=box]

      a -> b -> c -> d -> e -> f
      x -> y -> c
      y -> z -> f

      a [label="a"]
      b [label="a b"]
      c [label="a b Y X"]
      d [label="a b c Y X"]
      e [label="a b c", color=red]
      f [label="a b c z"]
      x [label="x"]
      y [label="x y", color=green]
      z [label="x y z", color=blue]
    }
}}}
The idea is that the new merge changeset should contain the `x y z` lines along with the `a b c` lines. However, what happens is that the merge back out the `x` and `y` lines!

The greatest common ancestor of the red `a b c` changeset and the blue `x y z` changeset is the green changeset with `x y`. The three way merge thus considers the file in these configurations:

 * base: `x y`
 * local: `a b c`
 * other: `x y z`

The merge algorithm concludes that the `x` and `y` lines were removed on purpose, while `a b c` and `z` were added. The result is that the `x y` lines are silently discarded!

== See Also ==
 * [[Update]]
 * [[Revert]]
 * [[Merge]]
Line 152: Line 250:

[[FrenchBackout|Français]]

Backout

hg backout [OPTION]... [-r] REV

Revert/undo the effect of an earlier changeset.

Backout works by applying a changeset that's the opposite of the changeset to be backed out. That new changeset is committed to the repository, and eventually merged.

Help text: http://www.selenic.com/mercurial/hg.1.html#backout

1. Inner Workings

Here's some more detail from Matt about the inner workings (and slightly adapted by experience) (see also this email thread)

/!\ Note that this page no longer tells the whole truth. The default behaviour changed in 1.7 as discussed here.

Let <startrev> be the revision we're at when we start the backout.

Backout is basically four steps rolled into one:

  1. hg update -C -r <rev-to-backout>

  2. hg revert --all -r <parent of rev-to-backout>

  3. hg commit

  4. hg update -C -r <startrev>

There's a fifth step that is done automatically if you specify --merge :

  1. hg merge  (merges <startrev> with the newly committed rev from 3.)

And there's a sixth, manual step:

  1. hg commit  (the result of merging)

When step 3 (commit) aborts, you're left with the first two steps completed and you can either:

  • hg commit  yourself to complete it, and/or

  • hg update -C  to abandon the process

Step 4 assures the parents of the committed merge changeset are in the right order. That is : parent1 = <startrev> and parent2 = <the new backout rev>.

2. An example:

$ hg init borepo
$ cd borepo
$ echo line1 > file.txt
$ echo line2 >> file.txt
$ hg ci -Am "add file"

Edit file.txt, so it contains:

line1
line1a
line2

Commit and add a few more changesets:

$ hg ci -m "add line1a"
$ echo line3 >> file.txt
$ hg ci -m "add line3"
$ echo line4 >> file.txt
$ hg ci -m "add line4"

Which produces the following (somewhat shortened) graph:

@  changeset:   3:36b1c0649d3e
|  tag:         tip
|  summary:     add line4
|
o  changeset:   2:2612107e45fe
|  summary:     add line3
|
o  changeset:   1:1f33c361852e
|  summary:     add line1a
|
o  changeset:   0:e3e45b087239
   summary:     add file

Now we backout changeset 1:1f33c361852e.

$ hg backout -r 1

The graph is now:

o  changeset:   4:c3daad6d657d
|  tag:         tip
|  parent:      1:1f33c361852e
|  summary:     Backed out changeset 1f33c361852e
|
| @  changeset:   3:36b1c0649d3e
| |  summary:     add line4
| |
| o  changeset:   2:2612107e45fe
|/   summary:     add line3
|
o  changeset:   1:1f33c361852e
|  summary:     add line1a
|
o  changeset:   0:e3e45b087239
   summary:     add file

We merge and commit, yielding the final graph:

@    changeset:   5:236d8d74edf8
|\   tag:         tip
| |  parent:      3:36b1c0649d3e
| |  parent:      4:c3daad6d657d
| |  summary:     merge backout
| |
| o  changeset:   4:c3daad6d657d
| |  parent:      1:1f33c361852e
| |  summary:     Backed out changeset 1f33c361852e
| |
o |  changeset:   3:36b1c0649d3e
| |  summary:     add line4
| |
o |  changeset:   2:2612107e45fe
|/   summary:     add line3
|
o  changeset:   1:1f33c361852e
|  summary:     add line1a
|
o  changeset:   0:e3e45b087239
   summary:     add file

And file.txt looks like this, nicely eliminating the 'line1a' from rev 1.

line1
line2
line3
line4



When we try this using the separate steps, and we omit step 4, we get a slightly different graph. Note the reversed order of the parents in changeset 5:0eeac5ff9c76.

@    changeset:   5:0eeac5ff9c76
|\   tag:         tip
| |  parent:      4:cbca219e80e1      | <---
| |  parent:      3:f82e9468d652      |
| |  summary:     merge backout
| |
| o  changeset:   4:cbca219e80e1
| |  parent:      1:0cf85b44002c
| |  summary:     Backed out changeset 0cf85b44002c
| |
o |  changeset:   3:f82e9468d652
| |  summary:     add line4
| |
o |  changeset:   2:24ceac6b9018
|/   summary:     add line3
|
o  changeset:   1:0cf85b44002c
|  summary:     add line1a
|
o  changeset:   0:73af1be51d81
   summary:     add file

3. Backout of a Merge Changeset

Warning

Backing out a merge will lead to trouble if you ever want to redo the merge. The only safe way to deal with a bad merge is to abandon the branch.

Imagine a situation where we merge two changesets. The first changeset has a b in a given file, the other has x y in the same file. The merge gives an conflict which we resolves:

We work a little on the top branch to add c in the file. We then discover that the merge was bad. We back it out:

The new red changeset is the backout, it has removed the Y and X lines from the bad merge, but it kept the new c line that was added after the merge.

We make some more changes on the bottom branch and merge it again:

The idea is that the new merge changeset should contain the x y z lines along with the a b c lines. However, what happens is that the merge back out the x and y lines!

The greatest common ancestor of the red a b c changeset and the blue x y z changeset is the green changeset with x y. The three way merge thus considers the file in these configurations:

  • base: x y

  • local: a b c

  • other: x y z

The merge algorithm concludes that the x and y lines were removed on purpose, while a b c and z were added. The result is that the x y lines are silently discarded!

4. See Also


CategoryCommand

Français

Backout (last edited 2019-11-01 00:19:51 by IanMoody)