我有一个像这样开始的脚本:
#!/bin/sh
for b in `git branch -r | grep -v -- '->'`; do git branch --track ${b##origin/} $b; done
git fetch --all
这将获取所有远程分支。我只想获取以“hotfix”开头的分支。
我该怎么做?
编辑: 一开始,除了主人
之外,我还想删除所有分支答案 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(通常缩写为face0ff
或cafedad
或其他)
理解Git的关键之一是认识到Git中的分支名称具有相当重要的意义。它们主要以两种方式起作用,其中一种方式与git fetch
相关联,因此我们很快就会回到这一点 - 但首先,我们需要查看提交图( DAG ,在gitglossary中)。 DAG或 D 竖立 A 循环 G raph,来自您的存储库中的所有提交。它是git fetch
提取的图,其名称仅仅是在图表中启动的方式。名称(如master
或branch1
)会转换为提交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分支,但是在某些其他名称下。
这是远程名称重新输入图片的位置。他们的分支有名称,如master
和branch1
以及hotfix
。我们的Git将接受他们的Git通过他们的名字找到(可达到)的提交,并将它们与我们现有的提交相结合。但是我们的Git必须在我们的存储库中提供他们的提交名称,这里我们的Git使用我们的远程跟踪分支名称。
当我们运行git fetch
时,我们的Git会调用他们的Git并询问他们拥有哪些分支(以及标记和其他名称),以及这些名称的提交内容。然后我们的Git检查我们是否有这些提交。如果没有,我们的Git要求这些承诺,他们的父母,以及那些父母&#39;父母等等,直到我们的Git找到了我们已经拥有的一些提交。在这一点上,我们的Git不再需要它们的提交,因为我们刚刚发现它们的图形与我们的图形连接在一起。
接下来,我们的Git将这些提取的提交存储在我们的存储库中,现在是最后的关键步骤:我们的Git将ID存储在我们的远程跟踪分支名称下。也就是说,他们的 master
可能是deadcab
,而我们的badbeef
是origin/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
可以直接实现。这几乎,但并不完全是你想要的。
你建议你想要的是:
删除所有本地分支名称,hotfix*
除外。这是一个有效的事情,但要小心,因为它使您自己的提交无法访问。您拥有的任何提交,其他人都没有,只能通过您自己的本地分支名称进行提交,不再具有名称。这将使他们有资格进行垃圾收集。
获取(作为远程跟踪分支)他们正在调用的分支git for-each-ref
,并使本地分支指向同一个提交。
在脚本中执行此类工作的Git命令是for-each-ref
。要使用它,您需要知道您自己的本地分支是特定类型的Git 引用(因此refs/
)。引用只是以refs/heads/
开头的名称,而分支名称只是以refs/remotes/
开头的引用。 远程跟踪分支只是一个以origin
开头,然后具有远程名称的引用,因此所有refs/remotes/origin/
分支都是git fetch origin
。
因此,我们希望分三步完成:
origin
:在origin/*
下存储的网址中调用Git,从中获取任何新提交,并更新我们自己的refs/remotes/origin/
远程跟踪分支(即, --prune
)中的所有内容。我们也应该使用origin/*
,它告诉我们的Git 删除,来自我们的远程跟踪分支,origin
上不再存在的任何git fetch --prune origin
分支。因此:
git for-each-ref refs/heads
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*
创建新的本地分支,其名称模仿名称与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}}