95

So I'm migrating from svn (code.google.com) to git(github).

I've imported my project from the svn repo, and it imported all the commit history along way. I'm not really proud of those comments as it was one of my first project, not really serious.

I'd like to rebase everything into a single 'initial import' commit.

I've pulled everything on my computer and I'm trying to do that. But all I found was: git rebase -i master but it only rebases new modifications and commits.

How can I clean my github repository from all history with a rebase?

plus-
  • 45,453
  • 15
  • 60
  • 73
  • 1
    To save you time, go to @Toby J's answer or https://stackoverflow.com/a/41769800/495558. – Genzer Sep 08 '19 at 15:26
  • Does this answer your question? [Make the current commit the only (initial) commit in a Git repository?](https://stackoverflow.com/questions/9683279/make-the-current-commit-the-only-initial-commit-in-a-git-repository). Specifically [this answer](https://stackoverflow.com/a/15572071/40342) should be fast and painless. – Joachim Sauer Aug 03 '21 at 20:19

5 Answers5

255

git rebase -i --root will start an interactive rebase of all commits from the beginning.

From there, you can squash all commits into one and/or perform other edits.

Tobias J
  • 19,813
  • 8
  • 81
  • 66
  • Wow, this saves my life! I wanted to keep the small commits messages to polish the final initial commit and this works out of the box. I'm glad that I kept scrolling. – Genzer Sep 08 '19 at 15:22
  • For extra bonus points. git rebase -i --signoff -S --root. This will both signoff and sign the commits with your user, which is something at least I missed the first time, but would have wanted afterwards, and should have done while I was rewriting all history. Now I did it a second time :D – Beamie Apr 28 '22 at 07:32
20

You could rebase and squash everything if you wanted to (except the initial commit) but why bother? Simply delete your .git directory, run git init to recreate it, git add everything, and git commit to make a new initial commit.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • Actually - yours is a better answer for just bundling a single commit. I'll leave mine up just to show that you can specify a commit to start rebasing from. – Abizern Dec 22 '11 at 15:25
  • 1
    Note removing `.git` also removes your hooks and other configuration if you have one. – bfontaine Apr 26 '19 at 12:30
11

Jefromi's answer will work, but if you want to keep your existing repo configuration, or even leave around the commits just in case, you could do the following:

git checkout master

git branch backup optionally leave another branch here in case you want to keep your history.

git reset --soft $SHA_OF_INIT_COMMIT this will update what HEAD is pointing to but leave your index and working directory in their current state. You can get the SHA with git log --pretty=format:%h --reverse | head -n 1, and make this one step with git reset --soft $(git log --pretty=format:%h --reverse | head -n 1)

git commit --amend change your initial commit to point to the current state of your repo.

Kevin M Granger
  • 2,375
  • 23
  • 28
  • As pointed out in [this answer](https://stackoverflow.com/a/1007545/222134), you should not be using git log for scripting. You're better off with `git rev-list --max-parents=0 HEAD` - but I still like your answer as the best one. :) The logic being: 1) Move master to point to 1st commit, 2) change that commit to hold what's in my working directory right now, 3) voila! new initial commit with all changes squashed neatly together :) – Johny Skovdal Jul 27 '18 at 21:13
  • @JohnySkovdal that answer says to instead use "git-log with specified custom format", which I'm doing, no? – Kevin M Granger Jul 30 '18 at 17:01
  • Darn, somehow missed that part. Read it as git log was no good no matter the parameters. Nvm me then. :$ – Johny Skovdal Jul 30 '18 at 18:09
5

Find the hash of the commit that you want to start squashing from say abcd12 and then rebase against that hash specifically.

git rebase -i abcd12

You are using master to rebase against, which performs the rebase against the tip of the master branch.

Abizern
  • 146,289
  • 39
  • 203
  • 257
  • it worked for the history, but the message next to each file still shows the commit message from before. – plus- Dec 22 '11 at 15:35
  • Did you actually squash the files? it gives an option to create a new commit message. – Abizern Dec 22 '11 at 15:47
  • Yeah I did squash everything but the first commit. I've removed all the commit messages. I was seeing it ok in github history, but not on individual files. Maybe it was a cache issue from github though. Anyway thanks, I've ended up initializing a new repo. – plus- Dec 22 '11 at 15:49
  • 1
    This is certainly the right answer if you don't want to squash all the history! Unfortunately due to the way Git thinks, you can't actually squash it all into the initial commit; you'll be left with the initial one and one squashed one after it. (It's also slower, since it has to individually apply each commit.) – Cascabel Dec 22 '11 at 16:20
3

If you'd like to reduce all your history to a single "Initial import" commit, simply remove .git directory and create a new local repository (keeping a backup of the old one). git init . && git add . && git commit -m "Initial import".

Such new repository won't have a common ancestor with the one you've pushed to GitHub, so you'll have to git push --force your newly created repository.

Jan
  • 11,636
  • 38
  • 47