删除特定提交

Jos*_*eek 260 git commit revert cherry-pick

我和一位朋友在一个项目上合作,他编辑了一堆本不应该编辑过的文件.不知怎的,我将他的作品合并到了我的作品中,或者当我拉动它时,或者当我试图选择我想要的特定文件时.我一直在寻找和玩很长一段时间,试图弄清楚如何删除包含对这些文件的编辑的提交,它似乎是revert和rebase之间的折腾,并没有简单的例子,并且docs假设我比我知道的更多.

所以这是问题的简化版本:

鉴于以下情况,如何删除提交2?

$ mkdir git_revert_test && cd git_revert_test

$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/

$ echo "line 1" > myfile

$ git add -A

$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 myfile

$ echo "line 2" >> myfile

$ git commit -am "commit 2"
[master 342f9bb] commit 2
 1 files changed, 1 insertions(+), 0 deletions(-)

$ echo "line 3" >> myfile

$ git commit -am "commit 3"
[master 1bcb872] commit 3
 1 files changed, 1 insertions(+), 0 deletions(-)
Run Code Online (Sandbox Code Playgroud)

预期的结果是

$ cat myfile
line 1
line 3
Run Code Online (Sandbox Code Playgroud)

这是我一直试图恢复的一个例子

$ git revert 342f9bb
Automatic revert failed.  After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
Run Code Online (Sandbox Code Playgroud)

gab*_*ous 257

有四种方法:

注意:避免,git reset --hard因为它也会丢弃自上次提交以来文件中的所有更改.如果--soft不起作用,请尝试--mixed--keep.

  • Rebase(显示最近5次提交的日志并删除你不想要的行,或重新排序,或者将多个提交压缩成一个,或者做任何你想做的事情,这是一个非常通用的工具):

    git rebase -i HEAD~5
    
    Run Code Online (Sandbox Code Playgroud)

如果出现错误:

git rebase --abort
Run Code Online (Sandbox Code Playgroud)

注意:当然,所有这些更改都是在本地完成的,git push之后您应该将更改应用到远程.如果您的repo不想删除提交("不允许快进",当您想删除已经推送的提交时会发生这种情况),您可以使用git push -f强制推送更改.

注意2:如果在分支上工作而你需要强制推送,你应该绝对避免,git push --force因为这可能会覆盖其他分支(如果你已经对它们进行了更改,即使你当前的结账在另一个分支上).强制推送时,首选指定远程分支:git push --force origin your_branch.

  • `git rebase -i HEAD~5` 对我有用。然后我只是删除了我不需要的提交,并且我能够在不到 30 秒的时间内解决问题。谢谢你。 (4认同)
  • git revert --strategy resolve &lt;commit&gt; 对我有用,但我必须添加一个 -m 标志。像这样: git revert --strategy resolve &lt;commit&gt; -m 1 因为我的提交是合并。 (3认同)
  • git revert --strategy resolve &lt;commit&gt; 。这个命令对我有用。谢谢 :) (2认同)

JD-*_*D-V 86

非常简单的方法

git rebase -i HEAD~x

(x =提交数量)

执行notepad文件时,除了提交之外,还会打开'put'在此输入图像描述

这就是你的完成...只需同步git仪表板,更改将被推送到远程.如果您提交的提交已经在遥控器上,则必须强制进行更新.因为--force被认为是 有害的,使用git push --force-with-lease.

  • 对于具有 cpp 心态的人:x(提交次数)是包容性的。例如 HEAD~4 包括最后 4 次提交。 (2认同)
  • @Ustin是〜3而不是-3 (2认同)

Hal*_*sen 63

Git在计算要回复的差异时使用的算法需要这样做

  1. 任何以后的提交都不会修改被还原的行.
  2. 在历史的后期没有任何其他"相邻"的提交.

"相邻"的定义基于上下文差异的默认行数,即3.如果'myfile'构造如下:

$ cat >myfile <<EOF
line 1
junk
junk
junk
junk
line 2
junk
junk
junk
junk
line 3
EOF
$ git add myfile
$ git commit -m "initial check-in"
 1 files changed, 11 insertions(+), 0 deletions(-)
 create mode 100644 myfile

$ perl -p -i -e 's/line 2/this is the second line/;' myfile
$ git commit -am "changed line 2 to second line"
[master d6cbb19] changed line 2
 1 files changed, 1 insertions(+), 1 deletions(-)

$ perl -p -i -e 's/line 3/this is the third line/;' myfile
$ git commit -am "changed line 3 to third line"
[master dd054fe] changed line 3
 1 files changed, 1 insertions(+), 1 deletions(-)

$ git revert d6cbb19
Finished one revert.
[master 2db5c47] Revert "changed line 2"
 1 files changed, 1 insertions(+), 1 deletions(-)
Run Code Online (Sandbox Code Playgroud)

然后一切按预期工作.

第二个答案非常有趣.有一个功能尚未正式发布(虽然它在Git v1.7.2-rc2中可用)称为Revert Strategy.你可以像这样调用git:

git revert --strategy resolve <commit>

它应该做得更好,弄清楚你的意思.我不知道可用策略列表是什么,也不知道任何策略的定义.

  • `perl -p` 对于编写非常短(一行)的程序很有用,这些程序循环并“传递”其输入到输出,类似于 sed。`perl -i` 用于*就地*编辑文件。`perl -e` 是如何提交要*评估*的代码。 (2认同)

And*_*ker 36

你的选择介于

  1. 保持错误并引入修复和
  2. 删除错误并更改历史记录.

您应该选择(1)其他人是否已接收到错误更改,以及(2)如果错误仅限于私人未推送分支.

Git revert是一个自动化的工具(1),它创建一个新的提交撤消一些先前的提交.您将在项目历史记录中看到错误和删除,但从存储库中提取的人员在更新时不会遇到问题.它在您的示例中不是以自动方式工作,因此您需要编辑"myfile"(删除第2行),执行git add myfilegit commit处理冲突.然后,您将在历史记录中进行四次提交,其中commit 4将还原提交2.

如果没有人关心您的历史记录发生变化,您可以重写它并删除提交2(选择2).这样做的简单方法是使用git rebase -i 8230fa3.这将使您进入编辑器,您可以选择不通过删除提交来包含错误提交(并在其他提交消息旁边保留"选择".请阅读执行此操作后果.

  • git rebase -i 8230fa3,删除提交的行对我来说非常适合我的本地更改.谢谢! (3认同)

tk_*_*tk_ 23

请遵循以下的操作步骤,因为我们使用--force,您需要拥有git repo的管理员权限才能执行此操作.

步骤1:在要删除的提交之前查找提交git log

第2步:签出提交git checkout <commit hash>

第3步:使用当前的结帐提交创建一个新分支git checkout -b <new branch>

第4步:现在您需要在删除提交后添加提交git cherry-pick <commit hash>

步骤5:现在对要保留的所有其他提交重复步骤4.

步骤6:将所有提交添加到新分支并提交后.检查一切是否处于正确状态并按预期工作.仔细检查一切已经提交:git status

第7步:切换到破碎的分支git checkout <broken branch>

步骤8:现在在要删除的分支之前对已损坏的分支执行硬重置git reset --hard <commit hash>

第9步:将固定分支合并到此分支中git merge <branch name>

步骤10:将合并的更改推回原点.警告:这将覆盖远程仓库!git push --force origin <branch name>

您可以在不创建新分支的情况下执行此过程,方法是将步骤2和3替换为步骤8,然后不执行步骤7和9.


Den*_*nis 17

您可以删除不需要的提交git rebase.假设您从同事的主题分支包含一些提交到您的主题分支,但后来决定您不希望这些提交.

git checkout -b tmp-branch my-topic-branch  # Use a temporary branch to be safe.
git rebase -i master  # Interactively rebase against master branch.
Run Code Online (Sandbox Code Playgroud)

此时,文本编辑器将打开交互式rebase视图.例如

混帐底垫,待办事项

  1. 通过删除行来删除您不想要的提交
  2. 保存并退出

如果rebase不成功,请删除临时分支并尝试其他策略.否则,请继续以下说明.

git checkout my-topic-branch
git reset --hard tmp-branch  # Overwrite your topic branch with the temp branch.
git branch -d tmp-branch  # Delete the temporary branch.
Run Code Online (Sandbox Code Playgroud)

如果您将主题分支推送到远程,则可能需要强制推送,因为提交历史记录已更改.如果其他人在同一个分支机构工作,请给他们一个抬头.


sda*_*aau 8

从这里的其他答案,我有点混淆如何git rebase -i用于删除提交,所以我希望在这里记下我的测试用例(非常类似于OP).

这是一个bash可以粘贴的脚本,用于在/tmp文件夹中创建测试存储库:

set -x

rm -rf /tmp/myrepo*
cd /tmp

mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com

mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"

echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"

echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"

echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"

echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"
Run Code Online (Sandbox Code Playgroud)

在这一点上,我们有file.txt这些内容:

aaaa
bbbb
cccc
dddd
eeee
Run Code Online (Sandbox Code Playgroud)

此时,HEAD处于第5次提交,HEAD~1将是第4次 - 而HEAD~4将是第1次提交(因此HEAD~5将不存在).假设我们要删除第3次提交 - 我们可以在myrepo_git目录中发出以下命令:

git rebase -i HEAD~4
Run Code Online (Sandbox Code Playgroud)

(请注意,git rebase -i HEAD~5结果为"致命:需要单个修订;无效的上游HEAD~5".)文本编辑器(请参阅@Dennis'答案中的屏幕截图)将打开以下内容:

pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit

# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...
Run Code Online (Sandbox Code Playgroud)

所以,我们得到了所有的提交,因为(但不包括)我们要求HEAD〜4.删除该行pick 448c212 3rd git commit并保存该文件; 你会得到这样的回应git rebase:

error: could not apply b50213c... 4th git commit

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit
Run Code Online (Sandbox Code Playgroud)

此时folder/file.txt在文本编辑器中打开myrepo_git/; 你会看到它已被修改:

aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit
Run Code Online (Sandbox Code Playgroud)

基本上,git看到当HEAD进入第二次提交时,有aaaa+的内容bbbb; 然后它有一个添加cccc+ 的补丁dddd,它不知道如何附加到现有内容.

因此,这里git无法为您做出决定 - 需要做出决定:通过删除第3次提交,您可以保留其引入的更改(此处为行cccc) - 或者您不这样做.如果不这样做,只需删除额外的行 - 包括cccc- folder/file.txt使用文本编辑器,所以它看起来像这样:

aaaa
bbbb
dddd
Run Code Online (Sandbox Code Playgroud)

......然后保存folder/file.txt.现在,您可以在myrepo_git目录中发出以下命令:

$ nano folder/file.txt  # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
Run Code Online (Sandbox Code Playgroud)

啊-所以为了纪念,我们已经解决了这个矛盾,我们必须 git addfolder/file.txt,在做之前git rebase --continue:

$ git add folder/file.txt
$ git rebase --continue
Run Code Online (Sandbox Code Playgroud)

这里再次打开一个文本编辑器,显示该行4th git commit- 这里我们有机会更改提交消息(在这种情况下可以有意义地更改为4th (and removed 3rd) commit或类似).假设您不想 - 只需退出文本编辑器而不保存; 一旦你这样做,你会得到:

$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.
Run Code Online (Sandbox Code Playgroud)

此时,现在您有一个这样的历史记录(您也可以使用说法gitk .或其他工具检查)的内容folder/file.txt(显然,原始提交的时间戳保持不变):

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   dddd
                |  +eeee
Run Code Online (Sandbox Code Playgroud)

如果以前,我们决定保留该行cccc(我们删除的第3个git提交的内容),我们会有:

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +cccc
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   cccc
                |   dddd
                |  +eeee
Run Code Online (Sandbox Code Playgroud)

嗯,这是我希望我已经找到的那种阅读,开始了解如何git rebase删除提交/修订; 所以希望它也可以帮助别人......