Skip to main content
whitep4nth3r logo

5 Sep 2022

4 min read

Rewrite your git history in 4 friendly commands

Did you make a series of unfortunate commits? Learn how to clean up your nonsense.

I build a lot of public experimental demo repos to support my tutorials, and I often encourage people to fork them and deploy them to Netlify to try things out. The problem is, these experimental repos can often come with a terribly messy git history — and I don't want people to inherit that. And so, before I publish and promote a demo project, I like to clean up the git history ✨.

First, the TL;DR: use these four commands — with caution (more on this later!) — and enjoy a tidy ship.

# 1. Reset the repo to the initial commit, preserving the current state of the files on your local machine
git reset --soft {INITIAL_COMMIT_HASH}

# 2. Stage all files
git add .

# 3. Make a commit
git commit -m "Initial commit"

# 4. Force push to the origin
git push --force

Let's look in detail at what each command does.

Soft reset to the initial commit

Each time you push a change to git, a unique identifier called a commit hash is generated from various bits of data associated with the commit, such as the commit message, file changes, commit author and date. Commit hashes point to the state of the repository when the commit was made, and allow us to move back and forward in time in the repository.

If your repository is hosted on GitHub, you can view a list of your commit hashes from the home page of your repository, by clicking on the commits link at the top right of the file list.

Screenshot of a github repo, showing the commits list link in the active blue colour, highlighted with a white rounded border.

This will take you to a list of commits, showing a shortened commit hash to the right of the commit message. Scroll down to find the first commit, click to view the commit and full commit hash, or use the copy button to copy the full commit hash to your clipboard, which might look something like this: 64d52970e9b73551e7d837ec367610p.

A screenshot of a GitHub commit list, showing a tooltip on the top commit hash, which says view commit details.

There are ways to get the first commit hash using a terminal command, but the method may vary depending on the number of root commits in the history — which is beyond the scope of this blog post.

When you've got your initial commit hash, run the following commands in your terminal. The reset command instructs git to reset the repository to a particular state, in this case the initial commit, and the --soft flag leaves all files in their most recent up-to-date state.

# reset the repo to the initial commit
git reset --soft {INITIAL_COMMIT_HASH}

# check the status of your local repository
git status

You should now see a message stating your branch is behind the main branch by however many commits you made after the first commit, and that there are some changes to be committed.

Terminal output showing a git reset --soft with a hash, then git status which shows the branch is behind origin main by 9 commits, and there are 7 file changes.

Stage all files

Next, use git add . to stage all files. Given that your .gitignore file will remain up-to-date and include any sensitive files you don't want to commit, you should be good to go. But at this point it's worth double-checking that running git status didn't list any files you don't want to add to the repository.

Make a commit

Next it's time to overwrite that history with a nice, tidy commit message. Use Initial commit or whatever commit message you'd like.

git commit -m 'I am rewriting history'

Force push to the origin

It's time to push your new commit to rewrite the history using git push --force. Force pushing tells git to prioritise the changes in your local branch over the changes pushed to the remote. And this is exactly what we want to do in this case! Run the following command in your terminal, and enjoy the power it brings.

Full disclaimer that you should only force push in git when you absolutely know what you're doing, or if your project is tiny and you're the only developer working on it — like most of mine!

git push --force

And just like that, you've pushed a forced update to the repository.

Terminal output showing git commit -m I am rewriting history and git push --force

The result

Go back to GitHub and refresh the list of commits, and you'll see your shiny new commit in the commit list!

A screenshot of the repo I forced push to, showing only two commits.

The keen-eyed perfectionists out there might notice that I now have two commits in the history rather than one single initial commit. However, for me and my purposes this a quick and friendly way to clean up my experimental git history — and gives us all a reminder that nothing in code is ever, really perfect.

If you are interested in completely resetting a git repository to its initial initial commit, the process involves a few more steps (which I think are a little less friendly). One way you can achieve this is by creating an orphan branch from main that contains all the current files, creating a single commit to that branch, and eventually replacing the original main branch with the new branch. Engineering Manager Candost Dagdeviren has a great blog post which lays out the steps.

So go forth and have a little spring clean of your git history — but please remember to do it with caution and only when you really, really need to!

Want weird stuff in your inbox?

Join undefined subscribers in the Weird Wide Web Hole to find no answers to questions you didn't know you had.

Subscribe

Salma sitting cross legged on a sofa, holding a microphone, looking up into the right of the space.

Salma Alam-Naylor

I'm a live streamer, software engineer, and developer educator. I help developers build cool stuff with blog posts, tutorial videos, live coding and open source projects.

Related posts

8 Jun 2022

Build a business card CLI tool

Learn how to use Node.js, npm and npx to build a CLI tool to output a business card to the terminal. Bonus demo repository included!

Tutorials 5 min read →

7 Mar 2022

How to delete all merged git branches with one terminal command

Automate your git cleanup! Here's a shell function to add to your bashrc/zshrc file to delete all merged git branches in one command.

Git 1 min read →