Replace a commit in git

I have a bad commit from a long time ago, I want to remove it completely from git history as if it never happened. I know the commit id let’s say 1f020. I have tried git rebase and remove it , but there is so many conflicts when rebasing that it is not possible that way. That commit is a simple 1 line change of code and pushing some files not related to the project.
So I want to write that 1 line code change and commit it, then replace somehow replace this new commit with the one a long time ago.

  • Can I undo committing a file while keeping the changes unstaged?
  • git rebase issue reordering
  • Alias “git git” to just “git”?
  • Maintaining iOS app for different countries in one Git repository
  • Protection against git removal of untracked .gitignored files?
  • You asked me to pull without telling me which branch you want to merge with
  • git rebase causes feature branch to lose tracking information
  • Display Git log including Notes in online
  • Git doesn't save created branches
  • How to share React components between two Meteor apps in the same repository?
  • Should individual git repositories be created for sub directories on a web site, or is it possible to branch them individually?
  • Git: rebase merge commit
  • 4 Solutions collect form web for “Replace a commit in git”

    If the offending commit is in a private repository, what you want to do is not a big deal. Rewriting published git history is irritating for your collaborators, so be sure removing this line is worth the cost.

    The git-rebase documentation has a helpful passage.

    git rebase [...] [<--onto newbase>] [<upstream>] [<branch>]

    A range of commits could also be removed with rebase. If we have the following situation:

    E---F---G---H---I---J  topicA

    then the command

    git rebase --onto topicA~5 topicA~3 topicA

    would result in the removal of commits F and G:

    E---H'---I'---J'  topicA

    This is useful if F and G were flawed in some way, or should not be part of topicA. Note that the argument to --onto and the upstream parameter can be any valid commit-ish.

    Assuming your history is linear and the offending commit is in your master branch, you can adapt the example above by running

    git rebase --onto 1f020~ 1f020 master

    For hairier situations, use interactive rebase. You may find it helpful to follow along with an example that merges two commits, but instead of marking the commit with s for squash, remove the entire line to remove the commit from your history.

    This is slightly complex but anyway, here is how it goes:

    detach head and move to commit just AFTER that bad commit. use git log to find out the next commit after 1f020.

    git checkout <SHA1-for-commit-just-after-bad-commit-1f020>

    move HEAD to commit just BEFORE that bad commit, but leave the index and working tree as it is

    git reset --soft <SHA1-for-just-previous-to-bad-commit-1f020>

    Redo the commit just AFTER that bad commit re-using the commit message, but now on top of commit just BEFORE that bad commit. thus, removing that bad commit

    git commit -C <SHA1-for-commit-just-after-bad-commit-1f020>

    Re-apply everything from the commit just AFTER that bad commit onwards onto this new place

    git rebase --onto HEAD <SHA1-for-commit-just-after-bad-commit-1f020> master

    You should never remove commits from the history of git. You will run into problems later.

    But if you know what you are doing, you can rewind your history locally, replace that commit with the current one, then replay all the commits on top again – then do a force push on your repository.

    But I HIGHLY advise against any of this. Just do a new commit and live that there is a bad commit in history.

    So, what you want is to:

    1. Remove the bad commit from history, and

    2. Not have to redo all the merges that came after the deleted commit. I.e. each commit that descends from the deleted commit should be kept as-is, only minimally changed to not include the changes erased from history.

    Solutions based on git rebase --onto and git rebase -i fail on the 2nd point, because they require redoing all the merges that happened later. However, it is theoretically possible to simply recreate all these other commits as if the offending commit had never happened, provided that the bad commit is small enough that reverting it from its successors itself create conflicts.

    As Michael and others pointed out, it is highly inadvisable to do this. It’s also a major undertaking that is almost certainly not worth the effort. But, for education value, here is an outline of a comprehensive solution that accomplishes the goal:

    • back up the repository.

    • use git rev-list to generate a list of commits that starts with the bad commit and leads up to all the branch heads from which the commit is reachable.

    • initialize an empty map to map old commits to new ones.

    • for each commit in the list, do the following:

      • check out the commit and revert the changes from the bad commit
      • create a tree object out of the current tree using git write-tree
      • use git commit-tree to create a new commit with the new tree, old commit message, and parents translated from old parents using the above map (if some parents are not in the map, just use the old parents)
      • register the new commit in the commit map.
    • go through tags and tag objects, and recreate them to point to the new commits, consulting the map.

    • go through branch heads and call git update-ref to point them to the new commits, consulting the map.

    If the one-line change (and the unnecessary files) introduced by the commit doesn’t conflict with the changes from later commits, this process could be completely automated, and does not require you to manually redo all the merges and conflicts from the later commits.

    The downside is that it still requires a rewrite of all the later commits, invalidating them if they had been shared elsewhere, and invalidating commit references in commit messages, such as those produced by git revert.

    Git Baby is a git and github fan, let's start git clone.