Product SiteDocumentation Site

4.9. Resolve Conflicts (Merging Changes of Others)

Please visit the svnbook section: Resolve Any Conflicts

We've already seen how svn status -u can predict conflicts, but dealing with those conflicts is still something that remains to be done. Conflicts can occur any time you attempt to merge or integrate changes from the repository into your working copy. By now you know that svn update creates exactly that sort of scenario. The very purpose is to bring your working copy up to date with the repository by merging all the changes made since your last update into your working copy. So how does Subversion report these conflicts to you, and how do you deal with them?

Suppose you run svn update and you see this sort of interesting output:

$ svn update
Updating '.':
U    INSTALL
G    README
Conflict discovered in 'bar.c'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options:
The U (which stands for “Updated”) and G (for “merGed”) codes are no cause for concern; those files cleanly absorbed changes from the repository. A file marked with U contains no local changes but was updated with changes from the repository. One marked with G had local changes to begin with, but the changes coming from the repository didn't overlap with those local changes.
It's the next few lines which are interesting. First, Subversion reports to you that in its attempt to merge outstanding server changes into the file bar.c, it has detected that some of those changes clash with local modifications you've made to that file in your working copy but have not yet committed. Perhaps someone has changed the same line of text you also changed. Whatever the reason, Subversion instantly flags this file as being in a state of conflict. It then asks you what you want to do about the problem, allowing you to interactively choose an action to take toward resolving the conflict. The most commonly used options are displayed, but you can see all of the options by typing s:
…
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: s

  (e)  - change merged file in an editor  [edit]
  (df) - show all changes made to merged file
  (r)  - accept merged version of file

  (dc) - show all conflicts (ignoring merged version)
  (mc) - accept my version for all conflicts (same)  [mine-conflict]
  (tc) - accept their version for all conflicts (same)  [theirs-conflict]

  (mf) - accept my version of entire file (even non-conflicts)  [mine-full]
  (tf) - accept their version of entire file (same)  [theirs-full]

  (m)  - use internal merge tool to resolve conflict
  (l)  - launch external tool to resolve conflict  [launch]
  (p)  - mark the conflict to be resolved later  [postpone]
  (q)  - postpone all remaining conflicts
  (s)  - show this list (also 'h', '?')
Words in square brackets are the corresponding --accept option arguments.

Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options:
Before deciding how to attack a conflict interactively, odds are that you'd like to see exactly what is in conflict. Two of the commands available at the interactive conflict resolution prompt can assist you here. The first is the “diff-full” command (df), which displays all the local modifications to the file in question plus any conflict regions:
…
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: df
--- .svn/text-base/sandwich.txt.svn-base      Tue Dec 11 21:33:57 2007
+++ .svn/tmp/tempfile.32.tmp     Tue Dec 11 21:34:33 2007
@@ -1 +1,5 @@
-Just buy a sandwich.
+<<<<<<< .mine
+Go pick up a cheesesteak.
+=======
+Bring me a taco!
+>>>>>>> .r32
…
The first line of the diff content shows the previous contents of the working copy (the BASE revision), the next content line is your change, and the last content line is the change that was just received from the server (usually the HEAD revision).

The second command is similar to the first, but the “display-conflict” (dc) command shows only the conflict regions, not all the changes made to the file. Additionally, this command uses a slightly different display format for the conflict regions which allows you to more easily compare the file's contents in those regions as they would appear in each of three states: original and unedited; with your local changes applied and the server's conflicting changes ignored; and with only the server's incoming changes applied and your local, conflicting changes reverted.

After reviewing the information provided by these commands, you're ready to move on to the next action.

The main way to resolve conflicts interactively is to use an internal file merge tool. The tool asks you what to do with each conflicting change and allows you to selectively merge and edit changes. However, there are several other different ways to resolve conflicts interactively—two of them allow you to selectively merge and edit changes using external editors, the rest of which allow you to simply pick a version of the file and move along. The internal merge tool combines all of the available ways to resolve conflicts.
You've already reviewed the conflicting changes, so it's now time to resolve the conflicts. The first command that should help you is the “merge” command (m) which is available starting with Subversion 1.8. The command displays the conflicting areas and allows you to choose from a number of options to resolve the conflicts area-by-area:
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: m
Merging 'Makefile'.
Conflicting section found during merge:
(1) their version (at line 24)                  |(2) your version (at line 24)
------------------------------------------------+------------------------------------------------
top_builddir = /bar                             |top_builddir = /foo
------------------------------------------------+------------------------------------------------
Select: (1) use their version, (2) use your version,
        (12) their version first, then yours,
        (21) your version first, then theirs,
        (e1) edit their version and use the result,
        (e2) edit your version and use the result,
        (eb) edit both versions and use the result,
        (p) postpone this conflicting section leaving conflict markers,
        (a) abort file merge and return to main menu:
As you can see, when you use the internal file merge tool, you can cycle through individual conflicting areas in the file and select various resolution options or postpone conflict resolution for selected conflicts.
However, if you wish to use an external editor to choose some combination of your local changes, you can use the “edit” command (e) to manually edit the file with conflict markers in a text editor. After you've edited the file, if you're satisfied with the changes you've made, you can tell Subversion that the edited file is no longer in conflict by using the “resolved” command (r). Subversion also provides the “launch” resolution command (l) to fire up a fancy graphical merge tool (see the section called “External merge”).
There is also a pair of compromise options available. The “mine-conflict” (mc) and “theirs-conflict” (tc) commands instruct Subversion to select your local changes or the server's incoming changes, respectively, as the “winner” for all conflicts in the file. But, unlike the “mine-full” and “theirs-full” commands, these commands preserve both your local changes and changes received from the server in regions of the file where no conflict was detected.
Finally, if you decide that you don't need to merge any changes, but just want to accept one version of the file or the other, you can either choose your changes (a.k.a. “mine”) by using the “mine-full” command (mf) or choose theirs by using the “theirs-full” command (tf).
Postponing conflict resolution
If you're doing an update and encounter a conflict that you're not prepared to review or resolve, you can type p to postpone resolving a conflict on a file-by-file basis when you run svn update.
Beginning with Subversion 1.8, an internal file merge tool allows you to postpone conflict resolution for certain conflicts, but resolve other conflicts. Therefore, you can postpone conflict resolution area-by-area, not just on a file-to-file basis.
The C (for “Conflicted”) means that the changes from the server overlapped with your own, and now you have to manually choose between them after the update has completed. When you postpone a conflict resolution, svn typically does three things to assist you in noticing and resolving that conflict:
  • Subversion prints a C during the update, and remembers that the file is in a state of conflict.
  • If Subversion considers the file to be mergeable, it places conflict markers—special strings of text which delimit the sides of the conflict—into the file to visibly demonstrate the overlapping areas. (Subversion uses the svn:mime-type property to decide if a file is capable of contextual, line-based merging.)
  • For every conflicted file, Subversion places three extra unversioned files in your working copy:
    • filename.mine -- This is the file as it existed in your working copy before you began the update process. It contains any local modifications you had made to the file up to that point. (If Subversion considers the file to be unmergeable, the .mine file isn't created, since it would be identical to the working file.)
    • filename.rOLDREV -- This is the file as it existed in the BASE revision—that is, the unmodified revision of the file in your working copy before you began the update process—where OLDREV is that base revision number.
    • filename.rNEWREV -- This is the file that your Subversion client just received from the server via the update of your working copy, where NEWREV corresponds to the revision number to which you were updating (HEAD, unless otherwise requested).
For example, Sally makes changes to the file sandwich.txt, but does not yet commit those changes. Meanwhile, Harry commits changes to that same file. Sally updates her working copy before committing and she gets a conflict, which she postpones:
$ svn update
Updating '.':
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: p
C    sandwich.txt
Updated to revision 2.
Summary of conflicts:
  Text conflicts: 1
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2
At this point, Subversion will not allow Sally to commit the file sandwich.txt until the three temporary files are removed:
$ svn commit -m "Add a few more things"
svn: E155015: Commit failed (details follow):
svn: E155015: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict
If you've postponed a conflict, you need to resolve the conflict before Subversion will allow you to commit your changes. You'll do this with the svn resolve command. This command accepts the --accept option, which allows you specify your desired approach for resolving the conflict. If run without that option, Subversion cranks up its interactive conflict resolution mechanism. Here, we'll discuss the use of the --accept option for conflict resolution.
The --accept option to the svn resolve command instructs Subversion to use one of its pre-packaged approaches to conflict resolution. If you want Subversion to resolve the conflict using the version of the file that you last checked out before making your edits, use --accept=base. If you'd prefer instead to keep the version that contains only your edits, use --accept=mine-full. You can also select the version that your most recent update pulled from the server (discarding your edits entirely) using --accept=theirs-full. (There are other “canned” resolution types, too.)
If you want to pick and choose from your changes and the changes that your update fetched from the server, you can manually repair the working file, fixing up the conflicted text “by hand” (by examining and editing the conflict markers within the file), then tell Subversion to resolve the conflict by keeping the working file in its current state by running svn resolve with the --accept=working option.
svn resolve removes the three temporary files and accepts the version of the file that you specified. After the command completes successfully—and assuming you didn't interactively choose to postpone resolution—Subversion no longer considers the file to be in a state of conflict:
$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'
Manual conflict resolution
Manually resolving conflicts can be quite intimidating the first time you attempt it, but with a little practice, it can become as easy as falling off a bike.
Here's an example. Due to a miscommunication, you and Sally, your collaborator, both edit the file sandwich.txt at the same time. Sally commits her changes, and when you go to update your working copy, you get a conflict and you're going to have to edit sandwich.txt to resolve the conflicts. First, let's take a look at the file:
$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread
The strings of less-than signs, equal signs, and greater-than signs are conflict markers, and are not part of the actual data in conflict. You generally want to ensure that those are removed from the file before your next commit. The text between the first two sets of markers is composed of the changes you made in the conflicting area:
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
The text between the second and third sets of conflict markers is the text from Sally's commit:
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Usually you won't want to just delete the conflict markers and Sally's changes -- she's going to be awfully surprised when the sandwich arrives and it's not what she wanted. So this is where you pick up the phone or walk across the office and explain to Sally that you can't get sauerkraut from an Italian deli. Once you've agreed on the changes to check in, edit your file and remove the conflict markers.
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread
Now run svn resolve, and you're ready to commit your changes:
$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
Naturally, you want to be careful that when using svn resolve you don't tell Subversion that you've resolved a conflict when you truly haven't. Once the temporary files are removed, Subversion will let you commit the file even if it still contains conflict markers.
If you ever get confused while editing the conflicted file, you can always consult the three files that Subversion creates for you in your working copy—including your file as it was before you updated. You can even use a third-party interactive merging tool to examine those three files.