如何将git rev-list限制为特定分支和远程站点?

时间:2018-11-08 19:50:21

标签: git

我希望能够在git rev-list中搜索特定的远程/分支组合。 git rev-list documentation对于--branches--remotes选项感到困惑,我认为这是我要使用的选项。

对于--remotes,文档显示:

  

-远程[=模式]

     

假装好像引用/远程处理中的所有引用在命令行上都列为[commit]。如果指定了[pattern],则将远程跟踪分支限制为与给定的shell glob匹配的分支。如果模式缺少末尾的?,*或[,/*。

我不明白当它说它们像“ commit”那样在命令行中列出时的含义。

我感到困惑的部分原因是我不确定字符串--branches--remotes会搜索哪种格式,因此我不得不在各个地方插入通配符以查看其是否有效。我本来以为分支会像“ remote / remote_name / branch_name”,而远程会像“ remote_name”,但是当我尝试着进行搜索时,却没有得到我期望的结果。

例如,这是我要运行的基本查询:

 git rev-list --after='timestamp' --author="Name" --format='%h,%aI,%cI'

我在各种通配符配置中使用了--branches=*remote_name/branch_name --remotes=remote_name的变体,但是它永远无法工作。我的意思是,我知道在存在提交A的某些远程/分支组合中,但是有时特定远程的所有分支都将找到提交A,即使它不应该找到,有时在非源远程上也没有分支即使我知道它存在,也会返回“提交A”。

我认为,只要我能更好地理解如何使用--branches--remotes进行搜索,我就能将它们拼凑在一起。可能不希望同时启用这两个选项来搜索rev-list

任何帮助将不胜感激。

谢谢。

2 个答案:

答案 0 :(得分:2)

TL; DR

git rev-list仅涉及遍历提交图(DAG)。您给它起点。 --branches是给它各种起点的一种方法; --remotes是另一个。与git log(默认使用HEAD作为起始点)不同,您必须 some 提交起始点指定为git rev-list。然后,它列出可达提交:这些名称仅在定位图形遍历的起点方面才有意义。

在Git中,您必须牢记什么是分支(​​或不是分支)。没有这个概念,您将被误入歧途。为了进行比较,让我们首先看一下Mercurial,其中 branch 是更具体的东西(尽管最近,Git对 branch 的定义松散而草率)也渗入了Mercurial的使用中。

在Mercurial中,您使用以下方法创建分支:

hg branch <name>

,然后对其进行提交。这些提交永远在该分支上 (好吧,直到/除非它们被剥离,但忽略删除提交的能力,它们就永远存在了)。如果提交C在分支X上,则在X上,而不在其他任何分支上。询问哪些提交在分支X上,它将始终包含C。有道理吧?提交被永久装订到其分支;分支是该分支上曾经进行的所有提交的集合。

在Git中,情况并非如此。您在分支C上进行提交X,并且在分支X上进行提交,但是在几分钟(或几天或几个月)内,它也在分支{{ 1}}和YZ。此时,完全删除分支master,并提交X仍在分支CYZ上。您甚至可以移动名称master,以使X上的提交C不再是 ,但仍{{{ 1}}。

换句话说,在Git中,提交 not 被装订到其分支。提交是否在某个分支中是动态属性,将来可能会更改。提交的存在或不存在包含它们的分支。 commits 很重要; 1 但是,提交是永久的(很好,主要是)并且是只读的,永远冻结。因此, commits 是固定的;是分支名称

考虑到这一点,让我们绘制一些图形。


1 分支名称或其他引用在Git中有其他用途,但是最好以此为模型。一旦掌握了这个概念,其余的将就位。


Git提交图

每个提交都记录其直接的前身(即 parent )提交。在最简单的情况下,一个提交有一个父级,而那个提交的父级有一个父级,依此类推。从链的末端开始,我们可以轻松地向后工作:

X

分支 name (在这种情况下为master)存储要被视为该分支一部分的 last 提交的原始哈希ID。提交A <-B <-C ... <-G <-H <--master 为其先前的提交master存储另一个提交哈希ID。 H存储其父级的哈希ID,依此类推,直到提交G。提交G存储B的哈希ID,但是B是有史以来的第一个提交,因此它没有父对象。

(由于提交本身是固定的,因此不再需要将内部箭头绘制为箭头,这对下一步很有帮助,因为文本中的箭头绘制非常有限。因此,从现在开始,我将使用:< / p>

A

例如。但是,分支名称的箭头会移动很多,因此将其保留为箭头很有用。)

在Git中向分支添加 new 提交只是冻结源快照并创建提交对象。新的提交对象记录当前提交的哈希ID,以便我们维护此向后链。然后,新的提交将获得自己的新的唯一哈希ID,Git将新的哈希ID写入分支名称:

A

成为:

A--B--C   <-- master

但是我们可以添加更多的分支名称。在进行另一个新提交之前,我们要这样做:让分支名称A--B--C <-- master 指向提交A--B--C--D <-- master

develop

现在Git需要知道要更新的 分支名称,因此Git将名称D附加到一个(并且只有一个)分支名称:

A--B--C--D    <-- master, develop

现在,当我们进行新的提交HEAD时,Git更新的分支名称不再是A--B--C--D <-- master, develop (HEAD) ,而是E

master

提交develop现在在A--B--C--D <-- master \ E <-- develop (HEAD) 上。提交Edevelop都在开发上,而A上。现在D,然后重新提交master

git checkout master

提交FA--B--C--D--F <-- master (HEAD) \ E <-- develop 上仅 ,而Fmaster和<{ {1}}都在这两者上。

如果我们在开发上再提交一些承诺,我们将得到:

E

(由于我们仍然要移动它,因此我在这里省略了develop。)

现在让我们运行A-B-C-D。这将合并自共享提交A--B--C--D--F <-- master \ E--G--H <-- develop 起的所有HEAD更改与自共享提交git checkout master && git merge develop以来的所有master更改。也就是说,Git将运行:

D

Git将结合两组更改,将它们应用于develop中的快照,并进行一次具有两个父级的新提交D

git diff --find-renames <hash-of-D> <hash-of-E>   # what happened on master
git diff --find-renmaes <hash-of-D> <hash-of-H>   # what happened on develop

提交D返回到两者 I A--B--C--D--F------I <-- master (HEAD) \ / E--G--H <-- develop I回到{{ 1}},然后到达H,然后我们制作的叉子在F处向后重新接合,从而导致HG,最后是{{1} }。因此,所有这些提交现在位于E上。 {{1}上的DC都是 ,而两个分支上的B都是。

这是关于合并提交的特殊之处。现在我们有了合并提交,我们可以删除名称A

master

所有提交都保留在I上。名称F不再存在。曾经在那里吗?还是那海市mi楼? Git不在乎这两种方式。

masterA-B-C-D-E-G-H

developA--B--C--D--F------I <-- master (HEAD) \ / E--G--H 都与此提交图有关。这两个命令非常接近-实际上,它们是从相同的源文件构建的,根据您运行的是master还是develop,具有两个不同的入口点。两者都将从您指定的末端开始并向后遍历图形。 git rev-list默认为您显示每个遍历的提交,而git log默认为仅显示其哈希ID。

另一个关键区别是这个git rev-list概念。 Git希望通过将名称git log附加到一个分支名称来跟踪您已签出的分支。默认情况下,git log命令将查找git rev-list并将其用作其(单个)起点; git log要求您提供一些起点。

他们两个都这样做“从头开始并向后工作”。如果git rev-list指向上面的示例中的提交HEAD,并且HEAD是指向提交git logHEAD的合并提交,则两者都将首先显示您提交了git rev-list(或其哈希ID),然后选择masterI中的一个进行下一步显示。然后,他们将显示IF(如果尚未混合,则显示H,如果混合,则显示I和C F B {{ 1}} A H A`没有父母,就停在那里。

最后,由于每次提交都可以从给定的起点到达,因此,两次提交都将显示或列出每次提交,因此提交G。如果您给他们一个不同的起点,例如提交E,他们将向您显示F然后是D然后是and然后是and

模式(带有, and since)可能很棘手,因为命令行解释器(“ shell”)往往会自己扩展I。如果运行D,将看到所有文件名的列表。如果运行D,则只会看到以C开头的文件名。 B可能会尝试扩展到名称以A开头的文件,尤其是当您有一些使用这些名称的文件时。

如果您在末尾省略了--branches=*,则Git会在内部提供它,从而避免使用shell。

答案 1 :(得分:0)

解决方案

同时搜索远程分支和分支的解决方案是使用以下选项:

git rev-list ... --remotes=*remote_name/branch_name

在此处同时使用--remotes--branches选项可以,但前提是您已经签出了相关分支。

说明

使用--branches=*branch_namerefs/heads中查找具有给定名称的分支,该文件夹是存储有关已签出分支的信息的文件夹。这意味着它只能根据已经签出的分支搜索git修订历史。

只要已将--remotes=*remote_name添加到您的本地远程列表中,就使用refs/remotes查找具有此名称的遥控器(rev-list是一个文件夹,用于存储有关所有已添加的遥控器的信息)。

如果同时使用这两个选项,refs/remotes可以找到您的遥控器,但是除非您已将其签出,否则它找不到您的分支。。

但是,--remotes=*remote_name/branch_name实际上将有关 all 分支的信息存储在这些远程服务器上,因此您只需使用refs进行搜索即可。

通过转到隐藏的.git文件夹中的实际文件夹,可以查看cd .git/refs中的信息。在您的git文件夹中,只需Eigen::NaturalOrdering