GIT:在几次提交之后追加补丁

8

我使用git来跟踪我们开发团队所做的更改并提交到我们的中央cvs风格存储库。由于它是cvs,它跟踪的是文件而不是提交,这使得有时很难准确地确定哪些文件构成了修复错误的完整补丁。我刚遇到了这个问题,并执行了以下操作:

1)查看CVS日志并将其作为完整的补丁提交到git中。

A--B--C--D

2) 我发现另一个文件的更改实际上是针对票(B)的,因此我用以下命令将当前分支重置为B:

git reset --soft <sha1 ID for commit B>

3) 我复制了这个更改,并将其附加到提交(B)中,使用以下命令:

git commit --amend

4) 令我惊讶的是,现在树上显示的是

A--B

只有在工作树中的提交(C)和(D)。它们的详细信息已从日志中消失,我不认为我能找回它们。我做错了什么?我的唯一选择是在(D)之上再进行一次提交,并且知道它实际上是(B)的一部分吗?


顺便说一句:我找到了如何恢复丢失的提交记录: http://www.gitready.com/advanced/2009/01/17/restoring-lost-commits.html 关键是使用“git reflog”查找所需的SHA ID。 - David Dombrowsky
2个回答

14

发生了什么

你的意思是修订,而不是追加,对吗?为了方便起见,我假装这是在一个名为 master 的分支上。现在你的代码库看起来是这样的:

A---B' (master)
 \
  \-B---C---D

Git提交明确依赖于它们的父级 - 在不同父级上的相同补丁是不同的提交。

如何恢复

您可以通过以下几种方式恢复先前的位置。有一个很好的简写方式可以用来直接检查它或创建一个分支:

git checkout master@{1}
git branch oldmaster master@{1}

假设你要找的是第一个之前的位置,那么可以使用 master@{1}。如果是第二个之前的位置 (master@{2}),或者你知道具体时间,也可以使用 master@{7:35}master@{23.hours.ago}。有关这些形式的概述,请参见 man git-rev-parse 的 "specifying revisions" 部分 (在线文档)。

如果不确定如何到达它,请尝试以下方法:

git reflog show master

这将为您提供master以前位置的列表,您应该能够从描述中确定您想要的位置(或者尝试几个)。您可以直接从列表中复制哈希值,并像上面一样使用git checkoutgit branch

您应该做的事情

警告:如果已经发布,则编辑历史记录是一个坏主意 - 在这种情况下,您应该只提交修复。是的,在存储库中将其拆分为两个提交有点丑陋,但其他用户必须能够信任他们在公共存储库中看到的内容而不发生更改!
话虽如此,要进行这种特定类型的历史记录编辑,您需要交互式变基:
git rebase -i master~4 master

master~4代表主分支最新提交前的四个提交。你可以使用任何形式 - 可能是另一个分支,也可能是提交哈希值 - 以便达到相同的效果。

这将在编辑器中打开一个包含你正在操作的提交列表:

pick <hash-A>  <message-A>
pick <hash-B>  <message-B>
pick <hash-C>  <message-C>
pick <hash-D>  <message-D>

# Rebase <hash-A^>..<hash-D> onto <hash-A^>
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

那里的注释帮助文本已经很明显了。在这种情况下,您需要将提交B的行中的“pick”更改为“edit”,保存并退出。重新设置将开始,并在应用B后暂停,让您进行更改。您需要做必要的事情,添加,使用“git commit --amend”,然后“git rebase --continue”。它将应用C和D,您就完成了。如果中途出现任何问题,请使用“git rebase --abort”返回到起始点。
重新设置可能有点可怕-例如,不要意外删除该列表中的行!如果您还不熟悉此操作,建议多使用“gitk”和备份分支名称。

这是一种令人难以置信的答案!太棒了。 - Dan Fitch
太棒了!我就感觉这与git-rebase有关。有人给那个人买杯啤酒吧。 - David Dombrowsky
很棒的回答。展示了Git的强大之处,做得非常出色。这是SVN死忠需要看到的东西。 - Dan Moulding

1

4) 令我惊讶的是,现在树形结构如下:

A--B

实际上,日志(历史记录)看起来像这样:

A--B'

因为提交与之前的不同,所以情况看起来像下面这样:

A---B'                         <-- 主分支  <--- HEAD
  \
    \--B---C---D

提交链“B---C---D”(原始B)似乎已经丢失,因为没有指向D的引用。您的分支现在指向提交B'(修改后的提交B)。您仍然可以通过reflog访问D;我认为它应该是HEAD@{2}...

我哪里做错了?

您应该使用“git rebase --interactive”,将提交B旁边的“pick”更改为“edit”,并在那里压缩一个补丁。

或者使用像StGITGuilt这样的Git补丁管理界面。

它们的详细信息已从日志中消失,我认为我无法找回它们了。

查看reflog,即"git reflog"或"git log -g"。在那里,您应该可以看到您“丢失”的提交记录。

希望对您有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接