0

I guess "octopus" strategy sounds a bit like this, though I don't understand the complexities.

What I'd really like to be able to do is take file-level merge conflicts and just apply all changes. Perhaps as a consequence, I would be OK with the order of theirs / ours not being deterministic.

This would be nifty, though probably not a huge feature for a lot of people. For example, something like:

git merge my-branch -X both or git merge -s naive?

Curious if anyone has used something like this.

Brian Peterson
  • 2,800
  • 6
  • 29
  • 36
  • you can always create your own merging strategy and apply it using the .gitattributes mechanism. – Serge Feb 26 '20 at 19:51
  • 1
    If I do get you right, you basically want the file in the state git leaves them on the file system when there are merge conflicts. minus the `<<<<<<` and `>>>>>>` lines? – Ente Feb 26 '20 at 20:51
  • Does this answer your question? [git merge, keep both](https://stackoverflow.com/questions/13263902/git-merge-keep-both) – grg Feb 26 '20 at 21:24
  • It *asks* my question, but I don't feel it adequately answers it, because it's not clear how to or if it's really possible to get it working using the suggested approach. Should I say it answers my question, in that case? – Brian Peterson Mar 09 '20 at 16:45
  • What I understand is, you want to include all changes even if they are conflicting from ours and theirs side, and the resultant file will possibly contain duplicates ? and you don't want to resolve this conflict manually ? Correct ? – Muhammad Tariq Jan 18 '21 at 05:56

1 Answers1

1

The usual term for this is union merge; see the link in grg's comment. There is no -s strategy, and no -X eXtended-option to any of the existing strategies, to make the low level file merge use union merge. You can, however, create a .gitattributes file and specify merge=union there, and the git merge-file command has a --union option, as well as the --ours and --theirs options.

(Presumably no one put -X union in as an extended argument to the existing recursive/resolve strategy because it is so relatively uncommon to want it.)

Discussion of merge strategies

The octopus strategy is very special: it implements a relatively simple merge that allows you to merge more than one other commit into the current (HEAD) commit. It requires that this merge have no conflicts anywhere as it has no place to record all the temporary inputs. The resolve and recursive strategies handle merge conflicts by copying the three input files—merge base, --ours, and --theirs—into the index, in the three index slots, and then using the existing git merge-file code1 to merge those three files, writing conflict markers into the final output version.

Note that the -s resolve strategy, implemented by the git merge-resolve command, is the same as git merge-recursive (and implemented by the same underlying code) with one exception: if git merge-recursive finds two or more merge base commits, git merge -s resolve simply picks one of them at random, while git merge-recursive first merges the merge bases to make a new commit, then uses the new commit as the merge base.

The -s subtree strategy is the recursive strategy; it just does some file renaming along the way.

The remaining strategy (-s ours) does not even compute a merge base since it is not actually doing any merging.

In effect, then, there are really only two merge strategies: recursive, and octopus. The remaining strategies are just modifications of recursive, or not merge operations at all (-s ours).

You can write your own merge strategy. Simply write any command, in any source language, and name the executable binary git-merge-foo or git-merge-xyzzy or whatever. Running git merge -s foo or git merge -s xyzzy will now invoke your strategy, with undocumented arguments that you must puzzle out. These arguments should drive your selection of a merge base and your merging process. Everything is left to your own code, including how to define and implement the merge, and how to git add the resulting files to the index, and how to run git commit (if you're going to run it at all). To make a future commit record an actual merge, your command should leave the correct bread-crumb-trail files in the Git directory (git rev-parse --git-dir) based on the current work-tree (since Git 2.5).


1It doesn't literally run git merge-file: instead, the base code for doing merges is in various source files, and both git merge-file and git merge-recursive invoke that same base code. That code takes three inputs, and writes one output. For git merge-recursive, the three inputs are stored in the index; for git merge-file, the three are stored in three file-system files. The output in all cases is the work-tree copy of the file. If the merge succeeds without conflicts, git merge-recursive moves that file to staging slot zero and proceeds without conflicts, but git merge-file simply exits with a zero status. If that merge hits conflicts, or fails for other reasons, git merge-recursive leaves the mess behind in the index and your work-tree and moves on to the next file as usual, while git merge-file simply exits with a nonzero status.

torek
  • 448,244
  • 59
  • 642
  • 775