<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Basic Merging</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Version Control with Subversion" /><link rel="up" href="svn.branchmerge.html" title="Chapter 4. Branching and Merging" /><link rel="prev" href="svn.branchmerge.using.html" title="Using Branches" /><link rel="next" href="svn.branchmerge.advanced.html" title="Advanced Merging" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Basic Merging</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="svn.branchmerge.using.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Branching and Merging</th><td width="20%" align="right"> <a accesskey="n" href="svn.branchmerge.advanced.html">Next</a></td></tr></table><hr /></div><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="svn.branchmerge.basicmerging"></a>Basic Merging</h2></div></div></div><p>Now you and Sally are working on parallel branches of the project: you're working on a private branch, and Sally is working on the <em class="firstterm">trunk</em>, or main line of development.</p><p>For projects that have a large number of contributors, it's common for most people to have working copies of the trunk. Whenever someone needs to make a long-running change that is likely to disrupt the trunk, a standard procedure is to create a private branch and commit changes there until all the work is complete.</p><p>So, the good news is that you and Sally aren't interfering with each other. The bad news is that it's very easy to drift <span class="emphasis"><em>too</em></span> far apart. Remember that one of the problems with the “<span class="quote">crawl in a hole</span>” strategy is that by the time you're finished with your branch, it may be near-impossible to merge your changes back into the trunk without a huge number of conflicts.</p><p>Instead, you and Sally might continue to share changes as you work. It's up to you to decide which changes are worth sharing; Subversion gives you the ability to selectively “<span class="quote">copy</span>” changes between branches. And when you're completely finished with your branch, your entire set of branch changes can be copied back into the trunk. In Subversion terminology, the general act of replicating changes from one branch to another is called <em class="firstterm">merging</em>, and is performed using various invocations of the <span class="command"><strong>svn merge</strong></span> command.</p><p>In the examples that follow, we're assuming that both your Subversion client and server are running Subversion 1.5 (or later). If either client or server is older than version 1.5, then things are more complicated: the system won't track changes automatically, and you'll have to use painful manual methods to achieve similar results. That is, you'll always need to use the detailed merge syntax to specify specific ranges of revisions to replicate (See <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.advancedsyntax" title="Merge Syntax: Full Disclosure">the section called “Merge Syntax: Full Disclosure”</a>), and take special care to keep track of what's already been merged and what hasn't. For this reason, we <span class="emphasis"><em>strongly</em></span> recommend making sure that your client and server are at least version 1.5 or later.</p><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchmerge.changesets"></a>Changesets</h3></div></div></div><p>Before we get too far in, we should warn you that there's going to be a lot of discussion of “<span class="quote">changes</span>” in the pages ahead. A lot of people experienced with version control systems use the terms “<span class="quote">change</span>” and “<span class="quote">changeset</span>” interchangeably, and we should clarify what Subversion understands as a <em class="firstterm">changeset</em>.</p><p>Everyone seems to have a slightly different definition of “<span class="quote">changeset</span>”, or at least a different expectation of what it means for a version control system to have them. For our purpose, let's say that a changeset is just a collection of changes with a unique name. The changes might include textual edits to file contents, modifications to tree structure, or tweaks to metadata. In more common speak, a changeset is just a patch with a name you can refer to.</p><p>In Subversion, a global revision number N names a tree in the repository: it's the way the repository looked after the Nth commit. It's also the name of an implicit changeset: if you compare tree N with tree N-1, you can derive the exact patch that was committed. For this reason, it's easy to think of revision N as not just a tree, but a changeset as well. If you use an issue tracker to manage bugs, you can use the revision numbers to refer to particular patches that fix bugs—for example, “<span class="quote">this issue was fixed by revision 9238.</span>”. Somebody can then run <span class="command"><strong>svn log -r 9238</strong></span> to read about the exact changeset which fixed the bug, and run <span class="command"><strong>svn diff -c 9238</strong></span> to see the patch itself. And (as you'll see shortly) Subversion's <span class="command"><strong>merge</strong></span> command is able to use revision numbers. You can merge specific changesets from one branch to another by naming them in the merge arguments: <span class="command"><strong>svn merge -c 9238</strong></span> would merge changeset #9238 into your working copy.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchemerge.basicmerging.stayinsync"></a>Keeping a Branch in Sync</h3></div></div></div><p>Continuing with our running example, let's suppose that a week has passed since you started working on your private branch. Your new feature isn't finished yet, but at the same time you know that other people on your team have continued to make important changes in the project's <code class="filename">/trunk</code>. It's in your best interest to replicate those changes to your own branch, just to make sure they mesh well with your changes. In fact, this is a best practice: by frequently keeping your branch in sync with the main development line, it helps prevent “<span class="quote">surprise</span>” conflicts when it comes time for you to fold your changes back into the trunk.</p><p>Subversion is aware of the history of your branch, and knows when it divided away from the trunk. To replicate the latest, greatest trunk changes to your branch, first make sure your working copy of the branch is “<span class="quote">clean</span>”—that it has no local modifications. Then simply run:</p><pre class="screen"> $ pwd /home/user/my-calc-branch $ svn merge http://svn.example.com/repos/calc/trunk --- Merging r345 through r356 into '.': U button.c U integer.c </pre><p>Your branch working copy now contains new local modifications, and these edits are duplications of all of the changes that have happened on the trunk since you first created your branch:</p><pre class="screen"> $ svn status M button.c M integer.c </pre><p>At this point, the wise thing to do is look at the changes carefully with <span class="command"><strong>svn diff</strong></span>, then build and test your branch. You might need to resolve some conflicts (just as you do with <span class="command"><strong>svn update</strong></span>), or possibly make some small edits to get things working properly. (Remember, just because there are no <span class="emphasis"><em>syntactic</em></span> conflicts doesn't mean there aren't any <span class="emphasis"><em>semantic</em></span> conflicts!) If you encounter serious problems, you can always abort the local changes by running <span class="command"><strong>svn revert</strong></span> and start a long “<span class="quote">what's going on?</span>” discussion with your collaborators. If things look good, however, then you can submit your changes into the repository:</p><pre class="screen"> $ svn commit -m "Merged /trunk to /my-calc-branch." Sending button.c Sending integer.c Transmitting file data .. Committed revision 357. </pre><p>At this point, your private branch is now “<span class="quote">in sync</span>” with the trunk, so you can rest easier knowing that as you continue to work in isolation, you're not drifting too far away from what everyone else is doing.</p><div class="sidebar"><p class="title"><b>Why Not Use Patches Instead?</b></p><p>A question may be on your mind, especially if you're a Unix user: why bother to use <span class="command"><strong>svn merge</strong></span> at all? Why not simply use the operating system's <span class="command"><strong>patch</strong></span> command to accomplish the same job? For example:</p><pre class="screen"> $ cd my-calc-branch $ svn diff -r 341:HEAD http://svn.example.com/repos/calc/trunk > patchfile $ patch -p0 < patchfile Patching file integer.c using Plan A... Hunk #1 succeeded at 147. Hunk #2 succeeded at 164. Hunk #3 succeeded at 241. Hunk #4 succeeded at 249. done </pre><p>In this particular example, there really isn't much difference. But <span class="command"><strong>svn merge</strong></span> has special abilities that surpass the <span class="command"><strong>patch</strong></span> program. The file format used by <span class="command"><strong>patch</strong></span> is quite limited; it's only able to tweak file contents. There's no way to represent changes to <span class="emphasis"><em>trees</em></span>, such as the addition, removal, or renaming of files and directories. Nor can the <span class="command"><strong>patch</strong></span> program notice changes to properties. If Sally's change had, say, added a new directory, the output of <span class="command"><strong>svn diff</strong></span> wouldn't have mentioned it at all. <span class="command"><strong>svn diff</strong></span> only outputs the limited patch-format, so there are some ideas it simply can't express.</p><p>The <span class="command"><strong>svn merge</strong></span> command, however, can express changes in tree structure and properties by directly applying them to your working copy. Even more important, this command records the changes that have been duplicated to your branch, so that Subversion is aware of exactly which changes exist in each location (see <a class="xref" href="svn.branchmerge.basicmerging.html#svn.branchmerge.basicmerging.mergeinfo" title="Mergeinfo and Previews">the section called “Mergeinfo and Previews”</a>.) This is a critical feature that makes branch management usable; without it, users would have to manually keep notes on which sets of changes have or haven't been merged yet.</p></div><p>Suppose that another week has passed. You've committed more changes to your branch, and your comrades have continued to improve the trunk as well. Once again, you'd like to replicate the latest trunk changes to your branch and bring yourself in sync. Just run the same merge command again!</p><pre class="screen"> $ svn merge http://svn.example.com/repos/calc/trunk --- Merging r357 through r380 into '.': U integer.c U Makefile A README </pre><p>Subversion knows which trunk changes you've already replicated to your branch, so it carefully only replicates those changes you don't yet have. Once again, you'll have to build, test, and <span class="command"><strong>svn commit</strong></span> the local modifications to your branch.</p><p>What happens when you finally finish your work, though? Your new feature is done, and you're ready to merge your branch changes back to the trunk (so your team can enjoy the bounty of your labor.) The process is simple. First, bring your branch in sync with trunk again, just as you've been doing all along:</p><pre class="screen"> $ svn merge http://svn.example.com/repos/calc/trunk --- Merging r381 through r385 into '.': U button.c U README $ # build, test, ... $ svn commit -m "Final merge of trunk changes to my-calc-branch." Sending button.c Sending README Transmitting file data .. Committed revision 390. </pre><p>Now, you use <span class="command"><strong>svn merge</strong></span> to replicate your branch changes back into the trunk. To do this, you'll need an up-to-date working copy of <code class="filename">/trunk</code>. You can do this by either doing an <span class="command"><strong>svn checkout</strong></span>, dredging up an old trunk working copy from somewhere on your disk, or by using <span class="command"><strong>svn switch</strong></span> (see <a class="xref" href="svn.branchmerge.switchwc.html" title="Traversing Branches">the section called “Traversing Branches”</a>.) However you get a trunk working copy, remember that it's a best practice to do your merge into a working copy that has <span class="emphasis"><em>no</em></span> local edits and has been recently updated. If your working copy isn't “<span class="quote">clean</span>” in these ways, you can run into some conflict-related headaches.</p><p>Once you have a clean working copy of trunk, you're ready merge your branch back into it:</p><pre class="screen"> $ pwd /home/user/calc-trunk $ svn merge --reintegrate http://svn.example.com/repos/calc/branches/my-calc-branch --- Merging r341 through r390 into '.': U button.c U integer.c U Makefile $ # build, test, verify, ... $ svn commit -m "Merge my-calc-branch back into trunk!" Sending button.c Sending integer.c Sending Makefile Transmitting file data .. Committed revision 391. </pre><p>Congratulations, your branch has now been re-merged back into the main line of development. Notice our use of the <code class="option">--reintegrate</code> option this time around. The option is needed because this sort of “<span class="quote">merge back</span>” is a different sort of work than what you've been doing up until now. Previously, we had been asking <span class="command"><strong>svn merge</strong></span> to grab the “<span class="quote">next set</span>” of changes one branch and duplicate them to another branch. This is fairly straightforward, and each time Subversion knows how to pick up where it left off. In our prior examples, you can see that first it merges the ranges 345:356 from trunk to branch; later on, it continues by merging the next contiguously available range, 356:380. When doing the final sync, it merges the range 380:385.</p><p>When merging your branch back to the trunk, however, the underlying mathematics is quite different. Your feature branch is now a mish-mosh of both duplicated trunk changes and private branch changes, so there's no simple contiguous range of revisions to copy over. By specifying the <code class="option">--reintegrate</code> option, you're asking Subversion to carefully replicate <span class="emphasis"><em>only</em></span> those changes unique to your branch. (And in fact it does this by comparing the latest trunk tree with the latest branch tree: the resulting difference is exactly your branch changes!)</p><p>Now that your branch is merged to trunk, you'll no longer need your branch. You can do some basic housecleaning in the repository:</p><pre class="screen"> $ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch Committed revision 392. </pre><p>But wait! Isn't the history of that branch valuable? What if somebody wants to audit the evolution of your feature someday, and look at all your commits? No need to worry. Remember that even though your branch is no longer visible in the <code class="filename">/branches</code> directory, its existence is still an immutable part of the repository's history. A simple <span class="command"><strong>svn log</strong></span> command on the <code class="filename">/branches</code> URL will show the entire history of your branch. Your branch can even be resurrected at some point, should you desire. (See <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.resurrect" title="Resurrecting Deleted Items">the section called “Resurrecting Deleted Items”</a>.)</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchmerge.basicmerging.mergeinfo"></a>Mergeinfo and Previews</h3></div></div></div><p>The basic mechanism Subversion uses to track changesets—that is, which changes have been merged to which branches—is by recording data in properties. Specifically, merge data is tracked in the <code class="literal">svn:mergeinfo</code> property attached to files and directories. (If you're not familiar with Subversion properties, now is the time to go skim over <a class="xref" href="svn.advanced.props.html" title="Properties">the section called “Properties”</a>.)</p><p>You can examine the property, just like any other:</p><pre class="screen"> $ cd my-calc-branch $ svn propget svn:mergeinfo . /trunk:341-390 </pre><p>It is <span class="emphasis"><em>not</em></span> recommended that you change the value of this property yourself, unless you really know what you're doing. (An example of this comes up in <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.blockchanges" title="Blocking Changes">the section called “Blocking Changes”</a>.) In general, this property is automatically maintained by Subversion whenever you run <span class="command"><strong>svn merge</strong></span>, and its value indicates which changes have already been replicated into a particular directory.</p><p>As we saw earlier, there's also a subcommand <span class="command"><strong>svn mergeinfo</strong></span>, which can be helpful in seeing not only which changesets a directory has absorbed, but also which changesets it's still eligible to receive. This gives a sort of preview of the next set of changes that <span class="command"><strong>svn merge</strong></span> will replicate to your branch.</p><pre class="screen"> $ svn mergeinfo . Path: . Source path: /trunk Merged ranges: r341:390 Eligible ranges: r391:395 </pre><p>The <span class="command"><strong>svn mergeinfo</strong></span> command, by default, looks back at the history of the thing you're querying and tries to make a sane guess about the “<span class="quote">source</span>” you want to be copying changes from. In our prior example, because we're querying our branch working copy, the command assumes we're interested in receiving changes from <code class="filename">/trunk</code> (since that's where our branch was originally copied from.) However, if another coworker had a different branch going on that we wanted to merge changes from, we could have this command tell us about eligible changesets from that source too:</p><pre class="screen"> $ svn mergeinfo --from-source \ http://svn.example.com/repos/calc/branches/other-branch . Path: . Source path: /branches/other-branch Merged ranges: Eligible ranges: r360:364 </pre><p>Another way to get a more precise preview of a merge operation is to use the <code class="option">--dry-run</code> option.</p><pre class="screen"> $ svn merge http://svn.example.com/repos/calc/trunk --dry-run U integer.c $ svn status # nothing printed, working copy is still unchanged. </pre><p>The <code class="option">--dry-run</code> option doesn't actually apply any local changes to the working copy. It only shows status codes that <span class="emphasis"><em>would</em></span> be printed in a real merge. It's useful for getting a “<span class="quote">high level</span>” preview of the potential merge, for those times when running <span class="command"><strong>svn diff</strong></span> gives too much detail.</p><p>Of course, the best way to preview a merge operation is to just do it! Remember, running <span class="command"><strong>svn merge</strong></span> isn't an inherently risky thing; if you don't like the results, simply <span class="command"><strong>svn revert -R</strong></span> the changes from your working copy and retry the command with different options. The merge isn't final until you actually <span class="command"><strong>svn commit</strong></span> the results.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3><p>While it's perfectly fine to experiment with merges by running <span class="command"><strong>svn merge</strong></span> and <span class="command"><strong>svn revert</strong></span> over and over, you may run into some annoying (but easily bypassed) roadblocks. For example, if the merge operation adds a new file (i.e. schedules it for addition), then <span class="command"><strong>svn revert</strong></span> won't actually remove the file; it simply unschedules the addition. You're left with an unversioned file. If you then attempt to run the merge again, you may get conflicts due to the unversioned file “<span class="quote">being in the way</span>”. Solution? After performing a revert, be sure to clean up the working copy and remove unversioned files and directories. The output of <span class="command"><strong>svn status</strong></span> should be as clean (read: empty) as possible!</p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="svn.branchmerge.using.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="svn.branchmerge.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="svn.branchmerge.advanced.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Using Branches </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Advanced Merging</td></tr></table></div></body></html>