Git仓库唯一标识符

7

我需要找出一个提交是否属于特定的git仓库。

我的想法是为每个我需要测试的仓库生成一个唯一的ID。 然后,我可以将此唯一ID与从已测试的提交计算出的ID进行比较。

例如,可以使用初始更改集的SHA。它能唯一地识别存储库吗?


当你说“属于”时,是指“起源于”还是“被发现在”? - Kirk Kelsey
好的...我无法检查提交是否真的可以在存储库中找到(需要太多时间)。但是我想知道测试提交的某个祖先是否存在于存储库中。我认为这意味着“起源” :) - Ilya Ivanov
你是对的...不过让我们从另一个角度来看:我的仓库和你的仓库都是从同一个源克隆而来的。我们能否在不尝试推送/拉取的情况下找出这个事实呢? - Ilya Ivanov
两个代码库有相同的初始提交肯定有某种含义。你在这里的真正目标是什么? - Cascabel
嗯...我无法检查提交是否真的可以在存储库中找到...当然你可以。if git cat-file -e $thecommit; then the commit exists in the repo; fi - jthill
6个回答

5
SHA1密钥是用于识别blob或tree的内容,而不是用于仓库的。
如果内容在不同的仓库之间有所不同,则它的历史记录没有共同的祖先,因此我认为基于变更集的解决方案将无法实现。也许(未经测试)您可以通过git notes添加一些标记(而无需更改所有SHA1)。
例如,请参见GitHub deploy-notes,该机制使用此机制来跟踪部署。

谢谢你的回答。我只是假设SHA也包括了'git init'执行或其他操作的时间戳... - Ilya Ivanov
2
@Ilya:这不仅仅是如此:提交的SHA1取决于其所有内容:元数据(日期、作者、消息)、树和其父级。如果提交或其任何祖先中有任何差异,SHA1将发生变化。 - Cascabel
谢谢!这可能节省了几个小时阅读手册 :) - Ilya Ivanov

1

(从评论中移动)

如果您的存储库中没有特定提交的父级(在这种情况下,您可以轻松回答问题),则不可能实现。虽然提交保留对父级的引用并以此方式维护整个树的完整性,但如果您没有该提交,则无法仅从哈希重建提交,因此您无法找到该父级的父级,直到找到实际位于您的存储库中的父级。


0
与Mercurial相比,它在哪里检查mercurial/treediscovery.pyMercurial存储库标识):
base = list(base)
if base == [nullid]:
    if force:
        repo.ui.warn(_("warning: repository is unrelated\n"))
    else:
        raise util.Abort(_("repository is unrelated"))

base变量存储两个仓库的最后公共部分。

Git在fetch/push时发出“warning: no common commits”的警告时有相同的假设。我只是没有搜索需要时间的Git源代码。

通过提供Mercurial push/pull检查的这个想法,我们可以假定如果两个仓库具有共同的根,则它们是相关的。对于Mercurial来说,这意味着从以下命令的哈希值:

$ hg log -r "roots(all())"

对于两个仓库,都必须有非空的插入语。

您不能通过精心制作仓库来欺骗根检查,因为构建两个仓库看起来像这样(具有共同部分但不同的根):

0 <--- SHA-256-XXX <--- SHA-256-YYY <--- SHA-256-ZZZ
0 <--- SHA-256-YYY <--- SHA-256-ZZZ

这是不可能的,因为这意味着你要反向计算SHA-256,而每个后续哈希都依赖于先前的值。这对Mercurial和Git都是正确的。

在Git中查看根目录的相应命令是:

$ git log --format=oneline --all --max-parents=0

你可以自己玩弄:

bash# md git
/home/user/tmp/git

bash# md one
/home/user/tmp/git/one

bash# git init
Initialized empty Git repository in /home/user/tmp/git/one/.git/

bash# echo x1 > x1
bash# git add x1
bash# git ci -m x1
[master (root-commit) 1208fb0] x1

bash# echo x2 > x2
bash# git add x2
bash# git ci -m x2
[master 1c3fe86] x2

bash# cd ..

bash# md two
/home/user/tmp/git/two

bash# git init
Initialized empty Git repository in /home/user/tmp/git/two/.git/

bash# echo y1 > y1
bash# git add y1
bash# git ci -m y1
[master (root-commit) ff56a8e] y1

bash# echo y2 > y2
bash# git add y2
bash# git ci -m y2
[master 18adff5] y2

bash# git fetch ../one/
warning: no common commits
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From ../one
 * branch            HEAD       -> FETCH_HEAD

bash# git co --orphan one
Switched to a new branch 'one'

bash# git merge FETCH_HEAD

bash# git log --format=oneline --all
18adff541c7ce9f1a1f2be2804d6d0e5792ff086 y2
ff56a8e7e9145d2b1b5a760bbc9b12451927ab0c y1
1c3fe8665851e89d37f49633cd2478900217b91c x2
1208fb0f721005207c6afe6a549a9ed0dcc5b0a8 x1

bash# git log --format=oneline --all --max-parents=0
ff56a8e7e9145d2b1b5a760bbc9b12451927ab0c y1
1208fb0f721005207c6afe6a549a9ed0dcc5b0a8 x1

bash# git log --all --graph

* commit 18adff541c7ce9f1a1f2be2804d6d0e5792ff086
|     y2
|  
* commit ff56a8e7e9145d2b1b5a760bbc9b12451927ab0c
      y1

* commit 1c3fe8665851e89d37f49633cd2478900217b91c
|     x2
|  
* commit 1208fb0f721005207c6afe6a549a9ed0dcc5b0a8
      x1

注意 Git 允许部分检出。我没有针对 --max-parents=0 进行过此类检查。


0
你可以使用 git filter-branch 来寻找你要查找的提交记录。
初始提交的哈希值并不能提供有关代码库本身的太多信息。没有一种方法可以唯一地标识一个代码库。

0
当我对一个存储库有写入权限时,我发现生成一个随机的 UUID 并将其存储在 .gituuid 文件中很有用,该文件也会被提交:
uuidgen > .gituuid
git add .gituuid
git commit -m "Add: git uuid" .gituuid

这个全局解决方案可以唯一地标识一个仓库,但是只有在您拥有写入权限时才相关。

注意:我还有其他脚本来跟踪这些 Git UUID,并允许我定位关联的仓库在我的文件系统中的位置。但这超出了本文的范围。


这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - aaossa

0
在 Rietveld 中,我们无法强制每个人在想要查找针对其存储库进行的审查时使用“git notes”,因此我们将使用git rev-list --parents HEAD输出的最后一个哈希值。

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