I got a classic situation - master and multiple branches. I need to merge changes (many changes through multiple commits) into master, but I want to ignore any changes that were made in master itself. I want master to be a clone of my branch.
I know that I could just checkout every file from branch into master and commit changes, but that won't make graph pretty :)
How can I achieve that? Solving merge-conflits is not enough, because there are still some changes that were auto-merged. Do I have to remove them manually or is there some git merge --magic
option that could help me?
ADD: I'd like files to be exact copy between branch and master (not commit history), but I'd like to have all that squished to single commit.
CodePudding user response:
The answer depends on whether you care about preserving the history of the master branch. If you use a git reset --hard
, you'll lose the history of master that diverged from the feature branches.
If you want to maintain history, a better trick would be to do it as two merges, with the first merge using the -s ours
merge strategy.
git checkout feature
git merge -s ours master
git checkout master
git merge --ff-only feature
The first merge, git merge -s ours master
will create an empty merge commit on feature
. The code will be an exact copy of what is on feature
.
The second merge will fast-forward master to the empty merge commit. The end result will be two branches with the exact same code and preserved histories. The code will be an exact copy of what was on feature prior to the two merges.
As far as I know, there isn't a single option/command to perform this operation. -Xtheirs
is not truly a merge strategy, it's just an option for the default merge strategy that tells it how to resolve conflicts.
git merge -s ours
exists specifically for the operation of merging the history of obsolete branches and throwing away the changes. There is no -s theirs
strategy.
The trick here is that you want to throw away the changes on master, but still keep the branch afterwards. Normally you would just delete the obsolete branch after doing an -s ours
merge.
CodePudding user response:
The key here is to realize that Git stores snapshots (which Git calls the tree of a commit). There are no changes in any commit, just a snapshot and some metadata. If you see changes, that's an illusion brought about by taking two commits and comparing them. Think about an old style movie film: each frame of the film holds a snapshot image, frozen in time, and we only see movement because we look at 24 carefully-sequenced frames every second.
What this means is that you can construct a commit "by hand" at any time if you like. If you want the snapshot of commit a123456
to be the next snapshot on the current branch, you simply make a new commit whose parent is the current commit, but whose tree is from commit a123456
:
git commit-tree -m "insert your message here" -p HEAD -p a123456 a123456^{tree}
or similar. The two -p
arguments here make this a merge commit, so that this is the result of the missing -s theirs
merge strategy. This new commit is not yet on any branch, so you now need to update the current branch name, using git merge --ff-only
or git update-ref
.
See jthill's answer to Is there a "theirs" version of "git merge -s ours"? (note that the question itself is now a bit confused due to December 2008 edit to the original October 2008 question, and some answers are about -X theirs
, which is different).