Rewrite your git history in 4 friendly commands
Tags: git, webdev, beginners, tutorial
Published: 2022-09-06 19:04:20

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](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.

```bash
# 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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96q7x11angatzib69rh9.png)

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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1yf8nxx8sjbfzfwhnni.png)

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_.

```bash
# 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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hncnjp6oi5b51m0v5vob.png)

## 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.

```bash
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!

```bash
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/df8fkavyjzc4vk3ja0i6.png)

## 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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogqg3cq9gnhe6pvm5ejx.png)

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](https://twitter.com/candosten) has a [great blog post](https://candost.blog/how-to-reset-first-commit-in-git/) 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!