Search code examples
gitrevert

git: better way for git revert without additional reverted commit


I have a commit in a remote+local branch and I want to throw that commit out of the history and put some of them into an own branch.

Basically, right now I have:

           D---E---F---G master

And I want:

             E---G topic
            /
           D master

That should be both in my local and in the (there is only one, called origin) remote repository.

Which is the cleanest way to get that?

Also, there are also other people who have cloned that repo and who have checked out the master branch. If I would do such a change in the remote repo, would 'git pull' work for them to get also to the same state?


Solution

  • If you've published then you are right that you don't want to re-write the history of master. What you want is to publish a commit to master that brings it back to the state that it was at D while retaining its current history so that other users can merge or rebase their work easily.

    If you are planning at some point in the future to merge topic into master then what you probably also want to do is make a new common base between master and topic, so that when you do subsequently merge topic, you don't lose the commits that were reverted in master. The easiest way to do this is by making a 'redo' commit on top of the 'undo' commit that resets master back to its original state and basing the new topic branch on top of that.

    # checkout master branch (currently at G)
    git checkout master
    
    # Reset the index to how we want master to look like
    git reset D
    
    # Move the branch pointer back to where it should be, leaving the index
    # looking like D
    git reset --soft HEAD@{1}
    
    # Make a commit (D') for the head of the master branch
    git commit -m "Temporarily revert E, F and G"
    
    # Create the new topic branch based on master.
    # We're going to make it on top of master and the 'undo'
    # commit to ensure that subsequent merges of master->topic
    # or topic->master don't merge in the undo.
    git checkout -b topic
    
    # Revert the undo commit, making a redo commit (G').
    git revert HEAD
    

    As an alternative you could have made commits E', F' and G' redoing each part separately but as E, F and G are already in your published history it's probably more understandable if you just reference the 'undo' commit and say that that commit is being undone. This is what git revert does, anyway.

    Essentially what you know have is this.

    D -- E -- F -- G -- D'      <-- master
                         \
                          \
                            G'  <-- topic
    

    The important things are that you have not rewritten history and topic is based on master so merges won't accidentally apply any 'undo' commits. You can now safely push both master and topic to your remote repository.