![](/img/trans.png)
[英]Git: How to fetch a single remote branch and create a remote-tracking branch of it automatically?
[英]How to create git Remote-Tracking Branch
他们说这很简单
您可以简单地通过将-u标志与“ git push”一起使用来告诉Git跟踪新创建的远程分支。
但这对我没有用。
如何创建git Remote-Tracking分支
Git现在可以通知您有关“未推动”和“未推动”的提交。
这是我的:
$ git status
On branch newfeature/v4-json
nothing to commit, working tree clean
与我的期望相比,引用以上文章 :
$ git status
# On branch dev
# Your branch and 'origin/dev' have diverged,
# and have 1 and 2 different commits each, respectively.
#
nothing to commit (working directory clean)
即,有关“未推动”和“未推动”提交的信息。
即,我希望看到与以下内容相同的内容:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
但是从上面的实际输出中,您可以看到, 尽管我已经进行了几次提交 , 但我仍然无法看到到目前为止我已经进行了多少次提交 。
这是我所做的:
$ git push -u origin newfeature/v4-json
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (12/12), 1.87 KiB | 958.00 KiB/s, done.
Total 12 (delta 9), reused 0 (delta 0)
remote: Resolving deltas: 100% (9/9), completed with 9 local objects.
remote:
remote: Create a pull request for 'newfeature/v4-json' on GitHub by visiting:
remote: https://github.com/.../pull/new/newfeature/v4-json
remote:
To github.com:xxx/yyy.git
* [new branch] newfeature/v4-json -> newfeature/v4-json
Branch 'newfeature/v4-json' set up to track remote branch 'newfeature/v4-json' from 'origin' by rebasing.
但是我没有git
从'origin'设置的远程跟踪分支'newfeature / v4-json':
A) git remote show origin
根本不显示我的newfeature的远程跟踪分支:
$ git remote show origin
* remote origin
Fetch URL: git@github.com:go-easygen/easygen.git
Push URL: git@github.com:go-easygen/easygen.git
HEAD branch: master
Remote branch:
master tracked
Local branches configured for 'git pull':
master rebases onto remote master
newfeature/v4-json rebases onto remote newfeature/v4-json
Local refs configured for 'git push':
master pushes to master (up to date)
newfeature/v4-json pushes to newfeature/v4-json (up to date)
根据http://www.gitguys.com/topics/adding-and-removing-remote-branches ,以下是我想看到的内容
$ git remote show origin
* remote origin
Fetch URL: /tmp/.../git/rp0
Push URL: /tmp/.../git/rp0
HEAD branch: master
Remote branches:
master tracked
newfeature tracked
Local branches configured for 'git pull':
master rebases onto remote master
newfeature rebases onto remote newfeature
Local refs configured for 'git push':
master pushes to master (up to date)
newfeature pushes to newfeature (up to date)
请注意,在“ Remote branches:
部分中,除了master tracked
外,还master tracked
了一个newfeature tracked
。 根据上述文章,被跟踪的 newfeature tracked
称为远程跟踪分支 。
B) git branch -a
都不是:
$ git branch -a
master
* newfeature/v4-json
remotes/origin/HEAD -> origin/master
remotes/origin/master
那里只有一个remotes/origin/master
远程跟踪名称,而我期望更多。 例如(无关紧要,只是为了显示具有更多远程跟踪名称的情况),
$ git branch -a
* master
remotes/origin/HEAD
remotes/origin/master
remotes/origin/v1.0-stable
remotes/origin/experimental
C) git branch -vv
也不是:
$ git branch -vv
master 75369c3 [origin/master] - [*] allow ...
* newfeature/v4-json 8c98d9c - [*] update ...
我希望看到,
$ git branch -vv
master 75369c3 [origin/master] - [*] allow ...
* newfeature/v4-json 8c98d9c [origin/newfeature/v4-json] - [*] update ...
此外,
git pull
也不从远程更新我的本地分支:
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
就是说,无论我拉多少次,我都不会得到相同的输出,
$ git pull
Already up to date.
Current branch master is up to date.
以上都是不正常的。 我已经使用MS VS多次创建了Remote-Tracking Branch,其结果完全符合我的预期,而不是上面的预期。 但是,我不喜欢黑魔术,所以我想知道如何使用纯git
来做同样的事情。
那么创建git Remote-Tracking Branch的正确方法是什么?
编辑以更新地址( git branch -a
和git branch -vv
)输出:是的,缺少某些内容 。 目前还不清楚到底出了什么问题,但我有一个猜测。 git push -u
输出的这一部分:
* [new branch] newfeature/v4-json -> newfeature/v4-json Branch 'newfeature/v4-json' set up to track remote branch 'newfeature/v4-json' from 'origin' by rebasing.
显示您的Git将您的origin/newfeature/v4-json
(分为两部分)设置为newfeature/v4-json
上游。 但是您的git branch -a
和git branch -vv
输出显示不存在origin/newfeature/v4-json
。
我可以通过进行单分支克隆来重现此行为的关键要素。 使用git clone --depth= number
或git clone --single-branch
将产生这样的克隆。 这样做的副作用是,您的Git将永远不会为任何分支创建任何远程跟踪名称, 除非您告诉Git所关心的那个分支。 如果这是问题所在,则解决方法是将克隆转换为普通(多分支)克隆。 (如果使用--depth
创建单分支方面,则取消克隆该副本也是明智的。)
要查看您的origin
克隆是否设置为单分支:
$ git config --get-all remote.origin.fetch
在普通克隆中,将打印:
+refs/heads/*:refs/remotes/origin/*
在选择了分支master
的单分支克隆中,将打印:
+refs/heads/master:refs/remotes/origin/master
它告诉您的Git: 为master
创建一个远程跟踪名称,而不是为*
(即所有分支)创建前者的远程跟踪名称 。
取消origin
克隆的单分支:
$ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
(或直接编辑.git/config
,例如git config --edit
,这是我的首选方法)。 另请参阅如何“撤消”-单分支克隆?
要将浅层克隆转换为完整(非浅层)克隆,只需运行:
$ git fetch --unshallow
请注意,尽管git clone
默认将它们git clone --depth= number --no-single-branch
在一起,但此操作与单分支无关(您可以在git clone
时使用git clone --depth= number --no-single-branch
覆盖此操作)。 在2.15之前的版本中,没有针对浅薄度的命令行测试; 在2.15或更高版本中,使用:
git rev-parse --is-shallow-repository
但在此之前,您必须测试文件.git/shallow
的存在:
if [ -f $(git rev-parse --git-dir)/shallow ]; then
echo true
else
echo false
fi
模拟git rev-parse --is-shallow-repository
。
顺便说一句,您要查看的输出存在问题。 您说您想将newfeature
看作是远程服务器上的一个分支,但这不会发生,因为需要存在newfeature/v4-json
名称,这排除了newfeature
的存在能力。
(以下行的原始答案。)
$ git push -u origin newfeature/v4-json
这完全按照您的要求进行。 在您显示的其余输出中,一切都很好。 因此,尚不清楚您认为错在哪里; 其实没有错。 我将解决您显示的其他消息:
# Your branch and 'origin/dev' have diverged, # and have 1 and 2 different commits each, respectively.
下面。
回顾一下Git的工作方式和一些Git特有的术语可能会有所帮助。 我认为,特别是,您使用的短语- 远程跟踪分支 -是一个坏词,会引起误解。 这是一个Git术语,所以我们应该理解人们在使用它时的含义,但这是一个不好的术语,这意味着人们会滥用它,如果您对某人的使用感到困惑,那么可能应该退一步并考虑一下这些事情再次发生。
首先,让我们注意Git实际上就是关于commit的全部内容。 承诺是Git的存在理由 ; 没有提交,我们根本不会使用Git。 因此,让我们看看什么是提交。
每个提交都包含文件,但不仅仅是一组文件。 它是快照中所有文件的快照, 1但它也包含一些元数据: 有关存储数据的信息。 最明显的是您在git log
输出中看到的内容:您的姓名和电子邮件地址,以及计算机对您进行提交的日期和时间的想法,以及为进行提交而保存的原因 ,即您的日志消息。 这些都是供您(或其他人)将来使用的:某天,也许明天,也许几个月或几年之后,您可以回顾一下您刚才所做的提交,并问自己: 我为什么要做那 ? 答案应该在您的日志消息中。
因为提交存储文件(作为快照,时间冻结,不可变并且可以永久存在(或只要提交本身一直存在)),所以非常适合归档。 在将来的任何时候,您都可以回顾过去,并准确地查看当时保存的内容。 您无法更改:它是过去的,固定的,已冻结的时间。 稍后我们将看到,即使Git也无法更改它。
为了找到提交,Git需要一个名称。 这些名称不是分支名称! 或者,更准确地说,您可以使用分支名称开始,但这不是Git所需的名称。 相反,任何提交的真实名称是其哈希ID 。 每个提交的哈希值ID 似乎是随机的,但实际上,它是上提交的全部内容的加密校验,以在提交数据的每一个位极其敏感:所有冻结的快照,并您的姓名和时间-stamp和您的日志消息。 这就是为什么您或任何人都不能更改提交的原因:更改任何内容都会更改哈希ID,然后您将拥有一个新的不同的提交。 在进行新提交之前,没人知道哈希ID是什么。 当时,它获得了唯一的ID。 没有人会将该ID用于其他任何提交! 没有人可以改变什么提交:Git会知道,如果你尝试,因为该ID不匹配了。 2
这个特殊的拼图游戏有最后一两个关键部分。 第一个是,在每个新提交中,Git都将前一次提交的哈希ID(真实名称)存储为该元数据的一部分。 也就是说,Git不会只是保存您的姓名和时间等,同时也节省了您的使用,使这个新提交的提交的原始哈希ID。 Git将此保存的哈希ID称为提交的父级 。 这意味着每个提交都在向后看的链中指向其父提交。
例如,假设我们在存储库中只有两个提交A
和B
A
是第一个提交,因此特意没有父提交-这是特例。 但是B
是由A
制成A
,因此B
指向A
:
A <-B
如果您提取提交B
,执行一些工作,然后进行新的提交C
,则新的提交将自动指向B
:
A <-B <-C
这意味着Git只需要知道最后一次提交的表面上随机的哈希ID。 在这种情况下,提交C
如果其实际的哈希ID是cba9876...
或其他值,Git可以使用它来查找C
的内容 。 这些内容包括提交B
的实际哈希ID。 然后,Git可以使用它来查找B
,其内容包括提交A
的实际哈希ID。 Git可以使用它来查找A
,而A
没有父母,所以现在,Git终于可以停止向后工作。
从分支提示提交(例如,由分支名称标识的C
向后工作的过程在Git中至关重要。 历史就是这样存在的 。 Git存储库中的历史记录是提交,这些提交通过这些向后的箭头连接。 您从头开始,一次走动一次,遍历历史,按照父箭头查看可以到达的位置。
当分支名称和其他此类名称显示出来时,这是最后一个拼图碎片输入图片的地方。 让我们暂停一下,在这里结束脚注,然后深入研究分支名称和图形绘制。
1 Git实际上是从索引制作快照的,但是我们不会在这里介绍这些细节,除了说要快照的内容(对于该提交,永远冻结的时间)就是当时索引中的内容,这至少可能与您在工作树中看到的内容有所不同。
2 Git实际上会在方便或适当的时候进行检查。 这会自动检测到Git存储库的意外损坏,例如在您尝试将其存储在Dropbox中时发生的情况。Dropbox有时会四处修改(和Git的)背后的文件,而Git会抓住它。 不幸的是,很少有修复损坏的存储库的好方法-而是,Git倾向于依赖Git存储库在各处复制的想法。 您可能在其他地方有一份不错的副本,因此您完全可以将其扔掉。
任何现有的存储库(好吧,除了一个完全空的,新鲜的, 没有提交的新存储库之外的任何其他存储库)都具有一组提交。 这些提交构成了我们刚刚看到的向后看的链,例如:
A <-B <-C
我们和Git需要某种方式来记录该链中最后一次提交的哈希ID。
Git实现此目标的方法是Git称为reference或refs 。 裁判的形式很多,但三巨头是:
master
。 origin/master
。 (Git称这些远程跟踪分支名称或远程跟踪分支 ,我认为这是一个坏名字;我已改用远程跟踪名称 ,我认为这很难弄错。) v1.3
。 它们实际上都是由相同的基础技术实现的,但在这里我们将它们视为单独的名称形式。 分支名称具有特殊属性; 所有其他名称都缺少此属性。
这些名称之一的含义非常简单:它只是Git对象的实际原始哈希ID,通常是提交。 3因此,像master
这样的分支名称指向分支中的最后一个提交-在此图形中提交C
:
A--B--C <-- master
请注意,相互连接的箭头从子对象中出来并指向(不可变的)父对象,这为我们提供了这种向后遍历的方法。 我们不必费心将它们插入。但是, 分支名称中的箭头会更改 。
当我们向master
添加新的提交时,Git会自动更新名称master
来保存新提交的哈希ID。 因此,如果我们现在创建一个新的提交,则新的提交D
将指向C
:
A--B--C <-- master
\
D
但是Git会立即调整master
使其不指向C
而是指向D
:
A--B--C--D <-- master
由于D
指向C
,我们仍然可以找到所有提交:我们从结尾开始,然后像往常一样向后工作。 现在, C
是此过程中的第二个提交,而不是第一个。
3分支名称必须包含提交对象哈希ID,而标记名称则更灵活。 我们在这里不需要关心这一点。 因为远程跟踪名称的值是从分支名称中复制的,所以远程跟踪名称也仅包含提交哈希ID。
Git是一个分布式版本控制系统。 这意味着每个Git存储库都是一种独立的孤岛,它需要的所有内容都在该存储库本地。 如果有许多提交多个分支机构,他们都在一个存储库:
A--B--C--D--G--H <-- master
\
E--F <-- dev
为了使Git真正有用,我们定期使用Git与其他Git用户交换工作。 为此,我们交换了commits 。 由于这种密码校验和技巧,它们的哈希ID在所有地方的所有 Git中都是通用的。 给定快照和元数据, 每个地方的每个 Git都会计算相同的哈希ID 。 因此,如果我的存储库具有这样的提交A
到H
(请记住,这些单个大写字母代表着唯一的,大的丑陋哈希ID),并且我连接到您的存储库并且您具有提交H
,则您的存储库还必须具有与矿。
如果您没有提交H
,那么我有您没有提交。 如果你有一些犯I
还是J
, 你有一个承诺, 我不知道。 无论哪种方式,我们的Gits都可以交换哈希ID来查看谁拥有什么。 发送提交的人将发送它们,接收提交的人将接收它们,发送者将向接收者提供任何需要的新提交。
假设您正在接受我的新委托。 我有新的提交I
和J
,而我的新提交J
的名称可以记住其哈希ID。 在我的存储库中,我有:
A--B--C--D--G--H <-- master
\
E
\
I--J <-- dev
无论出于什么原因,我都没有像 dev
那样提交F
相反,在(共享)提交E
之后,我对我的dev
进行了IJ
提交。
您的Git接受了我的承诺I
和J
我的承诺是I
有父母E
因此, 您的存储库现在具有以下内容:
A--B--C--D--G--H <-- master
\
E--F <-- dev
\
I--J <-- ???
您的 Git存储库将使用什么名字来记住我的提交I
? 最好不要使用dev
:如果您的Git使您的dev
指向commit I
,您将如何再次找到commit F
? 请记住,它具有一个显然是随机的哈希ID。 您将永远无法猜测 。
因此,您的Git所做的就是使用远程跟踪名称来记住我的分支。 您的Git会这样做:
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
(假设我的master
指向H
)。
您存储库中的origin/master
和origin/dev
名称是您的远程跟踪名称 ,记住了master
和dev
。 4此外,假设您现在查询Git,要求它在Git使用的普通向后走行方法中,比较dev
与origin/dev
可以到达的提交集。
从dev
开始,将要访问的提交是F
,然后是E
,然后是D
,依次类推回到A
从origin/dev
,将要访问的提交是J
,然后是I
,然后是E
,然后是D
,依次类推回到A
哪些提交是哪个步行特有的? 您从dev
到达的提交数量是您从origin/dev
不能到达的提交数量,反之亦然?
算出这些,然后与您的Git告诉您的内容进行比较:
# Your branch and 'origin/dev' have diverged, # and have 1 and 2 different commits each, respectively.
实际上,这里的拼图游戏还缺少另一部分,当我们在下面谈论git push
时,我们将在上一节中对其进行简要介绍。
4 Git有时称其为跟踪,而不是记住 ,但这是Git严重滥用单词的另一个地方。 我已经在远程跟踪中使用了它,但是至少在这里它是带连字符的,并用这个词作为形容词修饰remote 。
git push
与git fetch
不同 上面的过程是您的Git从origin
的Git上找到的分支名称创建远程跟踪名称的过程,它特定于git fetch
。 当你有你的Git调出的Git在它发生origin
,把他们提交给你 。
当然,您可以让您的Git在origin
调用他们的Git并发送提交。 这就是git push
操作,非常相似。 您的Git告诉他们的Git您所拥有的提交,而他们没有。 让我们画一些。 我们将从此开始:
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
现在,我们将运行git checkout master
和git checkout -b newfeature/v4-json
或更简单的命令:
git checkout -b newfeature/v4-json master
现在,我们有:
A--B--C--D--G--H <-- master, origin/master, newfeature/v4-json (HEAD)
\
E--F <-- dev
\
I--J <-- origin/dev
我们已经将特殊名称HEAD
附加到newfeature/v4-json
以记住添加新提交时更新哪个分支名称。
现在,我们将创建一个新提交。 它可能不止一个,甚至没有一个 ,但我们只创建一个用于说明。 新的提交有一些大的丑陋的哈希ID,但我们在这里将其称为K
:
K <-- newfeature/v4-json (HEAD)
/
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
现在,我们将使用以下命令让您的Git在origin
调用Git:
git push -u origin newfeature/v4-json
您的Git拨号他们的Git并宣布您已提交K
和H
5他们没有K
但是他们有H
所以他们让您的Git通过其快照和元数据发送提交K
您的Git可以告诉您,由于它们具有H
因此它们也具有G
和D
及其之前的所有内容,因此您只需向他们发送K
及其内容。
然后,最后,您的Git询问他们: 请,现在,如果可以,请设置名称newfeature/v4-json
指向commit K
请注意,您没有让他们设置xpt/newfeature/v4-json
或类似的东西。 您让他们设置了分支! 他们实际上还没有newfeature/v4-json
,因此他们可以设置一个。 他们做到了! 现在, 他们的存储库中有一个newfeature/v4-json
,指向commit K
你的Git现在创建 远程跟踪名称 origin/newfeature/v4-json
,指着承诺K
,记住他们的 newfeature/v4-json
,指向提交K
。 6但这仅表示您的图形中有一个额外的名称 ,如下所示:
K <-- newfeature/v4-json (HEAD), origin/newfeature/v4-json
/
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
由于使用-u
选项,您的Git也会立即运行:
git branch --set-upstream-to=origin/newfeature/v4-json newfeature/v4-json
这将为分支newfeature/v4-json
设置上游设置。 您的每个分支都可以具有一 (1)个上游设置,以这种方式使用它非常典型。 请参阅为什么我总是需要执行--set-upstream`吗? 更多。
5您的Git 可以告诉他们有关F
,但前提是您在这里说过git push origin dev
。 使用带有或不带有-u
git push origin newfeature/v4-json
,您告诉Git:根据需要告诉他们有关K
, H
, G
, D
, C
, B
和/或A
提交。 您其他未共享的提交则有意保留为私有。
6请记住,由于哈希ID的魔力,提交K
在世界各地的每个 Git中都是通用的。 每个 Git通过其哈希ID都具有K
,然后就是该提交; 或者根本没有K
,所以没关系。
(这并不一定是100%的保证。假设的哈希ID K
实际上是b5101f929789889c2e536d915698f58d5c5c6b7a
,这是在Git仓库的Git的本身提交的哈希值ID。如果你从来没有你的 Git仓库连接到一个Git仓库GIT中,它是好的,您和他们具有相同的哈希ID的不同提交,但是如果您确实将Git存储库连接到Git的Git存储库,则会发生一些不太理想的事情。简短的版本是您不会Git的提交,而他们却没有得到您的支持:这两个仓库现在根本无法合并,这对您和维护Git的人来说都完全可以,但另请参见新发现的SHA-1碰撞对您的影响git? )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.