26

I'm merging upstream changes to my project, and recently there were a lot of commits that created a lot of merge conflicts. It doesn't make sense to try to resolve them all at once.

How can I find out which commits create a conflict? Any of the following are acceptable:

  • A way to make Git stop merging as soon as it finds a conflict
  • A way to make Git list all the commits that conflicted, in chronological order
  • Anything else that lets me resolve the conflicts one-by-one, in chronological order, that doesn't involve merging a few commits at a time hoping to stumble upon the conflicts
Davis Sorenson
  • 408
  • 5
  • 13
  • 2
    Git a bit differs from svn. It tries to merge all commits at once. You can try interactive rebase, which applies commits one by one and fails as soon as conflict found. – madhead Aug 10 '13 at 14:49

4 Answers4

19

You can give git imerge a try: that will apply your commits one by one, giving you the chance to do a rebase incrementally (meaning you can start a rebase, interrupt it, resume it later!).

You can see here a comparison between Incremental merge vs. direct merge vs. rebase.

iconoclast
  • 21,213
  • 15
  • 102
  • 138
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • `git imerge` is definitely useful. – John Szakmeister Aug 10 '13 at 16:08
  • Thanks! This is also a good solution, but git-mergemate does exactly what I had in mind by default. git-imerge is also good, but a little bit overkill for my needs. – Davis Sorenson Aug 10 '13 at 16:32
  • 1
    Instead of using an external tool like `git imerge`, you could also just try [cherry-picking](https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html) a range of revisions to see what conflicts, one at a time (it's basically like a `rebase`). –  Aug 10 '13 at 17:48
7

Michael Haggerty also has a tool called git-mergemate that has a find-conflict command:

git-mergemate find-conflict BRANCH1..BRANCH2

Use bisection to determine the earliest commit on BRANCH2 that causes a conflict when merged to BRANCH1. Don't actually retain any merges.

git-mergemate find-conflict BRANCH1...BRANCH2

Use bisection to find a pair of earliest commits (one from each branch) that do not merge cleanly. Don't actually retain any merges.

git imerge can be used to do an incremental merge and resolve conflicts along the way, though it does not have the equivalent of find-conflicts in git-mergemate.

John Szakmeister
  • 44,691
  • 9
  • 89
  • 79
  • 3
    Following the link, it seems as though `git-mergemate` is actually just an old version of `git imerge`, suggested in VonC's answer below. You should probably edit this answer to point directly to imerge. – Mark Amery Feb 04 '14 at 13:12
3

You can use git log --merge to see all conflicted commits when trying to merge another branch into current branch.

# find all conflicted files
git merge --no-commit --no-ff other_branch | grep "CONFLICT"

# find all commits from 'other_branch' that causes the conflicts
git log --merge | grep commit

# abort "--no-commit" command above, because we only want to test and see
git merge --abort

It will produce something like:

commit bb713a4f01e4e55a2b297f7facf962090c11687f
commit 280d44bd8a569108319080633714fa8398eab3c4
commit 3a99961983f5d3ef4508d2a8457309f779650f68
commit 87239c7fef291206063e2c840270298556ee0ef4
commit f4e27e2d5753a9eaf375da66bc8a3d589a22ba23
commit c4365a21bb85a43f227047ecdda789320aa12918
commit 78572542cf08eb8d61a40b20c12cf11357eeb3df
commit cfbc6ffe334ed5748bd3988d3b48ab42a48eeb6a
commit 88a273099afb49b968ebf4c0c3602a334ef0b2d8

Executing git log --merge without starting a merge (git merge) will produce the following error:

fatal: --merge without MERGE_HEAD?

This command can be executed within the merge process only.

Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87
1

Is there any reason why you wouldn't just want to use rebase (non-interactively) to sync up with changes in the upstream branch? It will stop if there is a conflict on each commit, and then you can resume the rebase when it's resolved. It's like incremental merging, and it's built right into Git, there's no need for an external plugin/tool:

git fetch <remote>
git rebase <remote>/<upstream-branch>
# Conflict on commit X, resolve conflict, then continue the rebase
git rebase --continue

Warning about force pushing rewritten commits

Note, of course, that rebasing your local branch will change the sha IDs of its commits. If you've already pushed the commits that you want to rebase to your remote, then you'll need to force push the new commits to overwrite the old ones, which might pose a potential problem if you're sharing your branch with other people. You can learn more about these problems in:

  • Rebase is fine, but you often wont want to rebase into a branch already pushed upstream (also force-commit may not be an option) – ideasman42 Aug 06 '14 at 17:13
  • @ideasman42 I don't understand what you mean by "force commit". What is that supposed to be? There's no such command or option in Git. Do you mean force *push*? –  Aug 06 '14 at 17:16
  • sorry, I meant `force-push` – ideasman42 Aug 06 '14 at 17:19
  • @ideasman42 also, the original poster is trying to merge in upstream changes into his local branch. My answer doesn't rebase the upstream, it rebases *the unpushed local branch* on top of the upstream. There is no need to force push with my answer, because it doesn't rebase pushed commits. –  Aug 06 '14 at 17:20
  • @ideasman42 am I misunderstanding your first comment? What does it mean to "rebase into" a branch? There's also nothing in the question that says that the original poster has pushed his local changes to the remote repo yet. –  Aug 06 '14 at 17:26
  • @ideasman42 I don't think it was really necessary for me to say anything about rebasing pushed branches, since the original poster never said anything about having already pushed his local branch to the remote, only that he's trying to merge in upstream changes. However, I've gone ahead and added a short note about the potential problems of rebasing pushed commits anyways. –  Aug 06 '14 at 18:18
  • This doesn't help identify the commit on the branch that you're rebasing *onto* that caused a conflict, only the branch you're rebasing. – naught101 Apr 21 '19 at 05:32