Combine the first two commits of a Git repository?

48,126

Solution 1

Use git rebase -i --root as of Git version 1.7.12.

In the interactive rebase file, change the second line of commit B to squash and leave the other lines at pick:

pick f4202da A
squash bea708e B
pick a8c6abc C

This will combine the two commits A and B to one commit AB.

Found in this answer.

Solution 2

You tried:

git rebase -i A

It is possible to start like that if you continue with edit rather than squash:

edit e97a17b B
pick asd314f C

then run

git reset --soft HEAD^
git commit --amend
git rebase --continue

Done.

Solution 3

A was the initial commit, but now you want B to be the initial commit. git commits are whole trees, not diffs even if they are normally described and viewed in terms of the diff that they introduce.

This recipe works even if there are multiple commits between A and B, and B and C.

# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp

Solution 4

In the case of interactive rebase, you have to do it before A so that the list will be:

pick A
pick B
pick C

to become:

pick A
squash B
pick C

If A is the initial commit, you have to have a different initial commit before A. Git thinks in differences, it will work on the difference between (A and B) and (B and C). Hence the squash not working in your example.

Solution 5

In the case that you have hundreds or thousands of commits, using kostmo's answer of

git rebase -i --root

can be impractical and slow, just due to the large number of commits that the rebase script has to process twice, once to generate the interactive rebase editor list (where you select what action to take for each commit), and once to actually execute the re-application of commits.

Here is an alternative solution that will avoid the time cost of generating the interactive rebase editor list by not using an interactive rebase in the first place. In this way, it's similar to Charles Bailey's solution. You simply create an orphan branch from the second commit, and then rebase all the descendant commits on top of it:

git checkout --orphan orphan <second-commit-sha>
git commit -m "Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

Documentation

Share:
48,126

Related videos on Youtube

Christian
Author by

Christian

SOreadytohelp

Updated on November 22, 2020

Comments

  • Christian
    Christian over 3 years

    Suppose you have a history containing the three commits A, B and C:

    A-B-C
    

    I would like to combine the two commits A and B to one commit AB:

    AB-C
    

    I tried

    git rebase -i A
    

    which opens up my editor with the following contents:

    pick e97a17b B
    pick asd314f C
    

    I change this to

    squash e97a17b B
    pick asd314f C
    

    Then Git 1.6.0.4 says:

    Cannot 'squash' without a previous commit
    

    Is there a way or is this just impossible?

  • CB Bailey
    CB Bailey over 15 years
    Because the old and new initial commits have no common ancestor you may get some unnecessary conflicts as git tries to apply the whole history of master onto a, even though they have a tree in common. By using the --onto option to git rebase you can tell git the correct place to start applying.
  • Bruno Bronosky
    Bruno Bronosky over 12 years
    If you are doing this to quietly fix a github gist, you'll have to add -m "initial" to the commit. ;-)
  • oma
    oma almost 11 years
    git rebase --abort to start over and do it the right way (not squashing the first commit in the editor)
  • Admin
    Admin over 10 years
    Would it be better if the answer was repeated here too? I'm not sure.
  • Alex
    Alex over 9 years
    this triggers a massive interactive rebase when i do the git rebase --onto tmp <sha1_for_B>
  • RominRonin
    RominRonin about 4 years
    Considering I had a brand new repo with only two commits (that I wanted to roll into one), this worked perfectly for me. Thank you @CB Bailey