Why does git-rebase give me merge conflicts when all I'm doing is squashing commits?

给你一囗甜甜゛ 提交于 2019-11-28 02:42:09

All right, I'm confident enough to throw out an answer. Maybe will have to edit it, but I believe I know what your problem is.

Your toy repo test case has a merge in it - worse, it has a merge with conflicts. And you're rebasing across the merge. Without -p (which doesn't totally work with -i), the merges are ignored. This means that whatever you did in your conflict resolution isn't there when the rebase tries to cherry-pick the next commit, so its patch may not apply. (I believe this is shown as a merge conflict because git cherry-pick can apply the patch by doing a three-way merge between the original commit, the current commit, and the common ancestor.)

Unfortunately, as we noted in the comments, -i and -p (preserve merges) don't get along very well. I know that editing/rewording work, and that reordering doesn't. However, I believe that it works fine with squashes. This is not documented, but it worked for the test cases I describe below. If your case is way, way more complex, you may have a lot of trouble doing what you want, though it'll still be possible. (Moral of the story: clean up with rebase -i before merging.)

So, let's suppose we have a very simple case, where we want to squash together A, B, and C:

- o - A - B - C - X - D - E - F (master)
   \             /
    Z -----------

Now, like I said, if there were no conflicts in X, git rebase -i -p works as you'd expect.

If there are conflicts, things get a little trickier. It'll do fine squashing, but then when it tries to recreate the merge, the conflicts will happen again. You'll have to resolve them again, add them to the index, then use git rebase --continue to move on. (Of course, you can resolve them again by checking out the version from the original merge commit.)

If you happen to have rerere enabled in your repo (rerere.enabled set to true), this will be way easier - git will be able to reuse the recorded resolution from when you originally had the conflicts, and all you have to do is inspect it to make sure it worked right, add the files to the index, and continue. (You can even go one step farther, turning on rerere.autoupdate, and it'll add them for you, so the merge won't even fail). I'm guessing, however, that you didn't ever enable rerere, so you're going to have to do the conflict resolution yourself.*

* Or, you could try the rerere-train.sh script from git-contrib, which attempts to "Prime [the] rerere database from existing merge commits" - basically, it checks out all the merge commits, tries to merge them, and if the merge fails, it grabs the results and shows them to git-rerere. This could be time-consuming, and I've never actually used it, but it might be very helpful.

If you don't mind creating a new branch, this is how I dealt with the problem:

Being on master:

# create a new branch
git checkout -b new_clean_branch

# apply all changes
git merge original_messy_branch

# forget the commits but have the changes staged for commit
git reset --soft master        

git commit -m "Squashed changes from original_messy_branch"
user28186

I was looking for a similar requirement , i.e. discarding intermeiate commits of my development branch , I've found this procedure worked for me.
on my working branch

git reset –hard mybranch-start-commit
git checkout mybranch-end-commit . // files only of the latest commit
git add -a
git commit -m”New Message intermediate commits discarded”

viola we have connected the latest commit to the start commit of the branch! No merge conflict issues! In my learning practice I have come to this conclusion at this stage , Is there a better approach for the purpose .

Note that -X and strategy options were ignored when used in an interactive rebase.

See commit db2b3b820e2b28da268cc88adff076b396392dfe (July 2013, git 1.8.4+),

Do not ignore merge options in interactive rebase

Merge strategy and its options can be specified in git rebase, but with -- interactive, they were completely ignored.

Signed-off-by: Arnaud Fontaine

That means -X and strategy now work with interactive rebase, as well as plain rebase, and your initial script could now work better.

I was running into a simpler but similar issue, where I had 1) resolved a merge conflict on a local branch, 2) kept working adding lots more little commits, 3) wanted to rebase and hit merge conflicts.

For me, git rebase -p -i master worked. It kept the original conflict resolution commit and allowed me to squash the others on top.

Hope that helps someone!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!