git 重置为之前的提交然后推送

git reset to previous commit and then push

当尝试通过 git 重置

恢复到之前的提交(例如 123abc)时
git reset --hard 123abc 
git commit -a -m "revert to 123abc"

我不能推这个(我需要先拉,然后拉让我向前)。 我带来了这几行:

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

从现在开始有效

 git diff --name-only 123abc

为空

我想知道这是黑客攻击还是 git 的方法。如果不是, 如何正确完成此操作?

您应该尝试使用 git revert <commit hash>。这将恢复选定的提交,然后您可以推送更改

这是一个黑客。使用

git revert <commit hash>

但请注意,您正在还原 <commit hash> 应用的更改,因此要还原到之前的提交,请使用

git revert HEAD

这将创建另一个提交,该提交将还原由上次提交引起的更改。检查这个答案:

以上是将自身还原为历史记录的正确方法。如果你是唯一一个在回购中工作的人,你也可以强制推送删除最新提交的分支:

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".

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

运行 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 运行, 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 运行 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 p运行e. 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 <em>hash-id</em>, 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.