I've recently encountered a git scenario which I don't know how to handle. First let's set the scene.
Suppose you are maintaining a fork of a large open-source project, where upstream is doing development using pull requests (PRs). Since upstream is doing PRs their git history has lots of merge commits.
Periodically you will have to sync your tree with upstream. Typically this goes like so:
git checkout -b sync
git pull upstream master
git add
ing the conflict files, then git commit
.At this point you have a neat little merge commit at the top of the tree. Nested inside are all of upstream's commits and merges. You run your continuous integration tests (CI), they pass and the branch is merged into your fork's master branch. Wonderful.
git checkout -b sync
git pull upstream master
git add
and git commit
them.git pull upstream master
At this point your sync
branch contains two merge commits authored by you. Each individual merge commit contains upstream's various commits and merges.
You could run CI and merge now, but you shouldn't, because your first merge commit will interfere with future git bisects
. Ideally you'd have a single merge commit which is the sum of the two merge commits in sequence.
How does one flatten those two merge commits into one, but preserving upstream's git history?
git rebase --preserve-merges
is a) deprecated, and b) all or nothing. You can't selectively preserve all of upstream's merges, but flatten yours.
I've tried using git rebase --rebase-merges -i origin/master
and marking the second merge f
for fixup, but this doesn't achieve the desired effect. I got merge commits on files I've never touched.
One solution would be to redo the entire merge from scratch now that upstream is fixed. The problem is, even with rerere
this will be a lot of work. In these upstream syncs you end up fixing stuff which isn't a merge conflict, but is (eg) a compilation or logic error. Because these fixes are secondary to merge conflicts (separate commits), rerere
doesn't record automatic resolutions for them.
If I understand correctly, you want a single merge commit: the upstream tree, including recent fixes, merged with your sync
branch. So, that's what you should do: reset your sync branch to the commit prior to the original merge, then perform the merge again.
If you have made additional changes on your sync branch after the original merge but before the upstream fixes became available, you can rebase those commits onto the commit prior to the original merge first:
git checkout -b sync
git rebase --onto ${PREMERGECOMMIT} ${MERGECOMMIT}
git pull upstream master
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.