117

I have the following in the to-do text of git rebase -i HEAD~2:

pick 56bcce7 Closes #2774
pick e43ceba Lint.py: Replace deprecated link

# Rebase 684f917..e43ceba onto 684f917 (2 command(s))
#
...

Now, when I try to squash the first one(56bcce7) and pick the second one by adding "s" before the first, I get the following error:

Cannot 'squash' without a previous commit

Can someone explain me what it means, and how do I do it?

I want to squash the first commit(56bcce7) and "select and reword" the second(e43ceba) commit

slm
  • 12,534
  • 12
  • 87
  • 106
Dawny33
  • 8,545
  • 11
  • 65
  • 121

7 Answers7

103

I had a similar problem which I solved as follows:

This is the commit group I wanted to squash:

1 s 01cc5a08 Removes open div
2 s a2b6eecf Restores old fonts
3 s 603479ff Cleans left out div
4 pick 5afdbc33 Update: show logo on landing page
5 s 04c1cb13 change version of dev and prod from 1 to 2
6 s bbe6a8f8 Update: show logo on landing page if they have one
7 s c0d6008a Adds check for C users

As you can see, I wanted no. 4, but 1, 2 and 3 had no previous commit to squash into. Hence the Cannot 'squash' without a previous commit error.

My solution was to use the r option for # r, reword = use commit, but edit the commit message

So my commits list looked like this:

1 r 01cc5a08 Removes open div
2 s a2b6eecf Restores old fonts
3 s 603479ff Cleans left out div
4 s 5afdbc33 Update: show logo on landing page
5 s 04c1cb13 change version of dev and prod from 1 to 2
6 s bbe6a8f8 Update: show logo on landing page if they have one
7 s c0d6008a Adds check for C users

After saving, the interactive shell asked me for the rewording of the chosen commit.

After that, my commit log resulted in a single commit which resulted in a cleaner commit history.

Gus
  • 4,483
  • 4
  • 26
  • 29
  • 4
    like me if you got error because you didn't choose any commit to reword or pick and getting mentioned error (on question), you will need to do `git rebase --edit-todo` and fix referring this answer and then do `git rebase --continue` – old-monk Apr 24 '19 at 22:19
  • This answer was concise and to the point, really helped, thanks – gonzofish May 29 '19 at 21:50
97

Interactive rebase presents commits in the reverse order of what you are used to when using git log. git rebase -i replays the selected commits in the exact (top-down) order they are listed in the saved rebase instructions file. When squashing, the commit selected for squashing is combined with the commit that precedes it in the (edited) list, i.e. the commit from the previous line. In your case - there is no previous commit for 56bcce7. You have to do one of the following

  • git rebase -i HEAD~3 (if you want to squash 56bcce7 into 684f917)
  • If you mean to combine 56bcce7 with e43ceba, and e43ceba doesn't depend on 56bcce7, then simply reorder them:

    r e43ceba Lint.py: Replace deprecated link
    s 56bcce7 Closes #2774
    

    UPDATE: Gus's answer below suggests a better way of doing the same, without reordering the two commits:

    r 56bcce7 Closes #2774
    s e43ceba Lint.py: Replace deprecated link
    

    This will squash/merge the two commits into one. When the interactive rebase asks for a reworded commit message for 56bcce7, provide the commit message that describes the union of 56bcce7 and e43ceba.

Community
  • 1
  • 1
Leon
  • 28,052
  • 3
  • 52
  • 82
22

I had this problem and the reason why it happened in my case was that, you cannot squash older commits onto a new commit. Here is an example say you have 3 commits:

1 pick 01mn9h78 The lastest commit
2 pick a2b6pcfr A commit before the latest
3 pick 093479uf An old commit i made a while back

Now if you say git rebase -i HEAD~3 and you do something like

1 pick 01mn9h78 The lastest commit
2 s a2b6pcfr A commit before the latest
3 s 093479uf An old commit i made a while back

This will result in the error:

error: cannot 'squash' without a previous commit You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. Or you can abort the rebase with 'git rebase --abort'.

Solution :

When squashing commits, you should squash recent commits to old ones not vice versa thus in the example it will be something like this:

1 s 01mn9h78 The lastest commit
2 s a2b6pcfr A commit before the latest
3 pick 093479uf An old commit i made a while back

This will work fine, incase you want all your commit messages, I would suggest fixup instead of squash.

slm
  • 12,534
  • 12
  • 87
  • 106
DvixExtract
  • 1,077
  • 11
  • 23
  • 5
    Thank you- I don't squash commits often and the advice to pick the oldest commit is what helped me get past an unhelpful git error. – 0x574F4F54 Sep 14 '18 at 14:29
  • 'lastest' is an ambigous word; (1) because it not an English language word, and (2) because it is one letter away from 'latest', which is an English word and means 'newest'. 'Oldest' would be a better choice than 'lastest'. The confusion is compounded because you are squashing on line number 1, and that will result in an error - the one the OP mentioned. The actual order that comes up in hte editor is from oldest to newest, the opposite of what you are describing. – Craig Hicks Dec 18 '20 at 16:57
7

Squash with the reverse logic. You'll be able to select the desired commit message at the later step.

  • pick the first commit that you don't want the commit-message for.
  • squash or fixup the commit(s) that you want to merge, until the one that has the commit message that you actually wanted.
pick 56bcce7 Closes #2774
squash e43ceba Lint.py: Replace deprecated link
  • confirm the change (:x)
  • delete the commit message(s) that you don't want and leave only the message from the commit that you desire (in this case: Lint.py: Replace deprecated link).
  • confirm the choice (:x)

Hope it's clearer for somebody ✌

Kamafeather
  • 5,651
  • 10
  • 44
  • 74
2

It will be best to just say in the interactive editor containing the commits, git always squash from bottom to top and one should leave a "pick" entry at the top to receive the squashes from below.

ekyu88
  • 21
  • 2
2

I just tried this approach.

git log -n3

This would show the last 3 commits which would give me the idea of what is the latest commit and which one went previously. Now stated rebasing,

git rebase -i HEAD~3

Choose the lastest commit on top of which we need to squash the other two. The commit id which is choosen as base commit would be like,

pick commit_id

For the other two commit ids, change them into,

squash commit_id

or simply,

s commit_id

Tom Taylor
  • 2,378
  • 1
  • 27
  • 48
0

I also have already meet with this problem just now,that's just careless.you can solve the problem like next:when you try to squash the first one(56bcce7) and pick the second one you should add "s" before the second line but not the first one. you can also reference the next web site:http://backlogtool.com/git-guide/en/stepup/stepup7_5.html

  • 1
    Hi ! It would be better if you checkout [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) for future endeavor at Stack overflow. -Thank you – Momin May 27 '17 at 09:04