Bryan O'Sullivan avatar Bryan O'Sullivan committed 91a936b

Document merge behaviour with file names.

Comments (0)

Files changed (9)

 	hook.msglen \
 	hook.simple \
 	hook.ws \
+	issue29 \
 	mq.guards \
 	mq.qinit-help \
 	mq.dodiff \
 	mq.tarball \
 	mq.tools \
 	mq.tutorial \
+	rename.divergent \
 	rollback \
 	template.simple \
 	template.svnstyle \
 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, 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.)
+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
 this facility, it would simply be too easy for changes to become
 orphaned when files are renamed.
 
+\subsection{Divergent renames and merging}
+
+The case of diverging names occurs when two developers start with a
+file---let's call it \filename{foo}---in their respective
+repositories.
+
+\interaction{rename.divergent.clone}
+Anne renames the file to \filename{bar}.
+\interaction{rename.divergent.rename.anne}
+Meanwhile, Bob renames it to \filename{quux}.
+\interaction{rename.divergent.rename.bob}
+
+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 behaviour is that it always preserves \emph{both}
+names when it merges changesets that contain divergent renames.
+\interaction{rename.divergent.merge}
+
+I personally find this behaviour quite surprising, which is why I
+wanted to explicitly mention it here.  I would have expected Mercurial
+to prompt me with a three-way choice instead: do I want to keep only
+\filename{bar}, only \filename{quux}, or both?
+
+In practice, when you rename a source file, it is likely that you will
+also modify another file (such as a makefile) that knows how to build
+the source file.  So what will happen if Anne renames a file and edits
+\filename{Makefile} to build it under its new name, while Bob does the
+same, but chooses a different name for the file, is that after the
+merge, there will be two copies of the source file in the working
+directory under different names, \emph{and} a conflict in the section
+of the \filename{Makefile} that both Bob and Anne edited.
+
+This behaviour is considered surprising by other people, too:
+see~\bug{455} for details.
+
+\subsection{Convergent renames and merging}
+
+Another kind of rename conflict occurs when two people choose to
+rename different \emph{source} files to the same \emph{destination}.
+In this case, Mercurial runs its normal merge machinery, and lets you
+guide it to a suitable resolution.
+
+\subsection{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~\bug{29}.
+\interaction{issue29.go}
 
 %%% Local Variables: 
 %%% mode: latex

en/examples/issue29

+#!/bin/bash
+
+#$ name: go
+
+hg init issue29
+cd issue29
+echo a > a
+hg ci -Ama
+echo b > b
+hg ci -Amb
+hg up 0
+mkdir b
+echo b > b/b
+hg ci -Amc
+
+#$ ignore: abort: Is a directory: .*
+hg merge
+
+#$ name:
+# This error is expected from the failed merge.
+
+exit 0

en/examples/issue29.go.out

+$ \textbf{hg init issue29}
+$ \textbf{cd issue29}
+$ \textbf{echo a > a}
+$ \textbf{hg ci -Ama}
+adding a
+$ \textbf{echo b > b}
+$ \textbf{hg ci -Amb}
+adding b
+$ \textbf{hg up 0}
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+$ \textbf{mkdir b}
+$ \textbf{echo b > b/b}
+$ \textbf{hg ci -Amc}
+adding b/b
+$ \textbf{hg merge}
+

en/examples/rename.divergent

+#!/bin/bash
+
+hg init orig
+cd orig
+echo foo > foo
+hg ci -A -m 'First commit'
+cd ..
+
+#$ name: clone
+
+hg clone orig anne
+hg clone orig bob
+
+#$ name: rename.anne
+
+cd anne
+hg mv foo bar
+hg ci -m 'Rename foo to bar'
+
+#$ name: rename.bob
+
+cd ../bob
+hg mv foo quux
+hg ci -m 'Rename foo to quux'
+
+#$ name: merge
+# See http://www.selenic.com/mercurial/bts/issue455
+
+cd ../orig
+hg pull -u ../anne
+hg pull ../bob
+hg merge
+ls

en/examples/rename.divergent.clone.out

+$ \textbf{hg clone orig anne}
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+$ \textbf{hg clone orig bob}
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved

en/examples/rename.divergent.merge.out

+# See http://www.selenic.com/mercurial/bts/issue455
+$ \textbf{cd ../orig}
+$ \textbf{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
+$ \textbf{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)
+$ \textbf{hg merge}
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+$ \textbf{ls}
+bar  quux

en/examples/rename.divergent.rename.anne.out

+$ \textbf{cd anne}
+$ \textbf{hg mv foo bar}
+$ \textbf{hg ci -m 'Rename foo to bar'}

en/examples/rename.divergent.rename.bob.out

+$ \textbf{cd ../bob}
+$ \textbf{hg mv foo quux}
+$ \textbf{hg ci -m 'Rename foo to quux'}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.