0

folks, I have following commits push to remote master.

commit fba0f87
commit 1025716
commit 0f2d03c
commit 6449799
commit 4854bf7

So now my head is broken, and I want to revert back. I like to remove commits 1025716 and 6449799, but keep the remaining ones. How can I do this? How do I create a new commit that only has changes from fba0f87, 0f2d03c and 4854bf7 and push that commit so that my master is back to normal.

Romeo
  • 137
  • 3
  • 8
  • Commits are permanent and unchangeable: you cannot remove one from the middle. You can simply *stop using* ones towards the end, but if you need to undo something in the middle, your best bet is usually to apply a new commit that reverses (Git calls this "reverting") a previous commit. The Git command that applies a previous commit in reverse is spelled `git revert`. – torek Sep 26 '17 at 16:37
  • The only viable solution is to use `git revert`. – Arkadiusz Drabczyk Sep 26 '17 at 16:41
  • You can use [git rebase](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) to rewrite your history, although this is considered poor form if you are sharing your repository with other people. – larsks Sep 26 '17 at 16:55
  • @torek commits are definitely _not_ permanent - though once you've pushed to a remote that others have access to, you should avoid rewriting the commit history, at least on the `master` branch. Whether you do on other branches depends on your team workflow agreements. – LightCC Sep 26 '17 at 19:55
  • @LightCC: Well, they're permanent until they have no name at all and get garbage collected. That's close enough :-) ... not really, but in a comment, with limited room, it's what I generally go with. – torek Sep 26 '17 at 20:10
  • Possible duplicate of [Delete commits from a branch in Git](https://stackoverflow.com/questions/1338728/delete-commits-from-a-branch-in-git) – phd Sep 27 '17 at 08:38

3 Answers3

1

Since you have already pushed those commits to the remote repository, you shouldn't use any commands that rewrite history (such as git rebase) since this will cause problems for anyone else pulling your changes from this repository.

Your remaining option is to use git revert to get rid of the commits you don't want:

git revert 6449799
git revert 1025716

Each instance of git revert will create a new commit that removes the changes made by the specified commit.

Once you have run these commands (including fixing any merge conflicts as necessary), you can push these two new commits to effectively remove the original commits you don't want anymore.

Andy
  • 28,217
  • 5
  • 75
  • 86
1

Avoid this in the future

First, consider the following to avoid running into this situation again:

  1. Make ongoing changes in a separate branch until you have some tested and working changes ready to merge into master. Then you can merge or rebase a clean history into master.
  2. Don't push to remote that often while doing small changes that are in progress. Just commit locally, then you can do a merge to remote with a single commit after you have everything tested and working.

This allows you to rewrite local history when you run into issues like this, if you want to, and then when you push the history will be clean.


The best answer is...

git revert will work to add a new commit that will undo the changes in the commits that you need to undo, per Andy's answer.

And that's really the best answer most of the time - there's really no need to have a completely clean history - when you create a defect, just fix it and commit the fix.

But if you really want to know how to clean the history up, read on...


Clean up the History of master

If you are the only one using this remote, there is no problem with just rewriting history. There are lots of different ways to do this - rebase, cherry-pick, etc. For example, you can:

  1. checkout 4854bf7
  2. create a new branch (maybe call it fix?)
  3. cherry-pick 0f2d03c
    • fix any merge conflicts if making a new commit here
    • if you want to keep the commit, you can commit at this point, keeping the original commit message or creating a new one
  4. cherry-pick fba0f87
    • fix any merge conflicts
    • Make final commit (again, just reuse the original commit message, add to it, or make a new one)
a - b - c - d - e  <-- master currently here  
 \                                            
  c' - e'          <-- fix currently here            
  1. At this point, if you want to move master branch over to this new branch and effectively delete the original master:
    • checkout master
    • reset master branch to fix
    • delete fix branch

If you follow #5, you end up with:

a - c' - e'              <-- master
 \
  [b] - [c] - [d] - [e]  <-- will be garbage collected eventually

This might require a force push to push these new changes up to the remote, which, of course, should only be done if no one else has these changes already or if you have coordinated this fix with everyone that could have it.

Note you could also use the above strategy with fix to get everything the way you want it, and then just do a merge into master from fix. This is the same as revert, but if the changes in these commits are large and/or complex, you may want to handle the reintegration in a separate branch which is easier to handle then trying to keep track of in-process reversions.

LightCC
  • 5,446
  • 2
  • 28
  • 67
0

Checkout commit 4854bf7 (the last good commit) and cherry-pick the other commits you want to keep. Then force-push to master to overwrite the commit history.

Warning: Make sure if there are any other commits to master in the mean time that you merge those in before force-pushing, as this will overwrite the history in master. Additionally, any repositories containing the original history will need to force-pull from master before they can push, meaning they may lose local changes.

git checkout 4854bf7
git cherry-pick 0f2d03c
git cherry-pick fba0f87

Now, your current HEAD is at fba0f87 and the log only contains the commits you want to keep. You can check this with git log.

Now, ensuring that you are still tracking your remote master, and having performed the checks mentioned in the warning above:

git push -f
Oletha
  • 6,158
  • 1
  • 18
  • 40