删除没有 parent 的 Git 提交
Remove a Git commit with no parent
我正在 Git 上教 class。我不知道怎么做,但我的一个学生设法连续获得三个提交 没有以前的历史记录 !该学生甚至设法将该行的三个提交合并到 master
(在该学生研究和发现 --allow-unrelated-histories
之后),但在历史树中可以看到,而不是拆分 master
,那三个提交就像尾巴一样挂在那里。
早些时候发生的一件事是,在尝试将存储库 fooproj
克隆到一个单独的目录 fooproj-copy
时,学生不小心将它 克隆到了 [=16] 的子目录中=],以便 Bitbucket 将其显示为远程存储库中的子项目。不过,我让学生删除了这个子目录 fooproj-copy
,并推送了新的提交,所以我认为一切都很好。我不知道他们是如何在没有 parents.
的情况下获得提交的
所以我说我会删除这三个提交(即使它们已经合并到 master 中)。我做了一个 git reset --hard HEAD~1
并且它走上了那一行提交。我又做了一次 git reset --hard HEAD~1
,它一直在继续。但是还有一个 git reset --hard HEAD~1
,我已经到了队伍的末尾;由于这三个提交中没有更多 parents,我收到此错误:
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.
所以通常情况下,如果我想丢弃一些提交,我只需在提交 之前 对提交进行硬重置。但是在这种情况下在我想丢弃的提交之前没有提交。我怎样才能摆脱它们?
将其画成图形:
D
\
A--B--C--M--N <-- master
/
E
提交 A
、D
和 E
都是根提交(没有父级)。
根提交很容易进行:git checkout --orphan
将您置于未出生的分支上,以便该分支上的下一次提交创建分支本身并创建新的根提交。或者,git fetch
从另一个具有不相关历史记录的存储库获取以根提交终止的提交链(或复杂图)。或者,git commit-tree
可以使用任意父项编写新提交。
您不能真正删除这些提交——或者 任何 提交,真的——直接。您所能做的就是让它们无法访问.
如果至少有一个名称指向至少一个提交,那么提交 X 是可访问的,并且通过其祖先链最终将您引导至 X 。在这种情况下,名称 master
直接指向提交 N
,一个合并。 N
指向 E
和 M
,所以两者都是可达的。 M
指向 C
和 D
,所以两者都是可达的。
在这种情况下,如果你将master
指向C
,所有D
,M
,E
和 N
变得无法访问。因此,它们最终将过期并被垃圾收集。但是如果在 N
之后有一个提交——我们称之为 F
——你想保留,你无能为力。您可以 复制 提交:
D
\
A--B--C--M--N--F [abandoned]
\ /
\ E
\
F' <-- master
并开始使用 F'
,即 F
的副本,作为 master
的提示——但这意味着您没有保留 F
。您只保留不同的提交 F'
.
首先,根据您的说法,您可能不应该在 Git 上教授 class。本身就已经非常难了,要是给不太了解的人教我不知道学生们会怎么处理(我不是要人身攻击你,你可能是好意的,已经结束了教 class 是有充分理由的,但我真的认为由熟悉它的人来教它很重要)。
现在,按字面意思回答问题,删除没有 parent 的 Git 提交只需确保不再有任何对它的引用
完成 git 将在一段时间后自动删除其文件;如果您想立即完成(可能是因为该提交或一系列提交占用了大量 space),您可以使用 git gc --prune=all
.
所以在你的情况下,如果看起来这些提交不是其他分支的一部分并且没有任何标签,你只需要将你的分支重置为历史上提交不存在的某个点参考。
但是如果您想要解决存储库的特定问题:
从你所说的看来,学生所做的合并提交似乎将学生的最后一次提交作为其第一次提交 parent,因此至少最初他将 master 合并到他的分支中.
~
命令跟在 first parent 之后,因此当您执行第一个 git reset --hard HEAD~1
时,您将 master 重置为学生的提交行(并使用以下 2 个命令你达到了他的第一次提交)。
所以现在在那个存储库中你可能已经丢失了 你在 master 上的所有其他提交。
如果您有另一个克隆,最好返回它,否则您的原始提交行可能仍会被您的 reflog 引用,因此仍然存在。
在接下来的内容中,我假设您在学生合并后没有对 master 进行其他提交,从您所说的看来是这样。
您似乎没有使用任何图形存储库浏览器,如果是这样,请键入 gitk --all
并使用它来查看您的 branches/references 的确切状态,然后继续执行您将要执行的操作正在做(你必须在每次修改后用 F5 手动刷新它)。如果没有图形浏览器,基本上不可能很好地处理 git,但是您尝试将许多选项传递给 git 日志。
键入 git reflog
并查看它是否列出了您的提交。您需要找到您学生的合并提交或紧接其之前的提交。
为确保不丢失任何其他内容,请先将标签添加到您当前所在的位置 (git tag temp1
)。
然后,如果您找到了您学生的合并提交,请先标记它 (git tag temp-studentmerge <sha1-of-the-commit>
);代替 放置该提交的(缩写的)sha1,当然(它在 git reflog 的左侧第一列中列出)。
然后git reset --hard temp-studentmerge
。更新gitk;你现在应该再次看到你所有的提交。
现在您必须重置为合并的正确 parent;最简单和最安全的选择是在图形浏览器中查看它的 sha1,然后执行 git reset --hard <sha1>
。否则 git reset --hard HEAD^2
应该可以,根据您的描述。
^<n> 符号引用第 个 parent,而 ~ 仅引用第一个 parent。
现在检查一切是否正确,然后删除临时标签(git tag -d temp1
和 git tag -d temp-studentmerge
)。
如果您使用 gitk,您仍然会看到学生的提交,如果您使用简单的 F5,请改用 Shift-F5 (Reload) 并且您赢了再也见不到他们了。
提交 objects 实际上应该仍然在你的存储库中的某个地方,因为 git 删除不再引用的 objects 只有当它们超过某个时间时(我'我其实不太确定细节)。
如果出于某种原因您想立即删除它们的任何痕迹,您可以执行 git gc --prune=all
.
我正在 Git 上教 class。我不知道怎么做,但我的一个学生设法连续获得三个提交 没有以前的历史记录 !该学生甚至设法将该行的三个提交合并到 master
(在该学生研究和发现 --allow-unrelated-histories
之后),但在历史树中可以看到,而不是拆分 master
,那三个提交就像尾巴一样挂在那里。
早些时候发生的一件事是,在尝试将存储库 fooproj
克隆到一个单独的目录 fooproj-copy
时,学生不小心将它 克隆到了 [=16] 的子目录中=],以便 Bitbucket 将其显示为远程存储库中的子项目。不过,我让学生删除了这个子目录 fooproj-copy
,并推送了新的提交,所以我认为一切都很好。我不知道他们是如何在没有 parents.
所以我说我会删除这三个提交(即使它们已经合并到 master 中)。我做了一个 git reset --hard HEAD~1
并且它走上了那一行提交。我又做了一次 git reset --hard HEAD~1
,它一直在继续。但是还有一个 git reset --hard HEAD~1
,我已经到了队伍的末尾;由于这三个提交中没有更多 parents,我收到此错误:
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.
所以通常情况下,如果我想丢弃一些提交,我只需在提交 之前 对提交进行硬重置。但是在这种情况下在我想丢弃的提交之前没有提交。我怎样才能摆脱它们?
将其画成图形:
D
\
A--B--C--M--N <-- master
/
E
提交 A
、D
和 E
都是根提交(没有父级)。
根提交很容易进行:git checkout --orphan
将您置于未出生的分支上,以便该分支上的下一次提交创建分支本身并创建新的根提交。或者,git fetch
从另一个具有不相关历史记录的存储库获取以根提交终止的提交链(或复杂图)。或者,git commit-tree
可以使用任意父项编写新提交。
您不能真正删除这些提交——或者 任何 提交,真的——直接。您所能做的就是让它们无法访问.
如果至少有一个名称指向至少一个提交,那么提交 X 是可访问的,并且通过其祖先链最终将您引导至 X 。在这种情况下,名称 master
直接指向提交 N
,一个合并。 N
指向 E
和 M
,所以两者都是可达的。 M
指向 C
和 D
,所以两者都是可达的。
在这种情况下,如果你将master
指向C
,所有D
,M
,E
和 N
变得无法访问。因此,它们最终将过期并被垃圾收集。但是如果在 N
之后有一个提交——我们称之为 F
——你想保留,你无能为力。您可以 复制 提交:
D
\
A--B--C--M--N--F [abandoned]
\ /
\ E
\
F' <-- master
并开始使用 F'
,即 F
的副本,作为 master
的提示——但这意味着您没有保留 F
。您只保留不同的提交 F'
.
首先,根据您的说法,您可能不应该在 Git 上教授 class。本身就已经非常难了,要是给不太了解的人教我不知道学生们会怎么处理(我不是要人身攻击你,你可能是好意的,已经结束了教 class 是有充分理由的,但我真的认为由熟悉它的人来教它很重要)。
现在,按字面意思回答问题,删除没有 parent 的 Git 提交只需确保不再有任何对它的引用
完成 git 将在一段时间后自动删除其文件;如果您想立即完成(可能是因为该提交或一系列提交占用了大量 space),您可以使用 git gc --prune=all
.
所以在你的情况下,如果看起来这些提交不是其他分支的一部分并且没有任何标签,你只需要将你的分支重置为历史上提交不存在的某个点参考。
但是如果您想要解决存储库的特定问题:
从你所说的看来,学生所做的合并提交似乎将学生的最后一次提交作为其第一次提交 parent,因此至少最初他将 master 合并到他的分支中.
~
命令跟在 first parent 之后,因此当您执行第一个 git reset --hard HEAD~1
时,您将 master 重置为学生的提交行(并使用以下 2 个命令你达到了他的第一次提交)。
所以现在在那个存储库中你可能已经丢失了 你在 master 上的所有其他提交。
如果您有另一个克隆,最好返回它,否则您的原始提交行可能仍会被您的 reflog 引用,因此仍然存在。
在接下来的内容中,我假设您在学生合并后没有对 master 进行其他提交,从您所说的看来是这样。
您似乎没有使用任何图形存储库浏览器,如果是这样,请键入 gitk --all
并使用它来查看您的 branches/references 的确切状态,然后继续执行您将要执行的操作正在做(你必须在每次修改后用 F5 手动刷新它)。如果没有图形浏览器,基本上不可能很好地处理 git,但是您尝试将许多选项传递给 git 日志。
键入 git reflog
并查看它是否列出了您的提交。您需要找到您学生的合并提交或紧接其之前的提交。
为确保不丢失任何其他内容,请先将标签添加到您当前所在的位置 (git tag temp1
)。
然后,如果您找到了您学生的合并提交,请先标记它 (git tag temp-studentmerge <sha1-of-the-commit>
);代替
然后git reset --hard temp-studentmerge
。更新gitk;你现在应该再次看到你所有的提交。
现在您必须重置为合并的正确 parent;最简单和最安全的选择是在图形浏览器中查看它的 sha1,然后执行 git reset --hard <sha1>
。否则 git reset --hard HEAD^2
应该可以,根据您的描述。
^<n> 符号引用第
现在检查一切是否正确,然后删除临时标签(git tag -d temp1
和 git tag -d temp-studentmerge
)。
如果您使用 gitk,您仍然会看到学生的提交,如果您使用简单的 F5,请改用 Shift-F5 (Reload) 并且您赢了再也见不到他们了。
提交 objects 实际上应该仍然在你的存储库中的某个地方,因为 git 删除不再引用的 objects 只有当它们超过某个时间时(我'我其实不太确定细节)。
如果出于某种原因您想立即删除它们的任何痕迹,您可以执行 git gc --prune=all
.