Try to avoid needing to do this
Broadly speaking, changing git history, once you’ve pushed to a remote repo is considered bad practice. In certain cases, there’s reason to do this locally before you push, but once you share your work — don’t touch it!
Your coworkers will probably be upset at you; your parents, disappointed; and Santa will put you on the naughty list.
Nearly all of the operations listed on this page result in new commit SHA IDs, which mean your history actually changes, not just the content!
GPG signature invalidation
If you GPG-sign your commits, editing history in certain ways will invalidate signatures. I’m not certain exactly which operations will do this, but be aware that it can happen.
With that warning out of the way, there are still times when you will need to change the commit history, and you will need to do it on a remote repository. You will know when this time comes.
For the basics, also see Undoing things.
Changing the last commit
If all you need to do is change the message on the last commit you made (or author, or change content), you can do this easily by amending the commit:
git commit --amend- Reloads the last commit message in an editor for editing
- If you stage more changes before running this, those changes will be added to the commit’s
Updating a branch with rebase
If you branch off somewhere (branch A) and then want to include changes made on the original branch into your branch (branch B), you have two options:
- Simply merge branch A into branch B, as with any other merge operation (
git checkout branchB && git merge branchA). However, since you’re reading the page on “editing history,” I’ll assume you’re not allowed to do that, and therefore need… - Rebase your branch onto the top of the original branch
Don't do this if branchB contains merge commits
If your branch has merge commits (either from doing option 1 earlier, or something else), this can cause undue complications especially when working with cloud Git services like GitHub, GitLab, Bitbucket, and others.
For that, see Changing multiple messages and squashing commits and do an interactive rebase.
To rebase a branch onto another one is fairly straightforward:
git checkout <branchA>Switch to branch Agit pull origin <branchA>Ensure you have the latest changes from upstreamgit checkout <branchB>Switch back to branch Bgit rebase <branchA>Rebase onto the top of branchA
Before:
--- title: Before rebasing config: gitGraph: mainBranchName: branchA --- gitGraph commit id: "1" commit id: "2" branch branchB commit id: "3" commit id: "4" checkout branchA commit id: "5" commit id: "6"
After. The rebase operation effectively lifts up your branch and sets it back down on top of the newest commit on the branch you’re rebasing onto:
--- title: After rebasing config: gitGraph: mainBranchName: branchA --- gitGraph commit id: "1" commit id: "2" commit id: "5" commit id: "6" branch branchB commit id: "3" commit id: "4"
Changing multiple messages and squashing commits
If what you want to do is to change multiple commit messages at once, and/or combine a few commits (also known as “squashing”), you can use an interactive rebase:
git rebase -i HEAD~<n>- interactively edit the past<n>commits- Example:
git rebase -i HEAD~10to edit the last 10 commits you’ve made
- Example:
This will open an editor with a list of commits (NOTE: This list of commits is backwards from what you’re used to seeing with i.e., git log. Older commits are at the TOP of the file; newer commits at the BOTTOM):
pick abcdef1 Initial commit
pick 123456a Second commit
pick 654321a Fix a typo in the README
# (followed by lots of comments with instructions that I am
# not going to retype here)
You can simply change the message for the commits in-place, save, and quit the editor to change messages.
If you want to squash commits, change the pick command to squash on the commits which you wish to squash into their parents. For example, to squash 654321a into its parent, change the pick on line 3 to squash. You can do this for multiple commits in a row and it “stacks”; all consecutive squash commands will be squashed down into the parent just before the first one.
Deleting commits
If you really need to delete a commit, you can do so using the rebase -i approach described earlier. Instead of squash or pick, use the drop command — and it will vanish.
Note that because of Git’s delta compression technique, this will substantially alter ALL commits which come after it. The further back in history you delete a commit, the more commits will be recreated.
Merge conflicts lie ahead. Be warned.
Complete history filtering
If you need even more than the builtin git filtering provides, you may find reposurgeon and the associated suite of tools useful. Reposurgeon effectively provides an interactive directed acyclic graph editor which operates on VCS histories.
See also
- Reposurgeon homepage: http://www.catb.org/esr/reposurgeon/
You need to understand this in order to use it
I’m not going to help you use reposurgeon. If you want to perform an operation which requires this level of editing, you must learn and understand what’s happening — or you will pull the trigger on the metaphorical gun currently aimed at your own kneecap.
All you’ll get from me is a few possible use cases. if you end up here, the reposurgeon documentation is your next step.
- Completely removing all traces of a file from not only the current commit but all past commits as well
- Converting between different VCS systems (not only git and svn, but also hg, darcs, rcs, and others)