如何创建GIT远程跟踪分支机构 [英] How to create git Remote-Tracking Branch
问题描述
They said就这么简单
您可以告诉Git跟踪新创建的远程分支,只需使用-u标志和"git推送"即可。
但这对我来说从来都不管用。
如何创建GIT远程跟踪分支,
Git现在可以通知您"未推送"和"未拉出"提交。
这是我的:
$ git status
On branch newfeature/v4-json
nothing to commit, working tree clean
与我预期的相比,引用above article:
$ 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
根本没有显示我的新功能的远程跟踪分支:
$ 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
,还有一个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创建了很多次远程跟踪分支,结果完全符合我的预期,而不是上面的结果。然而,我不喜欢黑魔法,所以我想知道如何使用普通的git
来做同样的事情。
那么创建Git远程跟踪分支的正确方式是什么?
推荐答案
已更新地址编辑(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
,这是我的首选方法)。另请参阅How do I "undo" a --single-branch clone?
要将浅克隆转换为完整(非浅)克隆,只需运行:
$ git fetch --unshallow
请注意,此操作独立于单分支,尽管git clone
默认情况下将它们绑定在一起(您可以在git clone
时间用git clone --depth=number --no-single-branch
覆盖它)。在2.15之前的Git版本中没有针对浅表的命令行测试;在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实际上是关于提交的。提交是Git的raison d'être;没有提交,我们根本不会使用Git。那么让我们来看看什么是提交。
每次提交都包含文件,但不仅仅是一组文件。它是您拍摄快照时所有文件的快照,1,但它也有一些元数据:有关存储数据的信息。最明显的是您在git log
输出中看到的内容:您的姓名和电子邮件地址,计算机对您提交时的日期和时间的概念,以及您为提交而保存的原因,即您的日志消息。这些都是供您或其他人在未来使用的:某天、可能明天、可能几个月或几年后,您可能会回顾您刚刚做出的承诺,并问问自己:我到底为什么要?答案应该在您的日志消息中。
因为提交将文件存储为快照,在时间上冻结,不变,并且永远存在(或只要提交本身存在),所以它们非常适合存档。以后的任何时候,您都可以回到过去,查看您当时保存的内容。你不能改变它:它是过去的,固定的,冻结在时间里的。即使Git也无法更改它,我们稍后将看到这一点。
为了查找提交,Git需要一个名称。这些名称是而不是分支机构名称!或者,更准确地说,您可以开始使用分支名称,但Git不需要这个名称。任何提交的真实名称都是其散列ID。每个提交的散列ID看起来是随机的,但实际上,它是提交的整个内容的加密校验和,对提交中的每一位数据都非常敏感:所有冻结的快照,以及您的姓名、时间戳和日志消息。这就是您或任何人不能更改提交的原因:更改任何内容都会更改散列ID,然后您得到的是一个新的、不同的提交。在提交之前,没有人知道新提交的散列ID是什么。此时,它将获得一个唯一的ID。没有人会将该ID用于任何其他提交!而且没有人可以更改Commit中的任何内容:Git将知道您是否尝试,因为ID不再匹配。2
这个拼图游戏的最后一两个关键部分。首先,在每个新提交中,Git将前一个提交的散列ID(真实名称)存储为元数据的一部分。也就是说,Git不仅保存您的姓名和时间等,还保存您用来进行这个新提交的提交的原始散列ID。Git将这个保存的散列ID称为提交的父。这意味着每个提交都指向它的父级提交,在一个向后的链中。
例如,假设我们在存储库中只有两个提交A
和B
。A
是第一个提交,所以它故意没有无父级--这是一个特例。但B
来自A
,因此B
指向A
:
A <-B
如果提取提交B
,执行一些工作,然后重新提交C
,则新提交会自动指向B
:
A <-B <-C
这意味着Git只需要知道最后提交的明显随机的散列ID。在本例中,提交C
。如果它的实际散列ID是cba9876...
或其他什么,Git可以使用它来查找C
的内容。这些内容包括COMMITB
的实际散列ID。然后,Git可以使用它来查找B
,其内容包括COMMITA
的实际散列ID。Git可以使用它查找A
,而A
没有父级,所以现在,最终,Git可以停止向后工作。
这个由分支名称标识的分支提示提交类似C
的过程在Git中至关重要。这就是历史存在的方式。Git存储库中的历史记录是提交,通过这些向后箭头连接。你从尽头开始,沿着历史一步一步地走,看看你可以沿着父箭头到达哪里。
当分支机构名称和其他类似名称出现时,最后一块拼图进入画面。让我们暂停一下,完成这里的脚注,然后深入到分支机构名称和图表绘制。
1Git实际上是从索引中创建快照,但我们在此不会深入讨论这些细节,而是要说明所拍摄的快照--针对该提交而在时间上永久冻结的--是当时在索引中的内容,这至少可能与您在工作树中看到的内容不同。
2Git实际上会在看起来方便或合适的时候检查这一点。自动检测Git存储库的意外损坏,例如,你试图在Dropbox中存储--Dropbox有时会在你(和Git)背后修改文件,Git会抓住它。不幸的是,很少有修复损坏的存储库的好方法--相反,Git倾向于依赖这样一种想法,即Git存储库可以在各地复制。你可能在其他地方有一份很好的复制品,所以你就把这一份完全扔掉。
分支名称查找提交散列ID
任何现有的存储库-嗯,除了一个完全空的、新鲜的、新的存储库,其中还没有提交--都有一些提交集。这些提交形成了我们刚才看到的回溯链,例如:
A <-B <-C
我们和Git需要某种方法来记录此链中最后一个提交的哈希ID。
Git实现这一点的方法是使用Git所称的引用或引用。裁判的形式有很多种,但最重要的三种是:
- 分支机构名称,如
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用户交换工作。为此,我们交换提交。它们的散列ID在所有Git Everywhere中是通用的,这是因为加密的校验和技巧。给定快照和元数据,每个Git Everywhere将计算相同的哈希ID。因此,如果我的存储库有A
到H
这样的提交-请记住,这些单个大写字母代表唯一的、难看的大散列ID-我连接到您的存储库和您有提交H
,您的存储库也必须具有与我相同的提交。
如果您没有有提交H
,我有一个您没有的提交。如果您有一些提交I
或J
,您有一个我没有的提交。无论哪种方式,我们的Git都可以交换散列ID来查看谁拥有什么。发送提交的人将发送它们,接收提交的人将接收它们,发送者将向接收者提供所需的任何新提交。
假设您正在接受我的新承诺。我有新的提交I
和J
,并且我的新提交J
有一个名称,它记住了它的散列ID。在我的存储库中,我有以下内容:
A--B--C--D--G--H <-- master
E
I--J <-- dev
出于任何原因,我没有您在dev
上提交的F
。相反,我在dev
上提交了I-J
,在(共享)提交之后E
。
这是远程跟踪名称的用武之地
您的Git接受我的提交I
和J
。我的提交I
具有父级E
。因此您的存储库现在具有以下内容:
A--B--C--D--G--H <-- master
E--F <-- dev
I--J <-- ???
您的Git存储库将使用什么名称来记住我的提交I
?最好不要使用dev
:如果您Git使dev
指向CommitI
,您将如何再次找到Commit?请记住,它有一个明显随机的哈希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,让它比较从dev
到达的提交集与来自origin/dev
的提交集,并使用Git使用的向后遍历方法。
从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
时稍微描述一下。
4Git有时将这称为跟踪而不是记住,但这是Git严重过度使用单词的另一个方面。我在短语远程跟踪中使用过它,但至少在这里它是用连字符连接的,并将该词用作形容词来修饰远程。
git push
与git fetch
不同
上面的过程是特定于git fetch
的,其中Git从origin
上的分支机构名称创建远程跟踪名称。当您让Git在origin
调用Git并将他们的承诺提交给您时,就会发生这种情况。
当然,您可以让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
以记住哪个分支名称在我们添加新提交时更新。
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
设置为指向提交K
。请注意,您没有设置xpt/newfeature/v4-json
或类似的设置。您让他们设置他们的分支!他们实际上还没有anewfeature/v4-json
,所以他们设置一个是很好的。他们就是这么做的!他们现在的存储库中有一个newfeature/v4-json
,指向提交K
。
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)上游设置,通常就是这样使用的。有关详细信息,请参阅Why do I need to do `--set-upstream` all the time?。
5您的Git可以告诉他们F
,但只有当您在此处说git push origin dev
时才会这样做。使用git push origin newfeature/v4-json
,无论是否使用-u
,根据需要告诉您的Git:告诉他们关于提交的K
、H
、G
、D
、C
、B
和/或A
。您的其他未共享提交是故意保密的。
6记住,由于散列ID的魔力,K
提交在每个GitEverywhere中是通用的。每个Git要么按其哈希IDK
,然后提交;要么根本没有K
,因此无关紧要。
(这不一定是100%保证的。假设K
的散列ID实际上是b5101f929789889c2e536d915698f58d5c5c6b7a
。这是Git存储库中Git本身提交的散列ID。如果您从未将您的Git存储库连接到用于Git的Git存储库,则您和他们使用相同的散列ID进行不同提交是正常的。但是,如果您确实曾经将您的Git存储库连接到用于Git的Git存储库,则会发生一些不太好的事情。简而言之,你没有得到Git的提交,他们也没有得到你的提交:这两个存储库目前根本不能组合。对于您和维护Git的人来说,这可能是完全没有问题的。但也请参阅How does the newly found SHA-1 collision affect Git?)
这篇关于如何创建GIT远程跟踪分支机构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!