2

When merging branch Source into Target, I get ~1K conflicts and I've noticed the following:

  1. All conflicted files under path MyRepo\SomeFolder\A\ should be picked from Source branch. E.g. "MyRepo\SomeFolder\A\File1.txt, MyRepo\SomeFolder\A\File2.script"
  2. All conflicted files under path MyRepo\SomeFolder\B\ should be picked from Target branch. E.g. "MyRepo\SomeFolder\B\File3.csproj, MyRepo\SomeFolder\B\File4.txt"
  3. Small number of files from other paths should be manually resolved by picking fractions of code from both Source and Target.

Bullet 3 I can resolve manually. The number of conflicts in buckets 1. and 2. is huge. Is there a way to run a batch script/command that can resolve all the conflicts in 1/2?

Something like (pseudocode):

Foreach file in path
    if file is conflicted/ contains '<<<<'
       pick it from Source and resolve that conflict(or Target, depending on scenario 1 or 2)

Also, if there's a gui doing this, that would be even better, but I'm sure I'm asking too much :)

Alcibiades
  • 335
  • 5
  • 16
  • Idea: if the commit could be broken up into commits for just one directory at a time, you could just use ours/theirs. Of course you wind up with multiple merge commits... – matt Dec 14 '20 at 19:55

3 Answers3

0

What's needed here is a way to invoke git merge-file on the three input files from each conflicted merge. (This is one area where Mercurial's existing tools are better than Git's, as it has this built in.)

Given such a tool, you would:

  • list out the file names
  • divide the list into three parts: "automatic ours", "automatic theirs", and "manual"
  • use this tool (which runs git merge-file with options you specify, but on those three input files) with --ours or --theirs as appropriate, and then git add-s the results
  • manually resolve the remaining files.

This tool almost exists: git mergetool contains all the mechanisms you'd need to invoke the tool correctly, but git mergetool itself is pretty complicated. Modifying it to become the desired tool is hard.

An imitation of the tool that should exist can be constructed by leaning on git show to extract each of the three files, one at a time, from Git's index. Given the conflicted file F, there are three copies of F In Git's index right now. The merge base version of F is in :1:F, the --ours version is in :2:F, and the --theirs version is in :3:F. This may not correctly account for file rename operations though. It's probably better to use git checkout-index the way the mergetool code does.

To get a list of unmerged files, use git ls-files -u. (Note that this enables --stage.)

To run git merge-file, feed it checked-out (i.e., usable plain-text file) copies of the three inputs from each file. Add the desired merge option (--ours, --theirs; if you're working on the tool, it's probably reasonable to allow --union as well) for automated resolution of conflicts. Then, consider doing the rest of what git mergetool does: automatically git adding the result.

Writing the actual tool for this is left as an exercise.

torek
  • 448,244
  • 59
  • 642
  • 775
0

You can use git checkout --ours/--theirs -- directory/path.

It will change the content of files on disk only for conflicting files, and will still list the files as conflicting, so you can check that the content is to your liking, and run git checkout --[other-side] if you realize you chose the wrong side.

If you realize you need to return to the conflicting content for a file or directory, you can run :

git checkout -m -- file/or/directory

If by Source and Target you mean :

# from branch Target :
git checkout Target

# you are merging Source :
git merge Source

Then :

  • Source is --theirs
  • Target is --ours

The commands to run would be :

git checkout --theirs -- SomeFolder\A
git checkout --ours -- SomeFolder\B

If you are happy with the content for SomeFolder\A, run git add SomeFolder\A to remove the conflicting state and stage it for committing.

The downside is, as @torek indicated, that you won't have access to --theirs/--ours/-m versions anymore.

LeGEC
  • 46,477
  • 5
  • 57
  • 104
0

You should be able to do what you want using git-resolve-conflict. This is a small wrapper for git merge-file written by jakub.g. You can either check it out as a script from

https://github.com/jakub-g/git-resolve-conflict

or install it using

npm install -g git-resolve-conflict

It is just a small bash script that lets you resolve merge conflicts for specific files using a given strategy more easily (cmp. this SO answer).

To do this for all files of your subdirectories in a specific way, you could do something like this.

for ITEM in $(git diff --name-only --diff-filter=U | grep 'SomeFolder/A/'); do git-resolve-conflict --theirs $ITEM; done
for ITEM in $(git diff --name-only --diff-filter=U | grep 'SomeFolder/B/'); do git-resolve-conflict --ours $ITEM; done

This should also work under Windows if you use a unix-y shell, e.g Git Bash.

buddemat
  • 4,552
  • 14
  • 29
  • 49