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:
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.
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:
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.
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.
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”).
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.
mf
) or choose theirs by using the “theirs-full” command (tf
).
p
to postpone resolving a conflict on a file-by-file basis when you run svn update
.
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:
C
during the update, and remembers that the file is in a state of conflict. svn:mime-type
property to decide if a file is capable of contextual, line-based merging.)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).
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.r2At 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
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.
--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.)
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'
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
<<<<<<< .mine Salami Mortadella Prosciutto =======
======= Sauerkraut Grilled Chicken >>>>>>> .r2
Top piece of bread Mayonnaise Lettuce Tomato Provolone Salami Mortadella Prosciutto Creole Mustard Bottom piece of bread
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."
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.