Warning: the following is dangerous, as it rewrites history. Always make sure you have a backup of your repo before doing any kind of major history rewriting like this.
Replace the hash in the following with the hash of the parent of the commit you want to have as your new first commit.
git filter-branch --parent-filter '
read parent
if [ "$parent" = "-p 5bdd44e5919cb0a95a9924817529cd7c980f88b5" ]
then
echo
else
echo "$parent"
fi'
This rewrites the parents of each commit; for most commits, it leaves them the same, but the one with the parent matching the given hash, it replaces with an empty parent, meaning it will now become a commit with no parent. This will detach all of your old history.
Note that if what you want to be your first commit is a merge commit, you’ll need to match against something like -p parent1 -p parent2 -p parent3
for each of the parents of the merge commit, in the correct order.
If you want to apply this to all branches and tags instead of just the current branch, pass in --all
at the end of the command (after the script).
After you have done this, and checked that it worked properly, you can delete the original branch and run a gc
to clean out the now unreferenced commits:
git update-ref -d refs/original/refs/heads/master
Note that since git
tends to try to preserve data, in order to actually free up the space you will also have to remove the commits from your reflog, and then run the gc
to clean it up.
git reflog expire --expire-unreachable=all --all
git gc --prune=all
If you are not doing this to save space or eradicate the old commits, you can keep the old history around in a branch, such as git branch old-master refs/original/refs/heads/master
; you can even “virtually reattach” it using git replace
, at which point you would have two unconnected histories (so when you push to a remote repo, you’ll only push the truncated history) but when you look through history in your local repo you will see the full history.