summaryrefslogtreecommitdiff
path: root/.html/dev/merging-structural-changes.html
diff options
context:
space:
mode:
Diffstat (limited to '.html/dev/merging-structural-changes.html')
-rw-r--r--.html/dev/merging-structural-changes.html156
1 files changed, 0 insertions, 156 deletions
diff --git a/.html/dev/merging-structural-changes.html b/.html/dev/merging-structural-changes.html
deleted file mode 100644
index a019d9c..0000000
--- a/.html/dev/merging-structural-changes.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>
- The Codex »
- Merging Structural Changes
- </title>
-
- <link
- rel='stylesheet'
- type='text/css'
- href='http://fonts.googleapis.com/css?family=Buenard:400,700&amp;subset=latin,latin-ext'>
- <link
- rel="stylesheet"
- type="text/css"
- href="../media/css/reset.css">
- <link
- rel="stylesheet"
- type="text/css"
- href="../media/css/grimoire.css">
-</head>
-<body>
-
-<div id="shell">
-
- <ol id="breadcrumbs">
-
- <li class="crumb-0 not-last">
-
- <a href="../">index</a>
-
- </li>
-
- <li class="crumb-1 not-last">
-
- <a href="./">dev</a>
-
- </li>
-
- <li class="crumb-2 last">
-
- merging-structural-changes
-
- </li>
-
- </ol>
-
-
-
- <div id="article">
- <h1 id="merging-structural-changes">Merging Structural Changes</h1>
-<p>In 2008, a project I was working on set out to reinvent their build process,
-migrating from a mass of poorly-written Ant scripts to Maven and reorganizing
-their source tree in the process. The development process was based on having
-a branch per client, so there was a lot of ongoing development on the original
-layout for clients that hadn't been migrated yet. We discovered that our
-version control tool, <a href="http://subversion.tigris.org/">Subversion</a>, was unable
-to merge the changes between client branches on the old structure and the
-trunk on the new structure automatically.</p>
-<p>Curiousity piqued, I cooked up a script that reproduces the problem and
-performs the merge from various directions to examine the results. Subversion,
-sadly, performed dismally: none of the merge scenarios tested retained content
-changes when merging structural changes to the same files.</p>
-<h2 id="the-preferred-outcome">The Preferred Outcome</h2>
-<p><img alt="Both changes survive the
-merge." src="/media/dev/merging-structural-changes/ideal-merge-results.png"></p>
-<p>The diagram above shows a very simple source tree with one directory, <code>dir-a</code>,
-containing one file with two lines in it. On one branch, the file is modified
-to have a third line; on another branch, the directory is renamed to <code>dir-b</code>.
-Then, both branches are merged, and the resulting tree contains both sets of
-changes: the file has three lines, and the directory has a new name.</p>
-<p>This is the preferred outcome, as no changes are lost or require manual
-merging.</p>
-<h2 id="subversion">Subversion</h2>
-<p><img alt="Subversion loses the content
-change." src="/media/dev/merging-structural-changes/subversion-merge-results.png"></p>
-<p>There are two merge scenarios in this diagram, with almost the same outcome.
-On the left, a working copy of the branch where the file's content changed is
-checked out, then the changes from the branch where the structure changed are
-merged in. On the right, a working copy of the branch where the structure
-changed is checked out, then the changes from the branch where the content
-changed are merged in. In both cases, the result of the merge has the new
-directory name, and the original file contents. In one case, the merge
-triggers a rather opaque warning about a “missing file”; in the other, the
-merge silently ignores the content changes.</p>
-<p>This is a consequence of the way Subversion implements renames and copies.
-When Subversion assembles a changeset for committing to the repository, it
-comes up with a list of primitive operations that reproduce the change. There
-is no primitive that says “this object was moved,” only primitives which say
-“this object was deleted” or “this object was added, as a copy of that
-object.” When you move a file in Subversion, those two operations are
-scheduled. Later, when Subversion goes to merge content changes to the
-original file, all it sees is that the file has been deleted; it's completely
-unaware that there is a new name for the same file.</p>
-<p>This would be fairly easy to remedy by adding a “this object was moved to that
-object” primitive to the changeset language, and <a href="http://subversion.tigris.org/issues/show_bug.cgi?id=898">a bug report for just such a
-feature</a> was filed in
-2002. However, by that time Subversion's repository and changeset formats had
-essentially frozen, as Subversion was approaching a 1.0 release and more
-important bugs <em>without</em> workarounds were a priority.</p>
-<p>There is some work going on in Subversion 1.6 to handle tree conflicts (the
-kind of conflicts that come from this kind of structural change) more
-sensibly, which will cause the two merges above to generate a Conflict result,
-which is not as good as automatically merging it but far better than silently
-ignoring changes.</p>
-<h2 id="mercurial">Mercurial</h2>
-<p><img alt="Mercurial preserves the content
-change." src="/media/dev/merging-structural-changes/mercurial-merge-results.png"></p>
-<p>Interestingly, there are tools which get this merge scenario right: the
-diagram above shows how <a href="http://www.selenic.com/mercurial/">Mercurial</a> handles
-the same two tests. Since its changeset language does include an “object
-moved” primitive, it's able to take a content change for <code>dir-a/file</code> and
-apply it to <code>dir-b/file</code> if appropriate.</p>
-<h2 id="git">Git</h2>
-<p>Git also gets this scenario right, <em>usually</em>. Unlike Mercurial, Git does not
-track file copies or renames in its commits at all, prefering to infer them by
-content comparison every time it performs a move-aware operation, such as a
-merge.</p>
- </div>
-
-
-
-<div id="comments">
-<div id="disqus_thread"></div>
-<script type="text/javascript">
- /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
- var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname
-
- /* * * DON'T EDIT BELOW THIS LINE * * */
- (function() {
- var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
- dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
- (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
- })();
-</script>
-<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
-<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
-</div>
-
-
-
- <div id="footer">
- <p>
-
- The Codex —
-
- Powered by <a href="http://markdoc.org/">Markdoc</a>.
-
-<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/merging-structural-changes.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/merging-structural-changes.md">history</a>).
-
- </p>
- </div>
-
-</div>
-</body>
-</html> \ No newline at end of file