22

Got a file that has two commits of interest, both on the Master branch, both only modifying a single file foo: a previous commit AA, and the current version in HEAD. I would like to merge the two versions of the file, keeping bits of both, into HEAD on Master.

I did the simplest thing that I thought would work:

git checkout -b merge-purgatory AA
git commit -m "pulled foo back from previous commit for merging into HEAD."
git checkout master
git merge merge-purgatory

Which simply overwrites the current HEAD version of foo with AA version. Tried the more verbose git checkout -m as well, same result: a dumb overwrite.

How do I force git to treat the AA version of foo as a conflicting merge with the current HEAD version?

Noel
  • 2,061
  • 4
  • 31
  • 47

4 Answers4

19

If git's merge isn't doing what you want, you could do the following instead:

  1. Make sure that there are no uncommitted changes in the file foo, e.g. by making sure that git status is clean.
  2. Overwrite foo with the version from AA using: git show AA:foo > foo
  3. Selectively stage only the changes from foo that you want with: git add -p foo
  4. Discard all the other changes to foo with git checkout -- foo
  5. Commit the staged changes: git commit

Alternatively, if you'd rather use a graphical diff tool (such as meld), you could just do:

git show AA:foo > old-foo
meld old-foo foo
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • 3
    So basically, just bypass git's knowledge of the previous commit and use a manual merge/mergetool. Was hoping for a more cromulent behavior from git, but this is so simple that I used it successfully and just did a bit of clean-up afterwards. Thanks! – Noel Jan 17 '12 at 18:52
6

I get rid of it using:

git checkout -f b855a13754fabf5cef6ff93ab00558608a839377 -- .

which forces the changes of the commit id into my current branch (master), then I created a new branch (checkout -b) from these applied changes and created a merge request from the latter.

None of the above worked for me :-(

  • This should be the accepted answer. I have used this multiple times to reset the state of a branch to re-apply changes as new changes, when re-introducing them in a PR does not work – Isaac Oct 05 '22 at 18:46
4

The previous answers do not keep the story of the change, so the fact that you used a previous commit to generate the new commit. The following procedure will keep this story.

git checkout -b merge-purgatory AA

here you need to slightly modify your file, for example you can add an empty line. Then

git commit "pulled foo back from previous commit for merging into HEAD."
git checkout master
git merge --no-commit merge-purgatory

In this way the merge will fail and then all you need to do is to solve the conflict. This worked for me.

alexmogavero
  • 537
  • 2
  • 12
1
git merge --no-commit merge-purgatory

would at least give you the opportunity to review:change the merge before committing it.
See also techniques proposed in "How do you merge selective files with git-merge?", based on cherry-picking or checkout.


Regarding forcing the manual merge, you could declare in a .gitatributes file, for that specific file, a merge policy set to unset.

Performing a three-way merge

merge

The attribute merge affects how three versions of a file is merged when a file-level merge is necessary during git merge, and other commands such as git revert and git cherry-pick.
Unset 

Take the version from the current branch as the tentative merge result, and declare that the merge has conflicts. This is suitable for binary files that does not have a well-defined merge semantics.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • And, in any case, "Automatic merge went well; stopped before committing as requested" doesn't quite answer my question: how to prevent the "Automatic merge" from happening, and instead treat the two versions as conflicting (they are, overwriting each other's lines) and requiring a manual merge? – Noel Jan 16 '12 at 08:31
  • @Noel: sorry, I zapped the manual merge part. I have edited my answer. – VonC Jan 16 '12 at 08:35
  • thanks! But, hrm: `echo "* -merge" >> .git/info/attributes` and then `git merge --no-commit merge-purgatory` still results in "Automatic merge went well; stopped before committing as requested". – Noel Jan 16 '12 at 08:58
  • @Noel that looks like http://stackoverflow.com/questions/3122056/how-to-get-3-way-merge-in-git-on-non-conflict-merges and should have worked. Did you set the policy to unset, with a `/path/to/your/file merge=unset` line? – VonC Jan 16 '12 at 09:23
  • ah, didn't understand that I needed both (just tried them individually). Put both in .git/info/attributes, then `git merge --no-commit merge-purgatory` resulted in "Auto-merging search/src/main/webapp/js/search.js CONFLICT (content): Merge conflict in search/src/main/webapp/js/search.js Automatic merge failed; fix conflicts and then commit the result." Which is precisely what I was looking for! – Noel Jan 17 '12 at 18:49
  • However, given the dead-simple approach of @Mark Longair, I would rather not muck about with adding (& afterwards removing) lines from my .git folder just for a case like this. – Noel Jan 17 '12 at 18:50