MEM MEM - 3 months ago 9
Git Question

How can I revert multiple Git commits (already pushed) to a published repository?

New to git, and already messing up.

I've commited and pushed some changes to a remote dev machine.
I need to recover an older version, but keep the "bad progress" doing so far to keep working on a separate branch;

I was thinking doing it like this:


  1. Create a local branch named: "tested-thing"

  2. Revert local repository to the state where it worked (hopefully meaningful commits will help);

  3. Push to remote

  4. finish tests on tested-thing

  5. Merge "tested-thing" into dev

  6. Push to remote



Between steps 3 and 5 other developers may commit and push, and I'm afraid this may result on a "merge tragedy" - Anyway, may this be a proper way to go ?

UPDATE:

The main problem here resides on 2)

Here, on topic: "breaking work into a topic branch"
http://learn.github.com/p/undoing.html

They suggest:


  1. $ git branch test

  2. $ git reset --hard a6b4c974



By doing so, other developers could still:

$ git commit
(on the dev branch)

and I can checkout to test and work it out until merge time.

Despite all your options, this feels like to be a nice approach to follow.
However, it's not stated if this can be done after we have pushed ?

Please note the following: Since I made those changes and I mess up the all thing, no one else have worked on the repository so far. So, if I revert the working directory, no one will notice.

Answer

The Problem

There are a number of work-flows you can use. The main point is not to break history in a published branch unless you've communicated with everyone who might consume the branch and are willing to do surgery on everyone's clones. It's best not to do that if you can avoid it.

Solutions for Published Branches

Your steps have merit. If you need the dev branch to be stable right away, do it that way. You have a number of tools for Debugging with Git that will help you find the right branch point, and then you can revert all the commits between your last stable commit and HEAD.

Either revert commits one at a time, in reverse order, or use the <first_bad_commit>..<last_bad_commit> range. Hashes are the simplest way to specify the commit range, but there are other notations. For example, if you've pushed 5 bad commits, you could revert them with:

# Revert a series using ancestor notation.
git revert --no-edit dev~5..dev

# Revert a series using commit hashes.
git revert --no-edit ffffffff..12345678

This will apply reversed patches to your working directory in sequence, working backwards towards your known-good commit. With the --no-edit flag, the changes to your working directory will be automatically committed after each reversed patch is applied.

See man 1 git-revert for more options, and man 7 gitrevisions for different ways to specify the commits to be reverted.

Alternatively, you can branch off your HEAD, fix things the way they need to be, and re-merge. Your build will be broken in the meantime, but this may make sense in some situations.

The Danger Zone

Of course, if you're absolutely sure that no one has pulled from the repository since your bad pushes, and if the remote is a bare repository, then you can do a non-fast-forward commit.

git reset --hard <last_good_commit>
git push --force

This will leave the reflog intact on your system and the upstream host, but your bad commits will disappear from the directly-accessible history and won't propagate on pulls. Your old changes will hang around until the repositories are pruned, but only Git ninjas will be able to see or recover the commits you made by mistake.

Comments