Hello, there.

Usually, there is no need to remove the git history in a repository.

But there are some "real life" scenarios where you'd want to start fresh from a git history perspective, like:

- commits that contain sensitive data

- weird and unorganized git history

My use case was to simplify and unclutter the git history for a library that had to be transitioned from a private repository to a public repository.

Because this library was going to be accessible for all developers, I wanted to remove the intermediate changes, reversal, gitignore updates or the tags&releases. This way, the library repo looked polished and easy to follow.

Resetting to "Initial commit" strategy

Create a backup branch

git branch branch-before-reset

Get the initial commit's sha id

git rev-list --max-parents=0 HEAD
  1. This command git rev-list will list all the commit SHAs, starting from the current commit backwards.
  2. The option --max-parents=0 filters this list to include only commits without parents, which, in a typical repository, should only be the initial commit.
  3. HEAD specifies that you want to start from the latest commit on the current branch. This command will output the SHA of the initial commit, which is what you're looking for as .

Soft reset and amend

git reset --soft <root-sha-id>
  1. git reset is a command used to reset your current HEAD to the specified state. There are three modes in which git reset operates: --soft, --mixed (the default), and --hard.
  2. --soft Soft reset moves the HEAD pointer to this commit but does not touch the index file or the working tree. This means that all the changes from all commits that came after the root commit are preserved in the staging area, ready to be re-committed.
  3. <root-sha-id> specifies that the reset targets the commit identified by <root-sha-id>, which is the SHA ID of the first commit in the repository (its root).

Commit the changes

git commit --amend -m "Initial commit"

This step modifies the most recent commit. Because we just performed a soft reset, all the changes are staged.

Thus, the initial commit will modify the initial commit to include the changed files.

Force push the new history

git push --force

Update your remote repository with the new history by forcefully pushing the "Initial Commit."

Git manages and tracks changes accross different repositories: local and remote.

When you amend the commit history locally (squashing multiple commits, resetting to an initial commit, or other approach to rewrite history) you create a different version of the repository than the remote one.

To prevent data loss, git wants to preserve the timeline. When you try to push the local commit from a diverged history, the normal push is rejected. That is why we need to force the push.

Verify the changes

git diff branch-before-reset

Always double-check to ensure your project's current state for unintended alterations.


Orphan branch strategy

Another approach that works is to create an orphan branch without any history of the previous commits.

Create an orphan branch

git checkout --orphan new-main-branch

Stage all files

git add -A

Add all project files to this new branch prepare them for a fresh "Initial commit".

Commit

git commit -m "Initial commit"

Delete the old "main" branch

git branch -D main

Remove the previous main branch to make way for this fresh start. Note, this action is irreversible.

Make the orphan brach the new "main"

git branch -m main

Rename your new branch to 'main', establishing it as the default branch of your project.

Force push the changes

git push -f origin main

Update your remote repository with the new history by forcefully pushing the "Initial Commit."

Git manages and tracks changes accross different repositories: local and remote.

When you amend the commit history locally (squashing multiple commits, resetting to an initial commit, or other approach to rewrite history) you create a different version of the repository than the remote one.

To prevent data loss, git wants to preserve the timeline. When you try to push the local commit from a diverged history, the normal push is rejected. That is why we need to force the push.

Conclusions

Both strategies are effective. Remember, the choice between resetting to an "Initial Commit" or creating an orphan branch depends on your specific needs and preferences for presenting the repository.

Thank you for reading! If you enjoyed this post and want to explore topics like this, don’t forget to subscribe to the newsletter. You’ll get the latest blog posts delivered directly to your inbox. Follow me on LinkedIn and Twitter/X. Your journey doesn’t have to end here. Subscribe, follow, and let’s take continue the conversation. This is the way!