如何创建git Remote-Tracking Branch

问题描述 投票:0回答:1

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 github git-branch git-remote
1个回答
2
投票

编辑以解决更新的(git branch -agit 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 -agit branch -vv输出显示origin/newfeature/v4-json不存在。

我可以通过创建单分支克隆来重现此行为的关键元素。使用git clone --depth=numbergit 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 clonegit 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.

下面。

What does all this mean? (Long)

它可能有助于回顾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称为提交的父级。这意味着每个提交指向其父提交,在一个向后看的链中。

例如,假设我们在存储库中只有两个提交ABA是第一次提交,所以它故意没有父母 - 这是一个特例。但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存储库在整个地方被复制的想法。你可能在其他地方有一个很好的副本,所以你只需完全抛出这个。


Branch names find commit hash IDs

任何现有的存储库 - 除了一个完全空的,新的,新的存储库之外的任何一个存在而没有提交它 - 都有一些提交。这些提交形成了我们刚刚看到的向后看的链,例如:

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会自动更新名称qa​​zxswpoi以保存新提交的哈希ID。因此,如果我们现在创建一个新提交,新提交master将指向D

C

但是Git会立即调整A--B--C <-- master \ D 指向master而不是C

D

由于A--B--C--D <-- master 指向D,我们仍然可以找到所有提交:我们从最后开始,并像往常一样倒退。 C现在是这个过程中的第二个提交而不是第一个提交。


3Branch名称必须包含提交对象哈希ID,而标记名称更灵活。我们这里不需要关心这个。由于远程跟踪名称的值是从分支名称复制的,因此远程跟踪名称也只包含提交哈希ID。


Branch names are private to each repository, but repositories talk to each other

Git是一个分布式版本控制系统。这意味着每个Git存储库都是一个独立的岛,它需要本地存储库所需的一切。如果有多个提交多个分支,则它们都在一个存储库中:

C

为了使Git真正有用,我们经常使用Git与其他Git用户交换工作。为此,我们交换了提交。由于加密校验和技巧,它们的哈希ID在所有Gits中都是通用的。给定快照和元数据,每个Git都会计算相同的哈希ID。因此,如果我的存储库通过这样的A--B--C--D--G--H <-- master \ E--F <-- dev 提交A - 请记住这些单个大写字母代表唯一的,大丑陋的哈希ID - 我连接到您的存储库并且您已提交H,您的存储库也必须具有相同的提交矿。

如果你没有提交H,我有一个你没有的提交。如果你有一些提交HI,你有一个我没有的提交。无论哪种方式,我们的Gits都可以只交换哈希ID来查看谁拥有什么。发送提交的任何人都将发送它们,接收提交的任何人都将收到它们,并且发送方将向接收方提供所需的任何新提交。

假设您正在接受我的新提交。我有新的提交JI,我的新提交J有一个记住其哈希ID的名称。在我的存储库中,我有这个:

J

无论出于何种原因,我没有你在A--B--C--D--G--H <-- master \ E \ I--J <-- dev 上提交的F。相反,在(共享)提交dev之后,我在我的I-J上提交了dev

This is where remote-tracking names come in

你的Git接受我的提交EI。我的承诺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)。

您的存储库中的名称Horigin/master是(您的)远程跟踪名称,记住我的origin/dev和我的master.4此外,假设您现在查询您的Git,要求它比较devdev可用的提交集,在Git使用的普通的后退方法中。

origin/dev开始,你将访问的提交是dev,然后是F,然后是E,依此类推回D。从A开始,你将访问的提交是origin/dev,然后是J,然后是I,然后是E,依此类推回D。哪些提交是独一无二的步行?你从Adev无法到达多少次提交,反之亦然?

算出那些,然后比较你的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他们也有HG以及之前的一切,所以你只需要发送它们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:根据需要告诉他们有关-uKHGDC和/或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

© www.soinside.com 2019 - 2024. All rights reserved.