We all have faced someday the situation where a unwanted commit have been commited anyway, its an bad situation but git have given us the tools to deal with it.

To deal with a situation like this, the only solution is to rewrite history, rewriting history consist of replacing old commits, this solution can lead to a lot of problems if not done correctly.

First rule is to never overwrite an already shared commit, I mean by shared a pushed commit in a shared branch, a pushed commit in a branch that is maintained only by you is not a big deal to rewrite.

The good

The best to which is when everything happen in the best order and you did not need to change history in Git, or at least when the commits you want to change are not pushed yet.

In case the commit you want to change is the last unpushed commit you just need to stage the changes you want to add to the last commit and amend the commit "git commit --amend", the lately added changes are now part of the last commit that you can push like any other commit.

The Bad

You can do the same with an already pushed commit but git will complain when you came to push the changed commit, git will block the push until you tell him to force push the modified commit which will result in replacing the remote branch with the content of the local branch, this will make you colleague live a nightmare.

Your first choice is to never force push on a shared branch, but if for any reason you have to do it anyway, use --force-with-lease option instead of --force. Force with lease will make sure that there is no new commits on the remote that you did not yet pull, this way you will never unintentionally erase someone else work.

After this very bad manoeuver dont forget to notify your colleagues that you have force pushed on a shared branch so they can act accordinly.

The ugly

So as already stated you can change the last commit with amend option in commit, but what if the commit you want to change is not the last commit, in this case we can use another git tools which is fixup with the commit hash "git commit --fixup ", unlike amend this option will add a new commit to the history with the same message prefixed by "fixup!".

Yeah right fixup is just another commit, so why use fixup, why not just commit the change and push them, the answer is fixup will add a special commit that can give a hint to other developper to know that issues in a given commit are corrected in this commit, and the main purpose of the fixup commit is to complete it with an autosquash rebase which will squash the fixup commit with their respective commit.

Rebase with autosquash is very usefull to get rid of the fixup commit but it is better to always use it before merging a feature branch on the master and before you delete the feature branch, so you are sure nobody else will face problems synchronising his local branch with the squashed branch.

Safe net

While modifiying history in git, things can get worse, so never forget to keep track of commit hash you are trying to modify or erase, i'm kidding never memorise anything in IT field you just use "git reflog" while "git log" can give you commit hash of commits still tracked on your branch, reflog will list all the latests git command executed with the respective commit hash, if you have gone wild while modifying or deleting commit, you can refer to it to get the wanted commit hash, and you can use "git reset" to restore it.