Our project is working within fairly close quarters code-wise (a lot of ch开发者_如何学运维anges happening in parallel in a fairly small geographical area of the code), and our feature branch based git workflow works out really nice for our java code.
But the xml/html stuff is not working really well. Simple unrelated changes (a designer adding a surrounding div, a developer changing an id of an element within) gives really disasterous merges.
I realize there may be several options on how to handle this. A good git xml merge would be optimal, or putting restrictions on reformatting of xml/html code another. Not working in such close quarters would be another (unacceptable) option.
How do you solve this problem efficiently ?
Git allows for custom merge drivers, selected via gitattributes per path (e.g. for all *.xml
files).
What you need to find is a XML-aware merge driver, plus possibly also write a simple script to transform between Git conventions and said merge driver conventions. There is for example XML::Merge Perl module. There is XyDiff, but it looks like it lacks three-way merge (and I guess that for XML building 3-way merge from diffs like described in A Formal Investigation of Diff3 paper (PDF) wouldn't work). You can also read Matching, diffing and merging XML blog post (or article referenced therein).
Another solution would be to unset merge attribute for XML files (they would be treated like binary files wrt. merge conflicts), and use some graphical merge tool to resolve merge conflicts, perhaps via git mergetool.
If you know you could automate some of the merge issue you are having with those merges of xml files, you could script those resolutions.
If there is script, you can call them from a merge driver tailored for xml/xhtml files, only in some directories.
See here for a (really simple) of a merge driver.
That way, any conflict which remains (because the merge driver script did not solve it) are legitimate merge issues that need to be addressed.
There was an item noted in comments in another question that now redirects here (How to setup git merge / git pull for xml files?). Logically, this too should be a comment, but it really needs formatting. So, here it is as an answer, with this subject:
Setting merge.conflictStyle
to diff3
can be helpful
Doing:
git config --global merge.conflictStyle diff3
(or the same without --global
if you want it just for one repository, but I prefer the --global
myself) can make the work-tree copy more useful. Note that if you are writing a merge driver, you do not get the work-tree copy as an input. Instead, you get the three files, ours
base
and theirs
, as your three inputs. This is primarily useful if you aren't trying to write your own merge driver (and writing your own is tricky: if it were easy, XML merge would have been solved quite a while ago).
Example
Here are the example inputs from the other posting:
$ cat base
<li>
<span>BA</span>
</li>
$ cat ours
<li>
<span>BA</span>
</li>
<li>
<span>CE</span>
</li>
$ cat theirs
<li>
<span>BA</span>
</li>
<li>
<span>DF</span>
</li>
We can now see how Git will merge these files, using git merge-file
, which is the command line equivalent of one low-level (file-level) operation from a git merge
:
$ cp ours current
$ git merge-file current base theirs
$ cat current
<li>
<span>BA</span>
</li>
<li>
<<<<<<< curr
<span>CE</span>
=======
<span>DF</span>
>>>>>>> theirs
</li>
Here, as you can see, Git has pointed out that the changes in ours
(copied to current
) conflict with the changes in theirs
as compared to base
. However, some parts of the conflict were easy to resolve, so Git did that, and marked only the remaining parts of the conflict.
When we request a diff3
style merge, however, we get this:
$ cp ours current
$ git merge --diff3 current base theirs
$ cat current
<li>
<span>BA</span>
</li>
<<<<<<< curr
<li>
<span>CE</span>
</li>
||||||| base
=======
<li>
<span>DF</span>
</li>
>>>>>>> theirs
There are two differences. Not only does Git add the ||||||| base
section—which in this case, is empty; there are no lines in the merge base input—but it also stops doing a partial resolution of the changes in ours
/ current
with those in theirs
.
(This is necessary since Git now has to show "ours vs base" and "theirs vs base" rather than just "ours vs theirs, after best effort".)
精彩评论