Git - 在提交之间删除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20584267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Git - Remove in between commit
提问by Vineet1982
Our team is doing several projects in PHP. We have wrongly committed a folder of One Project to another. Now, we want to remove that particular commit from the Project. If we remove the particular folder/commit from the project then there is no issue for our project.
我们的团队正在用 PHP 做几个项目。我们错误地将一个项目的文件夹提交给另一个。现在,我们要从项目中删除该特定提交。如果我们从项目中删除特定文件夹/提交,那么我们的项目就没有问题。
If we just remove the folder and issue the new commit at the current position then the folder is removed but it will remain in the history of Git. So, we want to remove it completely from refs, history and other things from Git.
如果我们只是删除文件夹并在当前位置发出新的提交,那么该文件夹将被删除,但它将保留在 Git 的历史记录中。因此,我们希望从 Git 的引用、历史记录和其他内容中完全删除它。
We can also create a separate branch but the commit refs of authors would be lost. We want to only remove that particular commit. We have no issue in rewriting history or re-basing it but don't know how to do it.
我们也可以创建一个单独的分支,但作者的提交引用会丢失。我们只想删除那个特定的提交。我们在重写历史或重新建立历史方面没有问题,但不知道如何去做。
In the project we have done 136 commits and want to remove commit no.76th. The required information about SHA is as under
在项目中,我们已经完成了 136 次提交,并希望删除第 76 次提交。关于SHA所需的信息如下
5d39775b //136th commit
a4df5ee9 //135th commit
6971cf35 //134th commit
.....
....
162f833c //76th commit
32603274 //75th commit
.....
....
9770059 //1st commit
采纳答案by Vineet1982
I have tried all the provided methods i.e. rebase and cherry-pick. I here to provide full information about both the methods tried and things done by me, to help to understand things with better view
我已经尝试了所有提供的方法,即 rebase 和cherry-pick。我在这里提供有关我尝试过的方法和我所做的事情的完整信息,以帮助更好地理解事物
Preparations
准备工作
To check which is best I have done these things:
为了检查哪个是最好的,我做了这些事情:
Fork the remote repo so that the original would be intact and things can be understood easily. So, don't do any original repo until you are sure things done are correct or not.
first taken the clean copy of Git Repo. Generally, whenever we stash or do other things that are also stored in Git as local Git database. So, that Git database doesn't have any local or temporary things.
I have calculated total number of bytes taken by folder .git. As the repo is clean the minimum bytes would be correct here. To go further deep, I have noted down both bytes taken and bites taken on disk. As both are different things and they are:
bytes - 7,963,769 and size on disk - 8,028,160
If you are using Windows and have installed any Anti virus then you have to disable the Active/Real time mode. As doing things Git need fast access of i/o files checking. What happens when file is created by Git, the active mode locks the new Created for checking virus and when Git tries to re-access that it fails due to locking by Antivirus. In Case of failure you have start your process again from 1.
分叉远程仓库,以便原始仓库完好无损,并且可以轻松理解。所以,在你确定所做的事情正确与否之前,不要做任何原始的 repo。
首先获取 Git Repo 的干净副本。通常,每当我们存储或做其他事情时,这些事情也会作为本地 Git 数据库存储在 Git 中。所以,那个 Git 数据库没有任何本地或临时的东西。
我已经计算了文件夹 .git 占用的总字节数。由于 repo 是干净的,这里的最小字节是正确的。为了更深入,我记下了磁盘上占用的字节数和字节数。由于两者都是不同的东西,它们是:
字节 - 7,963,769 和磁盘上的大小 - 8,028,160
如果您使用的是 Windows 并安装了任何防病毒软件,那么您必须禁用主动/实时模式。在做事时,Git 需要快速访问 i/o 文件检查。当文件由 Git 创建时会发生什么,主动模式会锁定新的 Created 以检查病毒,当 Git 尝试重新访问时,由于 Antivirus 锁定而失败。如果失败,您可以从 1 重新开始您的流程。
Method I - Rebase
方法一 - 变基
In re-basing method can be done by two ways. One is through --onto and other is with -i.
在重新定位方法中可以通过两种方式完成。一种是通过--onto,另一种是通过-i。
-i Method
-i 方法
I used the following command:
我使用了以下命令:
git rebase -i 162f833c^
and it had opened the vim Editor and I see the list of commits starting from 162f833c not from master. If the end the following lines are provided.
它打开了 vim 编辑器,我看到了从 162f833c 开始的提交列表,而不是从 master 开始的。如果结尾提供了以下几行。
# Rebase 3260327..5d39775 onto 3260327
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
I removed a line so that commit will be lost and saved the file and quit the Editor and when I quit it started re-basing as showing:
我删除了一行以便提交将丢失并保存文件并退出编辑器,当我退出时它开始重新定位,如下所示:
Rebasing ( 1/64) ..(2/64)
Successfully rebased and updated refs/heads/master.
And then tried to check the log to see that commit is lost or not and in the log I couldn't find the commit I want to delete. Means the successfully completed the command. The I tried to check the status as:
然后尝试检查日志以查看提交是否丢失,并且在日志中我找不到要删除的提交。表示成功完成了命令。我试图检查状态为:
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 64 and 65 different commit(s) each, respectively.
Since the commits is deleted but on the remote from which it is derived required to be pushed. So, pushed the commit with the force to override earlier code.
由于提交已被删除,但在其派生的远程上需要推送。因此,用力推动提交以覆盖较早的代码。
git push -f
After that I removed the local repo and re-fetched again the repo and the size it shows:
之后,我删除了本地存储库并再次重新获取了存储库及其显示的大小:
bytes 6,831,765 bytes
size on disk 6,897,664 bytes
--onto Method
--onto 方法
After going through Many blogs and Manual, I found 1 blog herewhich really let me know how to use it. So the command I used is:
在浏览了许多博客和手册后,我在这里找到了 1 个博客,它真正让我知道如何使用它。所以我使用的命令是:
git rebase --onto 3260327 79504a5~1
and the out put is:
输出是:
First, rewinding head to replay your work on top of it...
Applying: 77th Message
Applying: 78th Message
Applying: 79th Message
....
Last commit
And then tried to check the log to see that commit is lost or not and in the log I couldn't find the commit I want to delete. Means the successfully completed the command. The I tried to check the status as:
然后尝试检查日志以查看提交是否丢失,并且在日志中我找不到要删除的提交。表示成功完成了命令。我试图检查状态为:
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 64 and 65 different commit(s) each, respectively.
So, with single command all the things are done and then I done a force push to check the bytes etc as earlier
因此,使用单个命令,所有事情都已完成,然后我像之前一样进行了强制推送以检查字节等
git push -f
After that I removed the local repo and re-fetched again the repo and the size it shows:
之后,我删除了本地存储库并再次重新获取了存储库及其显示的大小:
bytes - 6,831,389
size on disk - 6,893,568
Rebase -i Vs --onto
变基 -i Vs --onto
Thus, after doing rebase method. I really approve the --onto method for deleting the commit in between as it is single command and the bytes are also saved marginally higher then -i method. The real advantage is that we don't have to do additional things in --onto method.
这样,在做了rebase方法之后。我真的同意 --onto 方法来删除两者之间的提交,因为它是单个命令,并且字节也比 -i 方法略高。真正的优点是我们不必在 --onto 方法中做额外的事情。
Method II - Cherry-pick
方法二——摘樱桃
Cherry-pick really nice method but run through many commands and you have to take little cautions running the commands. First, I have to create a separate log file with
Cherry-pick 非常好的方法,但是运行了许多命令,并且您在运行这些命令时必须小心谨慎。首先,我必须创建一个单独的日志文件
git log --all --decorate --oneline --graph > 1
Which showed me the log of the repo as we need to view it again and again. From this repo identify the commit you want to delete and copy the SHA Key the last good commit meaning thereby identify the commit up to which we didn't want to change any thing. So, the next command would be
这向我展示了 repo 的日志,因为我们需要一次又一次地查看它。从这个 repo 中确定您要删除的提交并复制 SHA 密钥最后一个好的提交含义,从而确定我们不想更改任何内容的提交。所以,下一个命令是
git checkout 3260327 -b repair
generated output:
生成的输出:
Switched to a new branch 'repair'
So, up to last Good commit we have created a new branch. So, things up to last Good commit doesn't change. Again I run the following command to view all the good commits:
所以,直到最后一个 Good commit 我们已经创建了一个新分支。所以,直到最后一次 Good commit 的事情都没有改变。我再次运行以下命令来查看所有好的提交:
git log --decorate --oneline --graph > 2
I have removed the world --all as, I want to view the commits of branch repair only. As it showed me Good Commits upto marked correctly. Now, next command is to be used with caution as it is includes the bad commit as starting point and end point the last commit done and it would be as:
我已经删除了世界 --all 因为,我只想查看分支修复的提交。因为它向我展示了 Good Commits upto 标记正确。现在,要谨慎使用下一个命令,因为它包括错误提交作为起点和终点最后一次提交,它将如下所示:
git cherry-pick 162f833..5d39775
Output:
输出:
[repair 9ed3f18] xxxxxx
x files changed, xxx insertions(+), xx deletions(-)
[repair 7f06d73] xxxxx
xx files changed, xxx insertions(+), xx deletions(-)
.....
...
What this command does that it recommits all the commits leaving first commit provided above i.e (162f833) to last commit (5d39775) provided. So, the sha commits value would be changed accordingly as it is recommitting the commits one by one. Now it is the time to view the log as:
该命令的作用是重新提交所有提交,将上面提供的第一个提交(即(162f833))重新提交到提供的最后一个提交(5d39775)。因此,sha commits 值将随着它一一重新提交提交而相应更改。现在是查看日志的时候了:
git log --all --decorate --oneline --graph > 3
output as:
输出为:
* f61a9a5 (HEAD, repair) xxxxxx
* 25be3b9 xxxxx
* 49be029 xxxxx
.......
.......
| * 5d39775 (origin/master, origin/HEAD, master)
| * a4df5ee xxxxx
| * 6971cf3 xxxxxx
| .......
| .......
| * 162f833 xxxx
|/
* 3260327 xxxxx
......
* 9770059 xxxxx
So, viewing graph let us know that it had re-commits all the commits except the bad commit. showing you all the old sha keys with new keys. If everything is all right we have to make repair branch as master and deleting the master branch as:
因此,查看图表让我们知道它重新提交了除错误提交之外的所有提交。向您展示所有带有新密钥的旧 sha 密钥。如果一切正常,我们必须将修复分支设为 master 并删除 master 分支:
git checkout master
and output as:
并输出为:
Switched to branch 'master'
First checkout master branch so that we can over ride the changes on master branch. Then
首先结帐主分支,以便我们可以覆盖主分支上的更改。然后
git reset --hard 3260327
and output as:
并输出为:
HEAD is now at 3260327 xxxxx
It will discard the commits after the good commit and now we have to merge the repair branch with master:
它将在良好提交后丢弃提交,现在我们必须将修复分支与 master 合并:
git merge repair
and output as:
并输出为:
Updating 3260327..40d290d
Fast-forward
Now, if you view the log it will not show you the bad commit and every thing is done. I done a force push to check the bytes etc as earlier
现在,如果您查看日志,它不会向您显示错误提交,并且所有事情都已完成。我做了一个强制推送来检查字节等
git push -f
After that I removed the local repo and re-fetched again the repo and the size it shows:
之后,我删除了本地存储库并再次重新获取了存储库及其显示的大小:
bytes - 6,831,556
size on disk - 6,897,664
Ranking of commands
命令排序
Rebase --onto [First]
变基 --onto [第一]
bytes - 6,831,389
size on disk - 6,893,568
Cherry Pick [second]
樱桃选择[第二个]
bytes - 6,831,556
size on disk - 6,897,664
Rebase -i [third]
变基 -i [第三个]
bytes 6,831,765 bytes
size on disk 6,897,664 bytes
I would like to give preference to git rebase --ontocommand as things are done clean way with single command easily.
我想优先使用git rebase --onto命令,因为使用单个命令可以轻松地以干净的方式完成工作。
回答by Mureinik
In your master branch, you can interactively rebase:
在您的主分支中,您可以交互式地变基:
git rebase -i 162f833c^
This will rebase on top on the commit beforethe offending commit. Now just remove the offending commit from the list, save, and exist the editor (default in *nix platforms is vi).
这将在违规提交之前重新基于提交。现在只需从列表中删除有问题的提交,保存并存在编辑器(*nix 平台中的默认值是 vi)。
This will rebase your branch on top the commit before the problematic one, without it, which seems to be what you're trying to achieve.
这将使您的分支重新建立在有问题的提交之前的提交之上,没有它,这似乎是您想要实现的目标。
回答by gturri
You can use interactive rebase.
您可以使用交互式变基。
Since the commit you want to delete has the sha1 162f833c, then just do git rebase -i 162f833c^
由于您要删除的提交具有 sha1 162f833c,因此只需执行 git rebase -i 162f833c^
A text editor will open with a list of commits. Just delete the line corresponding to the commit you want to delete, save, and close.
一个带有提交列表的文本编辑器将打开。只需删除与您要删除、保存和关闭的提交对应的行。
As a safety net, when I do this kind of stuff, I like to put a tag on my HEAD first, so that if something goes wrong, I can just checkout this tag and retrieve my initial state.
作为一个安全网,当我做这种事情的时候,我喜欢先在我的 HEAD 上放一个标签,这样如果出现问题,我可以检查这个标签并检索我的初始状态。
回答by cforbish
You can automatically remove a commit and rewrite history by (where ${ref_to_delete}
is the commit you want to remove, and assumes master
is the branch that it is on):
您可以通过以下方式自动删除提交和重写历史记录(${ref_to_delete}
您要删除的提交在哪里,并假设master
是它所在的分支):
git rebase --onto ${ref_to_delete}~ ${ref_to_delete} master
If you use a remote repository, you'll have to push
with -f
:
如果您使用远程存储库,则必须push
使用-f
:
git push -f
回答by Messa
You can also use git cherry-pick
for this:
您也可以git cherry-pick
为此使用:
$ g # g is my alias for git log --all --decorate --oneline --graph --color
* 618f8e5 [2013-12-14 15:13] (HEAD, master) me: good 6
* e27d6d7 [2013-12-14 15:13] me: good 5
* 533f6c3 [2013-12-14 15:13] me: good 4
* 877585f [2013-12-14 15:13] me: bad
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ git checkout 00c06f3 -b repair
Switched to a new branch 'repair'
$ git cherry-pick 877585f..618f8e5
[repair b340e21] good 4
1 file changed, 1 insertion(+)
[repair 1d2e0d0] good 5
1 file changed, 1 insertion(+)
[repair 1ed1d19] good 6
1 file changed, 1 insertion(+)
$ g
* 1ed1d19 [2013-12-14 15:13] (HEAD, repair) me: good 6
* 1d2e0d0 [2013-12-14 15:13] me: good 5
* b340e21 [2013-12-14 15:13] me: good 4
| * 618f8e5 [2013-12-14 15:13] (master) me: good 6
| * e27d6d7 [2013-12-14 15:13] me: good 5
| * 533f6c3 [2013-12-14 15:13] me: good 4
| * 877585f [2013-12-14 15:13] me: bad
|/
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ git checkout master
Switched to branch 'master'
$ git reset --hard repair
HEAD is now at 1ed1d19 good 6
$ git branch -d repair
Deleted branch repair (was 1ed1d19).
$ g
* 1ed1d19 [2013-12-14 15:13] (HEAD, master) me: good 6
* 1d2e0d0 [2013-12-14 15:13] me: good 5
* b340e21 [2013-12-14 15:13] me: good 4
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ # Done :)
git rebase
is maybe better, so at least I am showing that there are usually multiple ways in git. After all, rebase is so powerful that "all meaningful operations in git can be expressed in terms of the rebase command" (Linus Torvalds).
git rebase
可能更好,所以至少我展示了 git 中通常有多种方法。毕竟,rebase 是如此强大,以至于“git 中所有有意义的操作都可以用 rebase 命令来表达”(Linus Torvalds)。
回答by Rashmi Ranganathan
git rebase -i 32603274.. This will show a huge list of commits.
git rebase -i 32603274.. 这将显示一个巨大的提交列表。
pick 162f833c .. pick ...
选择 162f833c .. 选择...
change the first commit as d 162f833c ..
将第一次提交更改为 d 162f833c ..
and save it.
并保存它。
This will drop the 76th commit alone
这将单独删除第 76 次提交