我想运行一个命令来查找“这是这些文件的最新版本吗?”
这里的目标是如此发现:“我在这里的文件是在回购中的前方还是后方?” ... ...如果存在差异,哪些不同(所以我以后可以运行git diff)
同样,如何找到提交顺序? (在颠覆中,它是一个整数,显然41落后于42.在git ......它们都是哈希。
答案 0 :(得分:3)
这个问题没有很好地形成 - 因为至少在某种程度上,正如你所指出的,哈希不利于订购。
事实证明,首先没有订单。或者,更准确地说,有partial order但不一定是任何单个总订单。即使在Mercurial中也是如此,它(如Subversion)具有线性增加的修订计数(因此,如果存在至少43个修订版,则存在修订版41,后跟修订版42),因为这些Mercurial版本号是 local:它们特定于存储库的一个特定克隆。同一个存储库的另一个克隆可以在其中具有相同的提交,但是以另一个顺序。
(当版本首次存储在存储库中时,会分配Mercurial的顺序版本号,但是两个彼此不同步的克隆,然后重新同步,将包含相同的提交以不同的顺序。例如,在你自己的存储库X中,提交41显然在42之前出现。但这是因为你写了#41 ......当你的#41进入你的co-工作人员的存储库Y,你的#41成为他们的#42,因为他们在你写#41时写了你现在的#42。他们将他们的#41发送到他们的存储库Y它变成了他们的#41。那么你们每个人都给了另一个提交,并从另一个提交了一个提交,那就是你们俩有#41和#42,但顺序相反。)
此属性是任何分布式版本控制系统的基础:Subversion只能提供这种独特的线性化,因为它不分布式;相反,中央服务器分配修订号。 (理论上,人们可以构建一个分布式系统,它使用来自中央服务器的预订,编号中可能存在漏洞,但编号也是顺序的。我从未见过有人这样做过它提出了有趣的同步问题。特别是,您不能分发保留号已被取代的提交;相反,您必须获得一个新的更高的数字。)
回到手头的问题,让我们定义足够多的项目,看看Git如何处理 - 或者有时候不会处理这个问题。
首先,Git有存储库,它存储了一组提交和其他三种对象类型。其他三个是带注释的标签,树和 blobs (文件,本质上)。存储模型不需要带注释的标签,因此我们可以忽略它们,而树在对象哈希值和文件/路径名之间进行映射,blob只存储未解释的文件数据。
commit 是这里最有趣的对象类型。它存储:
除了这些提交之外,存储库还存储了许多引用,其中最以用户为导向的是分支名称(如master
)和< em>标签名称(如v1.2
)。 引用仅仅是名称/对象ID对,并且分支引用被约束为仅包含提交对象的ID。如果名称master
包含ID 1234567
(缩写),我们会说master
指向提交1234567
。标记名称通常指向标记对象,而不是直接指向提交;但如果是这样,标签对象则指向提交。 1
除了提交和其他对象之外,存储库还包含索引。索引有几个角色,但是对于我们来说,这里的重要角色是,你可以让Git构建你将要创建的 next 提交。索引开始填充当前提交的内容。然后,您git add
个文件来更新它们,或者将新的文件添加到索引中。当你git commit
结果时,Git获取当前的索引内容并从它们进行提交 - 尽管说它将索引转换为某些树对象更精确,然后进行提交{ {1}}是它刚刚制作的顶级树。
大多数存储库还包括工作树(拼写有或没有连字符,有时称为&#34;工作树&#34;)。工作树只是一个文件具有计算机其余部分可以处理的形式的地方:您可以编辑它们,编译它们(如果它们是源代码),等等,以及编辑器和程序之类的程序。编译器和Web服务器可以读取它们。实际存储在存储库中的文件采用仅Git格式,因此工作树提供了一个可以实际使用的区域,并对其进行处理。
1 事实上,标记对象可以指向任何其他对象,包括另一个标记,或树或blob。尽管如此,这种能力大多未被使用。
请注意,在上面的描述中,我提到tree
将当前索引转换为某些树,并从顶级树进行提交。这会以上次git commit
编辑的形式保存文件。这意味着每个提交在提交时都有每个文件,完整且完整。这比最初的预期占用空间更少,因为大多数提交保留了大多数文件与之前的提交保持不变 - 因此它们最终会重新使用底层的Git blob对象。此外,每个Git对象都存储有zlib compression(除此之外,最终Git对象是&#34;打包&#34;,但这超出了本答案的范围)。因此,尽管每个提交都有一个完整的每个文件的副本,Git存储库往往不会膨胀很多。 2
2 如果您提交了大量压缩文件的轻微变体,例如bzipped或gzipped tar文件,则会出现此规则的明显异常。在这种情况下,你打败了Git的打包文件存储格式,尽管打包,但存储库迅速增长并变得不可行。如果你允许Git存储解压缩的,永不压缩的存档,Git的存储系统运行良好,存储库仍然可以管理。
当提交git add
包含另一个提交的ID为C
的父级时,我们会说C
指向就像我们说C
指向一些提交一样。因此,如果存储库中有三个提交,master
是第一个,A
是第二个,B
是最后一个,我们可以绘制一个图:
C
此处A <- B <- C <-- master
指向master
; C
指回C
;并B
指向B
。 A
并未提前指出任何地方 - 它不能;这是第一次提交。它有 no 父项,称为 root commit 。
Git 使用名称A
查找这些提交。分支名称 - 或者实际上,任何Git引用 - 都充当了启动Git的关键,提供了大丑陋的哈希ID。一旦Git找到提交master
,它就会使用C
查找C
和B
来查找B
。
我们致电A
的{{1}}和B
后代,C
和A
祖先A。箭头连接&#34;孩子&#34;回到父母&#34;是单向链接,因此在提交时,找到提交的子项相对比较困难;但找到父母是微不足道的。
如果有分支,则会发生分支,因为两个后代最终共享父分支。例如,我将停止绘制内部箭头 - 请考虑此图:
B
这里有两个名字让Git开始。一个是Git从提交C
开始,另一个是提交A--B--C <-- mainline
\
D--E <-- feature
。按照内部向后箭头,我们从C
到E
到E
,从D
到B
。 (并且,我们像往常一样从C
转到B
,但现在它只是一条共同的线,它不再那么有趣了。)
我们说在分支主线&#34;上提交B
是&#34;而在分支功能&#34;上提交A
是&#34;。也就是说,提交A--B--C
和A--B--D--E
位于两个分支上。 这个想法是Git所特有的。例如,Mercurial 不这样做(无论如何都使用命名分支;你可以在一个分支中拥有匿名的Mercurial头,然后同样的问题突然出现,效果相同)。同样值得注意的是,我们可以稍微改变相同的图形以强调共享:
A
在任何情况下,关键概念是提交可以同时在许多分支上,并且确定提交的顺序通过这些父母/子女,祖先/后代的关系。
你想知道如何判断文件是否在&#34;之前&#34;或&#34;背后&#34;某些特定的提交,答案是,你不能。例如,假设您有文件B
并且可以检查其内容;并假设您的存储库具有上图中的五个提交 C <-- mainline
/
A--B
\
D--E <-- feature
到README.txt
。
进一步假设A
与提交E
,README.txt
和README.txt
中的B
匹配,但不匹配D
中的E
,而不是A
中的那个。 <{1}} 在之前是什么?是落后的东西?好吧,匹配 C
,README.txt
和B
;但这就是我们所能说的。
如果我们采用更大的文件集合 - 例如整个工作树 - 我们可以将它与任何提交进行比较。但是,我们要么得到&#34;它匹配&#34;或者&#34;它不匹配&#34;。如果它不匹配,D
将为您提供一组指令:&#34;以下是如何更改提交以使其看起来像工作树&# 34; (反之亦然,你的选择)。但同样,您无法判断这是提前,还是背后,或者只是混淆了(如果您故意提取每个单独的文件)从一个随机选择的提交,例如 - 谁知道为什么,也许是午夜的疯狂:-))。
可以非常轻松地确定一次提交是否是另一次提交的祖先。例如,只给出两个提交哈希值,例如E
和git diff
,我们可以问:其中之一&#34;之前&#34;另一个?如果badf00d
恰好是提交c0ffee1
的ID而badf00d
是提交B
的ID,那么是,c0ffee1
。
但如果E
是ID,而不是badf00d < c0ffee1
,而不是badf00d
,该怎么办?在{&#34;之前B
来了吗? C
? C
之前是E
吗?答案可能是mu,例如在Hofstader和Persig意义上。
(要对此进行测试,请使用E
:
C
如果第一次提交是第二次提交的祖先,则返回true,即0,退出状态。请注意,如果答案是&#34; no&#34;,您仍然必须重复测试,以免任何一方成为另一方的祖先。)
答案 1 :(得分:0)
您可以将文件与diff
进行比较(remote/<branch>
),以查找是否有任何更改。
$ git fetch
$ git diff HEAD..origin/master # diff with origin/master (remote master)