Mercurial_ The Definitive Guide - Bryan O'Sullivan [35]
$ hg status -C
A b
a
R a
As with hg remove and hg copy, you can tell Mercurial about a rename after the fact using the --after option. In most other respects, the behavior of the hg rename command, and the options it accepts, are similar to the hg copy command.
If you’re familiar with the Unix command line, you’ll be glad to know that the hg rename command can be invoked as hg mv.
Renaming Files and Merging Changes
Since Mercurial’s rename is implemented as copy-and-remove, the same propagation of changes happens when you merge after a rename as after a copy.
If I modify a file, and you rename it to a new name, and then we merge our respective changes, my modifications to the file under its original name will be propagated into the file under its new name. (This is something you might expect to “simply work,” but not all revision control systems actually do this.)
Whereas having changes follow a copy is a feature where you can perhaps nod and say “yes, that might be useful,” it should be clear that having them follow a rename is definitely important. Without this facility, it would simply be too easy for changes to become orphaned when files are renamed.
Divergent Renames and Merging
The case of diverging names occurs when two developers start with a file—let’s call it foo—in their respective repositories.
$ hg clone orig anne
updating working directory
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg clone orig bob
updating working directory
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Anne renames the file to bar.
$ cd anne
$ hg rename foo bar
$ hg ci -m 'Rename foo to bar'
Meanwhile, Bob renames it to quux. (Remember that hg mv is an alias for hg rename.)
$ cd ../bob
$ hg mv foo quux
$ hg ci -m 'Rename foo to quux'
I like to think of this as a conflict because each developer has expressed different intentions about what the file ought to be named.
What do you think should happen when they merge their work? Mercurial’s actual behavior is that it always preserves both names when it merges changesets that contain divergent renames.
# See http://www.selenic.com/mercurial/bts/issue455
$ cd ../orig
$ hg pull -u ../anne
pulling from ../anne
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg pull ../bob
pulling from ../bob
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
warning: detected divergent renames of foo to:
bar
quux
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ ls
bar quux
Notice that while Mercurial warns about the divergent renames, it leaves it up to you to do something about the divergence after the merge.
Convergent Renames and Merging
Another kind of rename conflict occurs when two people choose to rename different source files to the same destination. In this case, Mercurial runs its normal merge machinery, and lets you guide it to a suitable resolution.
Other Name-Related Corner Cases
Mercurial has a longstanding bug in which it fails to handle a merge where one side has a file with a given name, while another has a directory with the same name. This is documented as issue 29.
$ hg init issue29
$ cd issue29
$ echo a > a
$ hg ci -Ama
adding a
$ echo b > b
$ hg ci -Amb
adding b
$ hg up 0
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ mkdir b
$ echo b > b/b
$ hg ci -Amc
adding b/b
created new head
$ hg merge
abort: Is a directory: /tmp/issue29Awb9eV/issue29/b
Recovering from Mistakes
Mercurial has some useful commands that will help you to recover from some common mistakes.
The hg revert