#pragma section-numbers 2 = Backout = `hg backout [OPTION]... [-r] REV` Revert/undo the effect of an earlier [[ChangeSet|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|repository]], and eventually merged. Help text: http://www.selenic.com/mercurial/hg.1.html#backout == 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 `` be the revision we're at when we start the backout. Backout is basically four steps rolled into one: 1. `hg update -C -r ` 1. `hg revert --all -r ` 1. `hg commit` 1. `hg update -C -r ` There's a fifth step that is done automatically if you specify `--merge` : 1.#5 `hg merge ` (merges with the newly committed rev from 3.) And there's a sixth, manual step: 1.#6 `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 = ` and `parent2 = `. == 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 }}} == 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]] ---- CategoryCommand [[FrenchBackout|Français]]