They said就像它一样简单
您只需将-u标志与“git push”一起使用即可告诉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: [email protected]:go-easygen/easygen.git
Push URL: [email protected]: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 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
,这是我的首选方法)。另见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似乎是随机的,但事实上,它是提交的整个内容的加密校验和,对该提交中的每一位数据都非常敏感:所有冻结的快照,以及您的名称和时间-stamp和您的日志消息。这就是为什么你或任何人不能改变提交的原因:改变任何东西都会改变哈希ID,然后你拥有的是一个新的不同的提交。在创建之前,没有人知道新提交的哈希ID是什么。那时,它获得一个唯一的ID。没有人会将该ID用于任何其他提交!并且没有人可以在提交中更改任何内容:Git会知道您是否尝试,因为ID将不再匹配
这个特殊的拼图游戏有一两个最后的关键部分。第一个是在每次新提交中,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
的内容。这些内容包括commit B
的实际哈希ID。然后Git可以使用它来查找B
,其内容包括commit A
的实际哈希ID。 Git可以使用它来查找A
,而A
没有父级,所以现在,最后,Git可以停止向后工作。
这个从分支提示向后工作的过程,如C
,由分支名称标识,在Git中至关重要。这就是历史的存在。 Git存储库中的历史记录是提交,由这些向后指向的箭头连接。您从最后开始步行,一次提交一次,通过历史记录,按照父箭头查看您可以到达的位置。
当分支名称和其他此类名称出现时,这是最后一个拼图块进入图片的地方。让我们暂停并在这里完成脚注,然后深入分支名称和图形绘制。
1Git实际上是从索引创建快照,但是我们不会在这里详细介绍这些细节,除了说什么得到快照 - 及时冻结 - 对于那个提交 - 是当时索引中的任何内容,至少可能与您在工作中看到的工作树有所不同。
只要看起来方便或合适,2Git实际上会检查这个。这会自动检测到Git存储库的意外损坏,就像(例如)你试图在Dropbox-Dropbox中存储一样,有时会修改你(和Git)后面的文件,而Git会抓住它。不幸的是,很少有一种很好的方法来修复损坏的存储库 - 相反,Git倾向于依赖于Git存储库在整个地方被复制的想法。你可能在其他地方有一个很好的副本,所以你只需完全抛出这个。
任何现有的存储库 - 除了一个完全空的,新的,新的存储库之外的任何一个存在而没有提交它 - 都有一些提交。这些提交形成了我们刚刚看到的向后看的链,例如:
A <-B <-C
我们和Git需要一些方法来记录这个链中最后一次提交的哈希ID。
Git实现这一点的方式是Git调用引用或引用的方式。有许多形式的裁判,但三巨头是:
master
。origin/master
。 (Git称这些远程跟踪分支名称或远程跟踪分支,我认为这是一个坏名称;我已经切换到使用远程跟踪名称,我认为这更难出错。)v1.3
。它们实际上都是由相同的底层技术实现的,但我们在这里只是将它们视为单独的名称形式。分支名称具有特殊属性;所有其他名字都缺少这个属性。
其中一个名称的内容非常简单:它只是Git对象的实际原始哈希ID,通常是commit.3所以像master
这样的分支名称指向此绘图中branch-commit C
中的最后一次提交:
A--B--C <-- master
请注意,连接提交的箭头从子节点出来并指向(不可变)父节点,为我们提供了这种向后遍历方法。我们不必费心去绘制它们。但是,分支名称中出现的箭头会发生变化。
当我们向master
添加新提交时,Git会自动更新名称qazxswpoi以保存新提交的哈希ID。因此,如果我们现在创建一个新提交,新提交master
将指向D
:
C
但是Git会立即调整A--B--C <-- master
\
D
指向master
而不是C
:
D
由于A--B--C--D <-- master
指向D
,我们仍然可以找到所有提交:我们从最后开始,并像往常一样倒退。 C
现在是这个过程中的第二个提交而不是第一个提交。
3Branch名称必须包含提交对象哈希ID,而标记名称更灵活。我们这里不需要关心这个。由于远程跟踪名称的值是从分支名称复制的,因此远程跟踪名称也只包含提交哈希ID。
Git是一个分布式版本控制系统。这意味着每个Git存储库都是一个独立的岛,它需要本地存储库所需的一切。如果有多个提交多个分支,则它们都在一个存储库中:
C
为了使Git真正有用,我们经常使用Git与其他Git用户交换工作。为此,我们交换了提交。由于加密校验和技巧,它们的哈希ID在所有Gits中都是通用的。给定快照和元数据,每个Git都会计算相同的哈希ID。因此,如果我的存储库通过这样的A--B--C--D--G--H <-- master
\
E--F <-- dev
提交A
- 请记住这些单个大写字母代表唯一的,大丑陋的哈希ID - 我连接到您的存储库并且您已提交H
,您的存储库也必须具有相同的提交矿。
如果你没有提交H
,我有一个你没有的提交。如果你有一些提交H
或I
,你有一个我没有的提交。无论哪种方式,我们的Gits都可以只交换哈希ID来查看谁拥有什么。发送提交的任何人都将发送它们,接收提交的任何人都将收到它们,并且发送方将向接收方提供所需的任何新提交。
假设您正在接受我的新提交。我有新的提交J
和I
,我的新提交J
有一个记住其哈希ID的名称。在我的存储库中,我有这个:
J
无论出于何种原因,我没有你在A--B--C--D--G--H <-- master
\
E
\
I--J <-- dev
上提交的F
。相反,在(共享)提交dev
之后,我在我的I-J
上提交了dev
。
你的Git接受我的提交E
和I
。我的承诺J
有父母I
。所以你的存储库现在有这个:
E
你的Git存储库用什么名字来记住我的提交A--B--C--D--G--H <-- master
\
E--F <-- dev
\
I--J <-- ???
?最好不要使用I
:如果你的Git让你的dev
指向承诺dev
,你怎么会再次找到提交I
?请记住,它有一个明显随机的哈希ID。你永远无法猜到它。
那么,你的Git所做的就是使用远程跟踪名称来记住我的分支。你的Git这样做:
F
(假设我的A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
指向承诺master
)。
您的存储库中的名称H
和origin/master
是(您的)远程跟踪名称,记住我的origin/dev
和我的master
.4此外,假设您现在查询您的Git,要求它比较dev
与dev
可用的提交集,在Git使用的普通的后退方法中。
从origin/dev
开始,你将访问的提交是dev
,然后是F
,然后是E
,依此类推回D
。从A
开始,你将访问的提交是origin/dev
,然后是J
,然后是I
,然后是E
,依此类推回D
。哪些提交是独一无二的步行?你从A
到dev
无法到达多少次提交,反之亦然?
算出那些,然后比较你的Git告诉你的:
origin/dev
在我们的拼图游戏中实际上还有另一个缺失的部分,我们在下一节谈论# Your branch and 'origin/dev' have diverged,
# and have 1 and 2 different commits each, respectively.
时,我们将在最后一节中略微描述。
4Git有时称这种跟踪而不是记忆,但这是另一个地方Git严重过度使用一个单词。我已经在短语远程跟踪中使用了它,但至少在这里它是连字符并使用该词作为修改远程的形容词。
git push
is different from git push
上面的过程,你的Git在git fetch
的Git上找到的分支名称创建了远程跟踪名称,这个名称特定于origin
。当你让你的Git在git fetch
上调用Git并将他们的提交带给你时,就会发生这种情况。
当然,你可以让你的Git在origin
调用他们的Git并发送提交。这是origin
操作,它非常相似。你的Git告诉他们的Git你有的提交,他们没有。我们来画一些。我们将从这开始:
git push
现在我们将运行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
以记住在添加新提交时哪个分支名称得到更新。
现在我们将创建一个新提交。它可能不止一个,甚至没有,但让我们创建一个用于说明。新的提交获得了一些很难看的哈希ID,但我们在这里称之为newfeature/v4-json
:
K
现在我们将让你的Git在 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并宣布你提交了git push -u origin newfeature/v4-json
和K
.5他们没有H
但他们确实有K
所以他们让你的Git发送提交H
及其快照和元数据。你的Git可以说,因为他们有K
他们也有H
和G
以及之前的一切,所以你只需要发送它们D
及其内容。
然后,最后,你的Git问他们:请,现在,如果没关系,请设置你的名字K
指向提交newfeature/v4-json
。请注意,您没有设置K
或类似的东西。你有他们设置他们的分支!他们实际上还没有xpt/newfeature/v4-json
,所以他们设置一个就可以了。所以他们这样做!他们现在在他们的存储库中有一个newfeature/v4-json
,指向提交newfeature/v4-json
。
你的Git现在创建你的远程跟踪名称K
,指向提交origin/newfeature/v4-json
,记住他们的K
,指向提交newfeature/v4-json
.6但这只是意味着你的图形中有一个额外的名字,如下所示:
K
由于 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
选项,您的Git立即运行:
-u
这将设置分支git branch --set-upstream-to=origin/newfeature/v4-json newfeature/v4-json
的上游设置。您的每个分支都可以有一(1)个上游设置,以这种方式使用它是非常典型的。有关更多信息,请参阅newfeature/v4-json
。
5你的Git可以告诉他们关于Why do I need to do `--set-upstream` all the time?,但只有你在这里说过F
才会有。使用git push origin dev
,有或没有git push origin newfeature/v4-json
,你告诉你的Git:根据需要告诉他们有关-u
,K
,H
,G
,D
,C
和/或B
的提交。您的其他非共享提交仍然是私有的,故意。
6请记住,由于哈希ID的神奇之处,提交A
在每个Git中都是通用的。每个Git都有K
,它的哈希ID,然后就是那个提交;或根本没有K
,所以没关系。
(这不一定是100%保证。假设K
的哈希ID实际上是K
。这是Git本身Git存储库中提交的哈希ID。如果你从未将你的Git存储库连接到Git的Git存储库,那就是好吧,你和他们有不同的提交具有相同的哈希ID。但是如果你曾经将Git存储库连接到Git的Git存储库,那么一些不那么好的事情就会发生。简短的版本就是你没有得到Git的提交,他们只是没有得到你的:这两个存储库根本无法在这一点上合并。对于你和维护Git的人来说,这可能完全没问题。但另见b5101f929789889c2e536d915698f58d5c5c6b7a
)