jimifiki
jimifiki

Reputation: 5534

git reset to previous commit and then push

When trying to revert to a previous commit (for instance 123abc) via git reset

git reset --hard 123abc 
git commit -a -m "revert to 123abc"

I cannot push this (I need to pull before and pulling moves me forward). I have come with this few lines:

for i in `git diff --name-only 123abc`; do git checkout 123abc $i; done
git commit -a -m "revert to 123abc"

Which works since now

 git diff --name-only 123abc

is empty

I was wondering if this is an hack or the git way to do it. In case it is not, how to accomplish this correctly?

Upvotes: 4

Views: 30764

Answers (3)

torek
torek

Reputation: 487755

When trying to revert to a previous commit (for instance 123abc) ...

The emphasis I added here on the preposition "to", as in revert to, is crucial. The accepted answer at your linked question (How do I revert a Git repository to a previous commit?) calls this out:

This depends a lot on what you mean by "revert".

Running git revert on a single commit may not suffice. See the answers there about reverting multiple commits, if needed.

Running git reset --hard may suffice, but introduces the very problem you've encountered. The things to understand here are:

  1. A branch name simply lets Git find one particular commit. We say that the branch name points to the commit. Using git reset, we can change the one particular commit to which some branch name points. Nothing else happens in the repository yet, although depending on the kind of git reset you run, something else might happen before git reset finishes: the first step of this git reset is just to change one of your own branch names. Since you're considering (or have used) --hard, some more things will change in your repository, but they're less important at the moment.

  2. Every Git repository has its own branch names. Moving one of your branch names has no effect on any other repository.

  3. What you need to do is to get some other Git repository to change one of its branch names. That's where you run into this problem:

    I cannot push this (I need to pull before and pulling moves me forward).

    The git push command is how you ask—or, using --force, command—some other Git repository to change or create or delete some of its names (branch names, tag names, and other such names). But each Git repository is set up to easily accept new incoming commits, yet at the same time, resist the suggestion to throw away any existing commits.

When you use git reset to move one of your branch names "backwards", so as to revert to (not revert as in add-a-commit-that-backs-out) some previous commit, you're deliberately throwing away some existing commit(s). Since you control your own Git repository, you can definitely do this to your own repository. Since the git reset command is meant to do this kind of throwing-away,1 it does so without complaint. But git push isn't, and their Git complains.

As soon as you use git pull, their repository has you put back all the commits you snipped out of your own repository. Git is, after all, designed to add commits as easily as possible! That leaves you with the situation you're in.

You now have a choice:

  • Force the other Git repository to discard some commits. This requires sufficient permissions. It also means that everyone else who is using that other Git repository need to take action with any clones they have made, because their clones will enthusiastically put back all the commits you are attempting to prune. So this is kind of mean to those other people.

  • Or, use git revert or some other command to add some commit(s) to your repository that, in the end, result in putting the files back, but don't remove any old commits. The new commits simply add on to the old ones. The old ones are still there for anyone who would like to ask about them (git log) or use them (git switch --detach hash-id, for instance).

Adding new commit(s) is what Git is designed to do, so the latter is the way to go unless there's some really strong reason to ditch the old commits.

As the question you linked notes, all of this is a lot easier with unpublished commits: a commit that only you have, in your own private repository, is simply not in any other Git repository. If you shave those commits off your own branches, nobody will ever know. They won't be able to object that a git push shaves those commits off their branches, because those commits aren't on their branches. (Again, each branch name is local to each Git repository. One repository can show another one the commit hash ID stored in its branch name, but each repository takes responsibility in keeping its own hash IDs in its own branch names. The commits get shared; the branch names do not.)

Since the commits you're looking at are published you cannot use this short-cut.


1This makes git reset a very-high-powered tool, like some sort of flame-throwing chainsaw, or industrial steel-cutting laser, or something. This over-powered-ness is part of the reason that Git 2.23 now has git restore: some of the things you can do, that used to require using git reset, can now be done with the rather gentler git restore. Both commands will throw away in-progress work if you ask them, but git restore is more like a hand-saw, or bolt cutters, or something along these lines.

Upvotes: 6

Roman Pavelka
Roman Pavelka

Reputation: 4171

It is a hack. Use

git revert <commit hash>

but beware, you are reverting the changes applied by the <commit hash>, so to revert to previous commit, use

git revert HEAD

This will create another commit that is reverting a change caused by the last commit. Check this answer: https://stackoverflow.com/a/22683231/12118546

This above is a proper way how to do this with putting the reverting itself to the history also. If you are the only one working in the repo, you can also force push the branch with the latest commit removed: https://stackoverflow.com/a/31937298/12118546

Upvotes: 1

Joshua Zeltser
Joshua Zeltser

Reputation: 598

You should try using git revert <commit hash>. This will revert the selected commit and you can then push the changes

Upvotes: 1

Related Questions