我有一个git问题,我需要在我的预接收中运行"git --no-pager diff --name-only {oldrev} {newrev}"
命令,但当 oldrev 是" 000000000000000000000000000000000000000000"我有一个 坏对象 错误,如何比较两次提交之间的差异,如果前一次提交是" 000000000000000000000000000000000000000000"?
答案 0 :(得分:3)
git
将提交报告为000[…]000
,因为它不存在。这是刚刚创建的分支/存储库的状态,没有任何现有历史记录。因此,git diff 000[…]000..master
会给您一个错误,因为" commit"你要比较的东西不存在。
在某些情况下,与空树进行比较可能会有所帮助:
git diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904..master
将为您提供一个完全包含master
当前状态的差异。在这里,神秘数字4b825dc642cb6eb9a060e54bf8d69288fbee4904
只是空树的SHA-1,根据定义,这是一个真正的全局常量(感谢@hvd用于挖掘该哈希值)。 git
知道开箱即用的空树,因此您无需向git
提交任何内容,以便正确解析该哈希值。
答案 1 :(得分:2)
cmaster's answer向您展示如何对the empty tree进行区分,这可能是您想要在此处执行的操作。但是,值得备份一下,考虑一下你的预接收挂钩中的全零哈希是什么意思。同样的#34;空哈希ID"将显示在更新,发布后和更新后的挂钩中。 你应该做些什么取决于你。 在钩子中处理null-hash-ID没有一个正确的答案。
Git引用分支名称,标记名称或可以通过git fetch
或git push
发送的任何其他名称 - 始终标识一(1)个对象(通常是提交 object,除了经常指向带注释的标记对象然后指向提交对象的标记。如果引用是分支名称,您可能希望将其视为"在分支上的任何其他提交更准确地称为可从分支名称访问。 (关于这一点,请参阅Think Like (a) Git。)另一种思考方式是提交包含在分支中:通常,一个特定的提交包含在许多分支中。
当你的Git是git push
的目标时,其他 Git - 还有另一个Git是git push
的来源 - 所做的就是调用你的Git,通常通过SSH或HTTPS连接,并与它进行一些对话。它们为你的Git提供了一些对象(提交,注释标签,树和/或blob),你的Git将它们保存在临时位置。 1 然后他们向你的Git发送一些请求(非表单的强制推送更新或命令(强制推送更新):请设置您的refs/heads/master
,使其指向提交1234567...
和请设置您的{ {1}}以便它指向带注释的标记refs/tags/v1.2
。
你的Git接受这些请求或命令并调用你的预接收挂钩。您的Git,因为 您的存储库,知道您的存储库中是否存在有问题的名称 - fedcba9...
和refs/heads/master
。如果它们确实存在于您的存储库中,则它们会识别一个特定的Git对象。 其他 Git建议更改它们,以便它们识别一些其他 Git对象。所以你的Git为你提供了三条信息:
(另一个Git也使用refs/tags/v1.2
或--force
,或者没有,但是没有特别好或坏的理由,你的Git不会告诉你。)
但它可能用于标记,可能 - 他们的Git发送的名称当前不会识别您自己的存储库中的任何对象。在这种情况下,您的Git会为您的钩子提供全零哈希ID,前提是您将知道如何处理此问题。
这意味着当您编写任何这些挂钩时,您必须准备接受全零散列并将其视为请求,意味着:创建指向指定对象的新名称。事实上,这意味着什么。
如果新名称是标签名称,那么我们通常认为标签指向一个特定的提交(可能通过一系列带注释的标签对象),并且"创建新标签"是我们通常期望的:标签不是假设到"移动&#34 ;;标记名+
今天不应标识提交v1.2
并明天提交1234567...
。 (Git自动执行此操作,因为Git 1.8.4无论如何都是通过在运行钩子之前拒绝标签更新,除非另一个Git设置了force标志。)
但是,对于分支名称,在commit Y 创建新分支名称是预期的操作,因为将现有分支名称从提交X移动到提交Y 。如果从散列 X 到散列 Y 的动作,只将新提交添加到分支中包含的集合中,那么正常(或快进) )操作。如果它删除了一些提交,它必须是一个强制推动,因为Git会先前拒绝它。
(对于既不是分支名称也不是标记名称的名称,Git没有关于强制与非强制更新的内置规则 - 除非它使用89abcde...
名称空间更新的分支规则;我有没有检查这个答案。)
请注意,还有一种参考更新,即 delete 请求或命令。在这种情况下,另一个Git要求或命令您的Git 删除一些引用。您的钩子将接收引用的名称,其当前对象以及全新的哈希ID作为新ID,以指示其他Git正在请求或命令删除操作。
在预接收或更新挂钩中,您可以允许操作(通过以零状态退出)或禁止它(通过退出非零状态)。预先接收的钩子在其标准输入上获得了整个提案 - 所有创建,删除和更新 - 一下子。作为参数,更新挂钩一次获得一个建议的更改。因此,预接收挂钩允许所有更新(然后可以选择性地拒绝,一次一个,在更新挂钩中)或禁止所有更新(使任何发起refs/notes/
的人再次尝试,或许,更小的更新集。)
1 在现代Git中,传入的对象存储在隔离区"隔离区中。然后,只有在接受请求时才迁移到常规存储库数据库。在较旧的Gits中,传入的对象立即进入存储库数据库;如有必要,Git会使用git push
稍后将其丢弃。