1

In the following git scenario:

A -- B1 -- B2 -- B3
  \- C1 -- C2 -- C3

I would like to merge C into B, producing another revision D, such that there are NO changes between B3 and D. In other words, the result is:

A -- B1 -- B2 -- B3 -- D
  \- C1 -- C2 -- C3 -/

and D is identical to B3.

Using git merge --strategy-option ours doesn't quite do the right thing: it resolves conflicts in favor of B, but still merges non-conflicting changes.

Alex I
  • 19,689
  • 9
  • 86
  • 158
  • 3
    Out of curiosity what's the point of merging C back if you aren't going to pull in any changes from that branch? – Ben Lindsay Apr 03 '16 at 04:50
  • Oh wait, I guess if C is master and B is a different branch that you want to be master then this would make sense. – Ben Lindsay Apr 03 '16 at 05:01
  • @BenLindsay: All the commits from C have also been cherrypicked into B at one point or another. For reasons that are not obvious to me, this merge still results in a bunch of changes to B... which are certainly bogus, but I do want to merge it to indicate that all the changes are in B as well, and not pick up any new changes in the process. – Alex I Apr 03 '16 at 05:04
  • 1
    What you're asking doesn't make sense. Either C and B are identical working copies, in which case D would be an empty merge commit, or C and B are not identical working copies, in which case D will obviously be a non-empty commit. – mkasberg Apr 03 '16 at 05:07
  • Why don't you compare C and B? `git difftool --dir-diff B..C` – mkasberg Apr 03 '16 at 05:08
  • @mkasberg: Sorry, diagram is not detailed enough. There is in reality mutliple linear commits B1, B2, ... and C1, C2, .... All C commits also appear as a B commit, in the same order (but not necessarily sequentially). – Alex I Apr 03 '16 at 05:09
  • OK, I see what you mean. Let me rephrase my previous statement then. Either all changes from C are already in B, in which case D would be an empty merge commit, or all changes from C are not in B in which case D would be a non-empty commit. Are you sure you didn't miss anything while cherry-picking C into B? Did you look at what changes are actually happening when you do the merge? One way to see them would be to `git diff B3..HEAD` after making the merge commit (which you can always throw away if you don't like it). – mkasberg Apr 03 '16 at 19:27

2 Answers2

2

Jefromi's answer here should help. Basically, assuming the master branch points to C and better_branch points to B, this should work:

git checkout better_branch
git merge --strategy=ours master    # keep the content of this branch, but record a merge
git checkout master
git merge better_branch             # fast-forward master up to the merge
Community
  • 1
  • 1
Ben Lindsay
  • 1,686
  • 4
  • 23
  • 44
  • This looks good, but I'm not sure it has the intended result. `git merge --strategy=ours` only uses `ours` for conflicts, not for all changes. – Alex I Apr 03 '16 at 05:13
  • 1
    Not true--see the "ours" option under the Merge Strategies section of the [git-merge documentation](https://git-scm.com/docs/git-merge). It says "This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head". I just tried it to double-check. For example, doing the merge will get rid of a file that has been added on the branch you want to ignore, where there wouldn't be any expected conflicts in a normal merge. – Ben Lindsay Apr 03 '16 at 05:31
2

I would use

git commit-tree B^{tree} -p B -p C -m "Merge from C but accept no changes"

This prints a commit, which you can fast-forward merge.

The commit-tree says "create a commit whose tree is identical to what is currently in B. Its parents are the current values of B and C." You can then fast- forward this commit into either B or C.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135