VS 2013 C# and Git: .csproj files don't merge upon pulling

后端 未结 1 717
无人及你
无人及你 2020-12-11 09:40

Me and a friend are working on a project written in C# using VS 2013 Express with Git (not the VS Git Plugin, mind you), and we\'re running into a problem. Our work

相关标签:
1条回答
  • 2020-12-11 10:17

    I'll put this in as an answer, based on Edward Thomson's comment, which contains this link to Merge conflicts in csproj files (haacked.com/archive/2014/04/16/csproj-merge-conflicts). Please note that I know nothing about Visual Studios, C#, or Windows, but I do know about git. :-)

    The problem is that when we pull, the csproj files randomly update. Sometimes they properly update and the files that have been added since the last pull properly show up in VS, and other times the csproj file is completely unaffected.

    First, let's do a few brief review notes:

    1. git pull is just git fetch followed by git merge. You can tell Git to do a rebase instead. This may be a good idea depending on your development flow, but won't change this particular problem, because ...
    2. Nothing else in Git makes merge commits, but ...
    3. Several other commands, including git rebase, use the merge machinery.
    4. Pushing (git push) never does any merging, so you will only see the problem in the "get me new stuff after both I and someone else did something" case. Even then, whether you see the problem depends quite heavily on what you and the someone-else did. This is because the merge machinery, used by both git merge and git rebase, is just not that smart.

    Now let's take a look at the underlying problem, which (based on the link) is that these *.csproj files contain XML: structured data that git's built-in text-oriented merge operations cannot merge correctly.

    Changes conflict when, in the git diff output, two different lines of development (the branches or commits being merged) made different changes to the same region of a single file. One classic example occurs in files when two editors cannot agree on spelling. For instance, I made this change some time ago:

    diff --git a/plates.tex b/plates.tex
    index 09939ca..3dfc610 100644
    --- a/plates.tex
    +++ b/plates.tex
    @@ -15,7 +15,7 @@ that I took on a trip to parts of Australia in February of 2010
     \end{plate*}
     The kangaroo is probably the most widely known marsupial.
     There are actually four species of large kangaroo:
    -the red, the eastern and western gray, and the antilopine.
    +the red, the eastern and western grey, and the antilopine.
     There are also smaller tree-kangaroos and rat-kangaroos.
     
     \begin{plate*}[h]
    

    If I were to merge this with someone else who made a different change to any of the lines shown in the diff, but left "grey" spelled with the letter a, I would get a conflict. For instance, if my editor were to insist that the word be spelled “kangaru”, the changes would conflict:

    Auto-merging plates.tex
    CONFLICT (content): Merge conflict in plates.tex
    Automatic merge failed; fix conflicts and then commit the result.
    

    When git encounters conflicting changes, its usual reaction is to simply declare that there is a conflict and stop. It leaves you with a work-tree version of the file containing conflict markers <<<<<<< ======= >>>>>>> surrounding both sides of the conflict (along with ||||||| above the base version if and only if you set merge.conflictstyle to diff3):

    \end{plate*}
    <<<<<<< HEAD
    The kangaru is probably the most widely known marsupial.
    There are actually four species of large kangaru:
    the red, the eastern and western gray, and the antilopine.
    There are also smaller tree-kangarus and rat-kangarus.
    ||||||| merged common ancestors
    The kangaroo is probably the most widely known marsupial.
    There are actually four species of large kangaroo:
    the red, the eastern and western gray, and the antilopine.
    There are also smaller tree-kangaroos and rat-kangaroos.
    =======
    The kangaroo is probably the most widely known marsupial.
    There are actually four species of large kangaroo:
    the red, the eastern and western grey, and the antilopine.
    There are also smaller tree-kangaroos and rat-kangaroos.
    >>>>>>> master
    
    \begin{plate*}[h]
    

    Again, though, this is the default behavior. You can, through command line switches or a .gitattributes file, change the default.

    You selected the union merge, and the git documentation has been improved a bit:

    union

    Run 3-way file level merge for text files, but take lines from both versions, instead of leaving conflict markers. This tends to leave the added lines in the resulting file in random order and the user should verify the result. Do not use this if you do not understand the implications.

    (boldface mine). The short version here, though, is that git will believe the merge succeeded (well, it did succeed) but will do so by producing an invalid XML file. There are examples on the linked haacked.com page of exactly how this goes wrong for the *.csproj files, but this is generally true of any union merge: it's not smart enough to get the right result and there are few places where it is a reasonable driver. It would make some sense to invoke it manually in some cases, then review the file and make any fixups by hand, but since it just succeeds and lets the merge proceed, you must be very careful with putting it in .gitattributes.

    Ideally, we would like to have a merge driver that understood XML formatting and the intent of a .csproj file (XML formatting alone is not sufficient as the semantics of the markup are not tied to the syntax). Since I do not use VS on Windows, I can only quote the haacked.com article again:

    Another way would be to write a proper XML merge driver for Git, but that’s quite a challenge as my co-worker Markus Olsson can attest to. If it were easy, or even moderately hard, it would have been done already. Though I wonder if we limited it to common .csproj issues could we write one that isn’t perfect but good enough to handle common merge conflicts? Perhaps.

    If the contents are as simple as the example XML, I think such a driver would be not too difficult, so I suspect they get more complicated.

    0 讨论(0)
提交回复
热议问题