在脚本中拉出某些git分支

时间:2017-01-03 20:10:50

标签: git branch git-branch

我有一个像这样开始的脚本:

#!/bin/sh
for b in `git branch -r | grep -v -- '->'`; do git branch --track ${b##origin/} $b; done
git fetch --all

这将获取所有远程分支。我只想获取以“hotfix”开头的分支。

我该怎么做?

编辑: 一开始,除了主人

之外,我还想删除所有分支

1 个答案:

答案 0 :(得分:1)

这并不是你认为它做的。我会稍微向后解决这个问题,因为......

第2项:git fetch --all表示从所有遥控器中提取。这与分支机构没什么关系。

项目#1:让我们定义术语远程,因为Git并没有做得很好。 (The gitglossary documentation描述了远程存储库远程跟踪分支,而没有定义单词" remote"!)A remote 主要是URL的简短单字名称。经典遥控器是单词origin。大多数存储库是通过克隆创建的,克隆设置远程以保存原始URL。此遥控器的默认名称为origin

因此,git fetch --all从所有遥控器中取出。除非你有多个遥控器,否则这没有什么特别之处。如果您只有origin,那么您仍然可以像往常一样从origin抓取。

第3项是Git实际取得的问题。事情变得复杂了。但是,让我们先注意,每个提交都有自己的唯一ID,Git打印的那些丑陋的SHA-1哈希ID(通常缩写为face0ffcafedad或其他)

理解Git的关键之一是认识到Git中的分支名称具有相当重要的意义。它们主要以两种方式起作用,其中一种方式与git fetch相关联,因此我们很快就会回到这一点 - 但首先,我们需要查看提交图 DAG ,在gitglossary中)。 DAG或 D 竖立 A 循环 G raph,来自您的存储库中的所有提交。它是git fetch提取的,其名称仅仅是图表中启动的方式。名称(如masterbranch1)会转换为提交ID。 Git通过其ID查找提交,并获取Git提交的内容。

每个提交在其内容中存储其父提交的ID。大多数提交只有一个父。 合并提交是指具有多个父级的提交,并且至少有一个 root 提交,其中没有父级。存储库中的第一个提交必然是根提交。这意味着我们总是可以从最近的一次提交开始,然后在向其父级提交之后向后工作。使用那个父母,我们找到了它的父母,并且使用这些父母,我们找到了更多的父母,直到我们最终回到根部。如果我们绘制过程,如果没有分支和合并,我们会得到这样的东西:

o <- o <- o ... <- o <- o   <-- most-recent

其中每个o表示一个提交,而向后指向的箭头表示从commit到parent。因为他们只指向后方,而不是前瞻,我们只能从孩子到父母,从不从父母到孩子。 1

内部链接的向后方向通常不那么重要,除了它们显示为什么我们必须有一个名称 - 例如分支名称 - 以获取我们开始了:最近的提交没有后来的提交指向它。这是分支名称的来源,在Git中:分支名称是我们查找最新提交的方式。

因此,如果有三个名称,master和两个branch - es,并且没有可见的合并,我们可能会像这样绘制DAG:

o--o--o--...--o--o   <-- master
       \
        o--...--o    <-- branch1
                 \
                  o  <-- branch2

在此图中,较新的提交是向右和较旧的提交。还值得指出的是 root 提交实际上是在所有三个分支上,并且在这个特定的图中,除了一个提交之外的所有提交branch2也在branch1。这是理解Git的另一个关键:提交通常在许多分支上同时进行。分支名称只是让我们开始,所以我们不会错过任何提交。它不一定是唯一的方式来进行提交,但我们需要一些名称,通过它我们可以找到每个提交。 2

简而言之,这些名称 - 分支名称,标记名称或任何其他名称 - 使某些提交可到达

这个相当长的时间最终将我们带到了git fetch实际取得的东西。

1 例如,维护命令git fsck执行此操作。它会找到没有指向它们的名称的提交。这些被称为&#34;未参考&#34;和&#34;悬挂&#34;提交,并且它们实际上是正常的,因为Git在正常的存储库工作过程中旋转了许多故意放弃的提交。 Git&#34;垃圾收集器&#34;或git gc最终清理它们。

2 该名称不一定是分支名称。例如,任何标记名称或refs/stash也可以命名提交,这些提交的提交根本不需要在任何分支上。

git fetch将一些名称定位到我们的存储库中

请记住,当我们运行git fetch时,我们会让我们的Git联系另一个Git。其他Git拥有自己的,独立的,独立的Git存储库,具有自己的提交和自己的分支。

当我们让Git调用他们的Git时,我们通常不希望我们的Git提交被Git的提交遗忘并替换。我们通常不希望我们的分支被丢弃,而不是他们的分支。 3 相反,我们通常想要的是拥有我们的 Git的提交被添加到。我们希望将他们的提交添加到我们的中,我们希望我们的Git能够记住他们的Git分支,但是在某些其他名称下

这是远程名称重新输入图片的位置。他们的分支有名称,如masterbranch1以及hotfix。我们的Git将接受他们的Git通过他们的名字找到(可达到)的提交,并将它们与我们现有的提交相结合。但是我们的Git必须在我们的存储库中提供他们的提交名称,这里我们的Git使用我们的远程跟踪分支名称

当我们运行git fetch时,我们的Git会调用他们的Git并询问他们拥有哪些分支(以及标记和其他名称),以及这些名称的提交内容。然后我们的Git检查我们是否有这些提交。如果没有,我们的Git要求这些承诺,他们的父母,以及那些父母&#39;父母等等,直到我们的Git找到了我们已经拥有的一些提交。在这一点上,我们的Git不再需要它们的提交,因为我们刚刚发现它们的图形与我们的图形连接在一起。

接下来,我们的Git将这些提取的提交存储在我们的存储库中,现在是最后的关键步骤:我们的Git将ID存储在我们的远程跟踪分支名称下。也就是说,他们的 master可能是deadcab,而我们的badbeeforigin/master = deadcab。我们不想替换我们的,但我们确实想要记住他们的 - 所以我们让Git记得...--o--o--o <-- master (badbeef) \ o--o <-- origin/master (deadcab) 。现在我们的图表看起来像这样:

deadcab

提交master,他们的cafeb0b指回提交badbeef,提交回master,即master。我们将origin/master我们的master称为与master分开。

如果我们决定喜欢他们的两个新提交,我们可以直接将deadcab推进到...--o--o--o \ o--o <-- master, origin/master (deadcab)

deadcab

现在我们有两个名称指向相同的提交,master;但那很好。这两个名称是我们的origin/master和我们的origin/master(我们的master是我们Git对他们的 git fetch的记忆,基于上次我们从他们那里取来了。)

3 如果我们想要那个,这称为&#34; fetch mirror&#34;,master可以直接实现。这几乎,但并不完全是你想要的。

你想要的几乎是,但并不完全是一个获取镜像

你建议你想要的是:

  1. 删除所有本地分支名称,hotfix*除外。这是一个有效的事情,但要小心,因为它使您自己的提交无法访问。您拥有的任何提交,其他人都没有,只能通过您自己的本地分支名称进行提交,不再具有名称。这将使他们有资格进行垃圾收集。

  2. 获取(作为远程跟踪分支)他们正在调用的分支git for-each-ref,并使本地分支指向同一个提交。

  3. 在脚本中执行此类工作的Git命令是for-each-ref。要使用它,您需要知道您自己的本地分支是特定类型的Git 引用(因此refs/)。引用只是以refs/heads/开头的名称,而分支名称只是以refs/remotes/开头的引用。 远程跟踪分支只是一个以origin开头,然后具有远程名称的引用,因此所有refs/remotes/origin/分支都是git fetch origin

    因此,我们希望分三步完成:

    1. origin:在origin/*下存储的网址中调用Git,从中获取任何新提交,并更新我们自己的refs/remotes/origin/远程跟踪分支(即, --prune)中的所有内容。我们也应该使用origin/*,它告诉我们的Git 删除,来自我们的远程跟踪分支,origin上不再存在的任何git fetch --prune origin 分支。因此:

      git for-each-ref refs/heads
    2. master:这将让我们对每个本地分支做一些事情。除非名称为git checkout master,否则我们要将其删除。这也需要一点小心,因为我们无法删除已签出的分支,因此首先git checkout master git for-each-ref --format='%(refname:short)' refs/heads | while read b; do [ $b == master ] || git branch -D $b done 可能是个好主意:

      hotfix*
    3. 创建新的本地分支,其名称模仿名称与git for-each-ref --format='%(refname:short)' 'refs/remotes/origin/hotfix*' | while read rb; do b=${rb#origin/} git branch $b --track $rb done 形式匹配的远程跟踪分支:

      {{1}}