0

I want to squash the last 12 commits into one. I tried this command but get a fatal error:

>git rebase -i HEAD~12
fatal: Needed a single revision
invalid upstream HEAD~12

I have one remote repository, I already pushed some commits but it does not really matter because I pushed it to heroku, so this code is not shared with other users. I mentioned it because I know that rewrite history is not good when some commits have been already committed.

>git remote
heroku

The security and heroku branch are already merged into master:

>git branch
  heroku-setup
* master
  security

My commits look like that:

>git log --pretty=oneline
04d85b2959b73daff8ce0d49002c81469748798d Switch to Google OAUth 2.0
862cd0f7a9243d602dbeb1d670c08f20a1b832d8 Switch to Google OAUth 2.0
b25a48a657b9bf5087eaa9c1821163d0746b5ac2 Fix mongodb config
bd4c95dd25056a8a8bc6ed97faf01c7007d3f598 Setup Heroku
c82762c29fc1e5563082d710a1d241ce3ec7681f Setup Heroku
976d2baabe386eb1135e7789be167b081d40eeb0 Setup Heroku
e7ae7dd8755e75fc2bfd4bee460ad7f73b6e8ae4 Setup Heroku
6a389b55b782f37daa1c7434b68fe48100bb79e2 Setup Heroku
c26583bcf92f383c66526a29ee5642c3123b650e Setup Heroku
f7d36cf7215de13ade5ff537c3954f99f05506bd Setup Heroku
1110ed9efc60a27ac6334fb5987110de27983dcc Security with Passport
073d3ba79b727e2dc938aa4345f144baa66e05e3 Security with Passport
b82898acf97cc52f94a08e13388a7641460d8ef2 RequireJS + Nested Layout
8d30a5444244229c443354d7b448098d8ead4083 Project Organization

Basically I want my history to be

<new SHA> Security with Passport
b82898acf97cc52f94a08e13388a7641460d8ef2 RequireJS + Nested Layout
8d30a5444244229c443354d7b448098d8ead4083 Project Organization
7
  • possible duplicate of Squash my last X commits together using Git Commented Jul 12, 2014 at 18:44
  • Might be a duplicate but I would like to understand why the rebase command does not work
    – Sydney
    Commented Jul 12, 2014 at 18:46
  • It should not work because there isn't 12 commits before your current HEAD. Double-check where your HEAD is referring to, or try with the --root option git rebase --root -i
    – VonC
    Commented Jul 12, 2014 at 18:51
  • My current HEAD is git rev-parse HEAD returns 04d85b2959b73daff8ce0d49002c81469748798d. I think I don't get what HEAD~12 does because if I count the number of commits before the HEAD not including it, I have 13.
    – Sydney
    Commented Jul 12, 2014 at 18:56
  • 5
    Why not just say git rebase -i b82898acf97cc52f94a0 explicitly rather that trying to name that same commit by an oblique reference? Commented Jul 12, 2014 at 19:00

1 Answer 1

6

The error you got is not terribly obvious but I believe I know what caused it.

With HEAD~12 you're asking git to follow 12 first-parent links. Meanwhile, with git log --pretty=oneline you get shown parent links ... all parent links, not just first-parent links.

If you add --graph to your git log command, you will see that some of these commits are on different paths through the commit graph. The following is meant only as an illustration, not a proper analysis of the above (there's not enough information to do a proper analysis), but let's say the graph looks like this:

A - B - C1 - D1 - E1 ----- H - I   <-- HEAD=master
      \                      /
        C2 - D2 - E2 ----- G       <-- security
           \             /
             D3 - E3 - F           <-- heroku-setup

This graph contains 14 nodes total (as does your sample git log output). Assuming the first parent of each merge commit (I, G, and F) corresponds to the horizontal direction (and the second to the down-and-left direction), starting from I, commit B is master~5, and hence HEAD~5. Start at node I and count steps to the left: 1 (H), 2 (E1), 3 (D1), 4 (C1), 5 (B).

HEAD~12 means to start at node I and count leftward 12 steps. What happens when you try to move left from commit A?

Note that while I drew this graph left-to-right, with the root-most commit A on the left and the tip commit HEAD on the right, git log --graph draws it more or less bottom to top, by default (various options can shuffle the node ordering). With no options at all, git log sorts by reverse chronological order, but using --graph sets --topo-order unless overridden by some other ordering option.

You can also supply --first-parent to git log to instruct it to look only at each first-parent link (the ones you can name using HEAD~n). See the documentation for git log, or for git rev-list. Git commands generally either take a single revision, which is handled by git rev-parse, or—as with git log—a list of revisions, which is handled by git rev-list. The documentation under gitrevisions is also useful.

4
  • +1. What git log option would show only A, B, C1, D1, E1, H and I then?
    – VonC
    Commented Jul 13, 2014 at 3:47
  • @VonC: presumably you already know, but --first-parent does the trick. I'll add links to git log and git rev-list documentation (though these are, well, perhaps "explosively large" is the right phrase, for anyone not yet familiar with git).
    – torek
    Commented Jul 13, 2014 at 4:46
  • I thought so, but that would be nice to add indeed: the OP will be able to check that a git log --first-parent does not return 12 commits.
    – VonC
    Commented Jul 13, 2014 at 4:47
  • Unfortunately I already rebased everything, so I can't test --first-parent. That answer explains well why HEAD~12 did not work in my case. torek guessed right that commits where on different paths.
    – Sydney
    Commented Jul 13, 2014 at 5:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.