Reverting specific commits from git

ⅰ亾dé卋堺 提交于 2019-12-18 10:17:05

问题


I have a git tree with a lot of commits and a lot of files. Now, I want to revert specific commits that touch a file only. To explain:

> git init
Initialized empty Git repository in /home/psankar/specific/.git/
> echo "File a" > a
> git add a ; git commit -m "File a"
[master (root-commit) 5267c21] File a
 1 file changed, 1 insertion(+)
 create mode 100644 a
> echo "File b" > b
> git add b; git commit -m "File b"
[master 7b560ae] File b
 1 file changed, 1 insertion(+)
 create mode 100644 b
> echo "File c" > c
> git add c; git commit -m "File c"
[master fd6c132] File c
 1 file changed, 1 insertion(+)
 create mode 100644 c
> echo "b and c modified" > b ; cp b c
> git commit -a -m "b and c modified"
[master 1d8b062] b and c modified
 2 files changed, 2 insertions(+), 2 deletions(-)
> echo "a modified" > a
> git commit -a -m "a modified"
[master 5b7e0cd] a modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> echo "c modified" > c
> git commit -a -m "c modified"
[master b49eb8e] c modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> git log --pretty=oneline c
> git log --pretty=oneline c | cat
b49eb8e03af331bddf90342af7d076f831282bc9 c modified
1d8b062748f23d5b75a77f120930af6610b8ff98 b and c modified
fd6c13282ae887598d39bcd894c050878c53ccf1 File c

Now I want to revert just the two commits b49eb8 and 1d8b06 without reverting the changes to a. IOW revert only the commits in a file (without reverting other intermediate commits (which may be thousands in number) in different files) How is this possible ?


回答1:


You can use git revert with the --no-commit option. In your example:

$ git revert --no-commit b49eb8e 1d8b062
# Files that were modified in those 2 commits will be changed in your working directory
# If any of those 2 commits had changed the file 'a' then you could discard the revert for it:
$ git checkout a
$ git commit -a -m "Revert commits b49eb8e and 1d8b062"

If you don't provide a commit message then a prepared message will be available when the commit message editor is started.

If you omit the --no-commit option then the changes in the commits you specify will be reverted. This is achieved by applying the reverse of the changes in the specified commits and committing that. This results in a new commit, both the original and the reverted commit will be in the history of your repository.




回答2:


There are two cases here:

  1. When you have already pushed your git tree to somewhere and you don't want to change the history. In this case you will need a new commit expressing the changes you made in reverting the previous commits. You should use @mamapitufo's answer.

  2. If you have never pushed the branch that the changes are on, and you can change the history. In this case you can completely remove the unwanted commits. This will neaten the history and means that you don't push a wrong turning to your co-workers or the public.

In the second case you should do git rebase -i. Find a commit which comes before any of the history you want to change. This might be the hash of the commit, or the name of the branch or tag. For example, you could do

git rebase -i 23def8231

or if you started from the branch origin/dev_branch and did the work which includes the bits to remove on your branch called dev_branch, you could do

git rebase -i origin/dev_branch

Now, you will be sent into an editor window where you can see a list of all the commits which you are rebasing. This might be vim - if you don't usually edit in the terminal it could be set as the default. You will probably need a quick start guide to vim and an open mind if that's the case.

Now, the easiest thing to do is to remove commits. You do this by deleting the line, or adding a # which indicates a comment to the start of the line. (There are already some comments in the file, to explain things to you. Ignoring these or deleting them has no effect.)

When you are finished, save the file and exit the editor. The rebase happens like this: git goes back to the commit you named. It goes through the list you saved and replays each commit in that list. Then it makes the result of that process the new version of the branch you were originally on.

Important things to remember:

  • If you get lost or delete too many lines, you can cancel the rebase by deleting every commit line in the file, and saving. The rebase process will end with nothing changed at all.
  • It's possible to create conflicts. For example if you remove a commit which edits a file, and leave in a later commit which edits the same place. The later commit will now not apply correctly and you will have to edit by hand or in a merge tool to get the version you want.

You can also do lots of other manipulation in git rebase -i. For example changing the order of commits, squashing several together into one, adding extra changes between commits, or changing the messages. It is very useful. The classic use case is cleaning up your local branch before you push it back to somewhere where other people will look at your changes.



来源:https://stackoverflow.com/questions/20324638/reverting-specific-commits-from-git

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!