3

It must be very obvious, but I found no way to do it. Every manual describes rebasing onto a top of existing branch or simple interactive rebase and that's all. Suppose, I have a diamond-shaped git history like that:

*   949430f Merge commit (D) (HEAD, mybranch)
|\  
| * e6a2e8b (C)
* | 3e653ff (B)
|/  
*   9c3641f Base commit (A)

and i want to archieve history like:

*   949430f Combined commit (BCD)
|  
*   9c3641f Base commit (A)

Commits B and C may be melted or discarded at all, doesn't matter, I want to preserve only the result. Also I DO NOT want to revert commits because of nasty conficts resolving.

Here things I've tried:

1) I can't archeve that by simple squashing B and C

git rebase -i HEAD~2
...
p 3e653ff (B)
f e6a2e8b (C)
...
Could not apply a91f3a4

Well, that's somewhat understandable, there're some conflicts.

2) I can't archeve that by squashing.

git rebase -i -p HEAD~3
...
pick 9c3641f Base commit (A)
f 3e653ff (B)
f e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: unable to match a91f3a4...

3) I can't even discard B and C

git rebase -i -p -m HEAD~3
...
pick 9c3641f Base commit (A)
#pick 3e653ff (B)
#pick e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: Commit 949430f is merged but option -m is not set.
fatal: cherry-pick failed
Could not pick 4f3e6231b5cecf57434613ca3afd2a21ba375eb9

Why? Here is option "-m"...

Does anyone know how to solve this problem?

3 Answers3

6

What you want is git reset --soft (plus a commit as noted by aragaer). Despite the different circumstances in the question, see this answer by VonC.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • 2
    And the full answer would be `git reset --soft commitA; git add .; git commit -m "Combined commit"`. – aragaer Jun 29 '15 at 18:03
  • 1
    You don't need to `git add`: the soft reset leaves the index as is. (I'm assuming you're at the tip of the branch, on commit `D`, here. Remember that git stores files, not deltas; if you're on commit `D` and have that in the index, those are the latest files.) – torek Jun 29 '15 at 19:06
  • That's even better 8) – aragaer Jun 29 '15 at 22:55
  • @aragaer: Though I'll note that in general the `git add .` won't *hurt* either (unless there are stray files lying around that get added, but presumably you'd have your `.gitignore` set up properly by this point...). – torek Jun 29 '15 at 23:40
  • I had an urge to add `git clean -qdf` in the beginning just for that. – aragaer Jun 30 '15 at 07:24
  • Wow, thank you, guys, it really is simple. I guess, I was misleaded by the whole "rewrite history" thing. – ScalewingedAcidicorn Jun 30 '15 at 08:22
1

I'd try linearizing the commit graph first, and then squashing them together:

$ git checkout commitA -b newbranch
$ git cherry-pick commitB
$ git cherry-pick commitC
[resolve any conflicts]
$ git rebase -i commitA
[change the command for commitC to 'squash']
musiphil
  • 3,837
  • 2
  • 20
  • 26
1
git rebase -i 9c3641f^ # 1 before base commit

then in the interactive editor

pick 9c3641f Base commit (A)
pick 3e653ff (B)
fixup e6a2e8b (C)
fixup 949430f Merge commit (D) (HEAD, mybranch)

I would actually expect the last one to not be present because merge commits disappear during an interactive rebase in my experience.

That will squish B and C into one commit. D will disappear and you don't really want it anyway since it's not adding code.

That will give you the desired output. The conceptual thing you missed was that you need to keep the first commit (pick) but if you "fixup" the other two they will merge into it. You need to give them something to merge into that is not the base commit. So you pick the second, and then the third merges into it giving you two commits.

You could also do

git rebase -i 9c3641f

and then just wouldn't see the base commit in the interactive editor but the pick and fixup would be the same for the remaining lines.

masukomi
  • 10,313
  • 10
  • 40
  • 49
  • I've tried that. Git refuses to squish B and C into one commit. But thank you anyway. – ScalewingedAcidicorn Jun 30 '15 at 08:26
  • I do it ALL the time. can you clarify "refuses to squish"? Conflict? or?? feel free to ping me on twitter and we can work it out (especially if there's a public branch I can poke) – masukomi Jun 30 '15 at 15:50