24

I have a git project that has run for a while and now I want to throw away the old history, say from start to two years back from now. With throw away I mean replace the many commits within this time with one single commit doing the same.

I checked git rebase -i but this does not remove the other (full) history containing all commits from git.

Here a graphical representation (d being the changesets):

(base) -> d1 -> d2 -> d3 -> (HEAD)

What I want is:

(base) -> d1,d2 -> d3 -> (HEAD)

How could this be done? Thanks.

EDIT

I got it working with

git rebase -i cd1e8c9

with cd1e8c9 being the start revision (base) to squash. Then I used fixup to meld the revisions together. Thanks.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
schoetbi
  • 12,009
  • 10
  • 54
  • 72
  • possible duplicate of [Collapsing a git repository's history](http://stackoverflow.com/questions/250238/collapsing-a-git-repositorys-history) – Shawn May 14 '15 at 23:14

4 Answers4

37

If you do not really care about the whole history, another simple way to do this would be to take the current branch and create an orphan branch based on this. Then add all files to this branch and make one initial commit (which would lose all history). This can then be pushed to the remote repository.

Assuming you are in the branch that you want to flatten. First check if it is clean:

git status -s

The above command should not output anything.

Now create a orphan branch:

git checkout --orphan flattened

Add all files

git add .

Create single commit

git commit -m "Initial flattened commit"

Check if everything is as wanted and push to remote (ex):

git status -s

# (original_branch being the branch with the full history)
git diff original_branch..flattened  

# (assuming your remote is origin and the branch to overide is master) 
# Think twice before doing this!
git push origin +flattened:master 
murraybo
  • 895
  • 8
  • 13
  • What was this intended to do? Giving this a try I did the above and the server was left with the original branch (master) with no fewer commits - in fact it had one more, the "flattening" commit that was just pushed. Pulling to local master also showed no fewer commits. This seems to do nothing. – Chris Moschini May 31 '16 at 09:58
  • The above sequence of commands should create a new branch with only one commit which contains all files from the branch the local repository was at the beginning. The last push overrides the remote master branch with the "one commit" branch. This removes all history for the master branch. This can be used to shrink the repository afterwards to save space and bandwidth. Maybe you missed or mistyped the step "git checkout --orphan flattened". – murraybo May 31 '16 at 15:02
  • I think where I'm confused is where this then plays out locally. I dug some more after leaving my comment and it appears that this flattens things on the server, but if you then pull from master to master locally, you get that 1 new commit - your local history remains unflattened, and now differs sharply from the server's. To actually flatten it seems everyone would need to clone anew, not pull, which at least needs to be clearly explained here, as it's unlikely to be what some intended when they wanted a flattened history. – Chris Moschini May 31 '16 at 17:03
  • 3
    The sequence above is rewriting the history so that the all local repositories would not have a commit in common with the new content of the remote branch. Therefore everybody would need to force the update from the server, or as you mention reclone the repository. It is not targeting the normal development git cycle. It is aiming at problem were you want to keep things in git but do not care about the history. We used it to reduce the amount of storage needed for a tools repository. It had grown to 18GB in total but the head commit only needed less than 1GB. Nobody cared about the 3 old JDKs. – murraybo May 31 '16 at 19:07
  • 3
    Makes sense, just would make sense to include a final tidbit in your answer with the commands to force that pull from the server to local. – Chris Moschini May 31 '16 at 20:15
  • @ChrisMoschini you can `git checkout -B master` before the push and then just do `git push origin +master` instead, that would make master equal locally and remotely – Vegard Apr 22 '22 at 11:46
4

squash the respective commits into one using git rebase --interactive.

Alan Haggai Alavi
  • 72,802
  • 19
  • 102
  • 127
3

I'm not very comfortable with doing rebasing so try this on a separate clone to see if it works before doing it on your real work space.

Here are my commits

noufal@sanitarium% git log --pretty=oneline
967122e7d4e687c0707d25c62cb0d3b6a45d337f Added h
3b82cae737d5fb3317bc7a686a2fdf0fdd9d1c7e Added g
94d89e0455b12e1e4843e64a8f62f3ad6cdf42f3 Added f
a30321b7a367d9b7da6369783650acadbb773cfb Added e
04453f1c90ffde0574c9c8a76f154d741d7d83f4 Added d
ec723a3266e56cc39967bf117154465575905e31 Added c
f415d1f58e2f7bd4beea80ab9acd8309bf5b64e7 Added b
7f1f8d1f903168aa929818a0eb81e0ec7743fb85 Added a
21790602bd6c0a009899ea33e64fec63559c0a76 Added it

I'm rebasing 04453f1c90ffde0574c9c8a76f154d741d7d83f4 (Added d) onto 21790602bd6c0a009899ea33e64fec63559c0a76 (the first commit) and squashing them all and I do it with this command

git rebase 04453f1c90ffde0574c9c8a76f154d741d7d83f4 --onto 21790602bd6c0a009899ea33e64fec63559c0a76

After I finish this, the logs look like this

noufal@sanitarium% git log --pretty=oneline
c76290666c8b868d36290d8f5276b879bb78d05d Added h
7001ce74f0837b35c0b82abbb82ad8f40801449c Added g
051062042e56759d83258c5e90a9876aa6f52764 Added f
fb1a62b0c0faefa0110ef7b8eee01a13f2f62034 Added e
21790602bd6c0a009899ea33e64fec63559c0a76 Added it

Is this what you're looking for?

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • What version of git do you use? I got: Usage: git rebase ... with git version 1.7.3.1.msysgit.0 – schoetbi Dec 22 '10 at 07:12
  • With option --root I got your result however when I do checkout master the old history will show up again. How can I completley remove it from history? – schoetbi Dec 22 '10 at 07:48
  • You have to squash the commits (`d1` and `d2`) into `d1`. This is done using `rebase`. Shifting your `HEAD` around will only display logs upto that commit. – Noufal Ibrahim Dec 22 '10 at 08:24
  • Then I will try with rebase. Thanks – schoetbi Dec 22 '10 at 08:39
3

This may seems unconventional, but if you don't care about the history, and the repository have only single master branch and have not been published to Github.com or other sites, you can:

  1. Delete hidden .git folder in the root of repo
  2. git init
  3. Commit

Remember the first step will clear all git data including branch and commit, so please be careful.

willnode
  • 1,377
  • 13
  • 17