【问题标题】:How to create git Remote-Tracking Branch如何创建 git 远程跟踪分支
【发布时间】:2019-08-14 01:41:47
【问题描述】:

They said就是这么简单

您可以通过使用带有“git push”的 -u 标志来告诉 Git 跟踪新创建的远程分支。

但它从未对我有用。

如何创建 git Remote-Tracking 分支,使用哪个

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 也没有从 remote 更新我的 local 分支:

$ 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 github git-branch git-remote


    【解决方案1】:

    编辑以更新地址(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=<em>number</em>git clone --single-branch 将产生这样的克隆。这样做的副作用是你的 Git 永远不会为任何分支创建任何远程跟踪名称​​除了你告诉 Git 你关心的那个分支。如果这问题,解决方法是将克隆转换为普通(多分支)克隆。 (如果您使用--depth 创建单分支方面,unshallow 克隆可能也是明智之举。)

    查看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=<em>number</em> --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 相当奇特的术语可能会有所帮助。特别是,您使用的短语——remote-tracking branch——在我看来是一个不好的术语,具有误导性。它一个Git术语,所以我们应该理解人们在使用它时的意思,但它是一个术语,意味着人们误用如果您对某人的用法感到困惑,则可能值得退后一步重新考虑这些事情。

    首先,让我们注意,Git 确实是关于 commits。提交是 Git 的 raison d'être;没有提交,我们根本不会使用 Git。那么让我们看看什么是提交。

    每个提交包含个文件,但它不仅仅是一组文件。它是您拍摄快照时所有文件的快照,1但它也有一些元数据:信息关于存储的数据。最明显的是您在git log 输出中看到的内容:您的姓名和电子邮件地址,计算机对您提交提交的日期和时间的看法,以及您保存的原因用于提交,即您的日志消息。这些都是为你或其他人在未来使用的:有一天,也许明天,也许几个月或几年后,你可能会回顾你刚刚做出的这个承诺,并问自己:到底为什么我做了那个吗?答案应该在您的日志消息中。

    因为提交将文件存储为快照、及时冻结、不可变并且永远存在(或只要提交本身存在)——它们非常适合存档。在未来的任何时候,您都可以回到过去并确切地查看您当时保存的内容。你无法改变它:它是过去的,固定的,被时间冻结了。甚至 Git 也无法改变它,我们稍后会看到。

    为了找到一个提交,Git 需要一个名称。这些名称​​不是分支名称!或者,更准确地说,您可以开始使用分支名称,但这不是 Git 需要的名称。任何提交的真实名称都是它的 hash ID。每个提交的哈希 ID 似乎是随机的,但实际上,它是提交的全部内容的加密校验和,对提交的每一位数据 in 非常敏感:所有冻结的快照,还有您的姓名和时间戳以及您的日志消息。这就是为什么您或任何人都无法更改提交:更改任何内容都会更改哈希 ID,然后您将拥有一个新的和不同的提交。在提交之前,没有人知道 new 提交的哈希 ID 是什么。那时,它会获得一个唯一的 ID。没有人会将该 ID 用于任何其他提交!并且没有人可以更改提交中的任何内容:如果您尝试,Git 会知道,因为 ID 将不再匹配。2

    这个特殊的拼图游戏有最后一两个关键部分。首先是在每个 new 提交中,Git 将 previous 提交的哈希 ID(真实名称)存储为元数据的一部分。也就是说,Git 不仅会保存您的姓名和时间等信息,还会保存您用于 进行此新提交的提交的原始哈希 ID。 Git 将此保存的哈希 ID 称为提交的 parent。这意味着每个提交指向它的父提交,在一个向后看的链中。

    例如,假设我们在存储库中只有两个提交 ABA 是第一次提交,所以它故意有 no 父级——这是一个特例。但是B是由A组成的,所以B又指向A

    A <-B
    

    如果你提取提交B,做一些工作,并做出一个新的提交C,新的提交会自动指向B

    A <-B <-C
    

    this 的意思是 Git 只需要知道 last 提交的明显随机哈希 ID。在这种情况下,提交C。如果它的实际哈希 ID 是 cba9876... 或其他什么,Git 可以使用它来查找 Ccontents。这些内容包括提交B 的实际哈希ID。 Git 然后可以使用它来查找B,其内容包括提交A 的实际哈希ID。 Git 可以使用它来查找A,而A 没有父级,所以现在,Git 终于可以停止向后工作了。

    branch tip 提交(如C)开始向后工作的过程(由 branch name 标识)在 Git 中至关重要。这就是历史存在的方式。 Git 存储库中的历史提交,由这些向后指向的箭头连接。您从头开始,一次一个提交,遍历历史,看看您可以按照父箭头到达的位置。

    这是最后一块拼图进入图片的地方,分支名称和其他此类名称出现。让我们暂停一下,结束这里的脚注,然后深入研究分支名称和绘图。


    1Git 实际上是从 index 制作快照,但我们不会在这里详细介绍这些细节,只是说快照的内容——及时冻结,永远,对于那个提交 - 是当时 index 中的任何内容,这至少可能与您在 work-tree 中看到的内容不同你的工作。

    2Git 实际上会检查这一点,只要它看起来方便或合适。这会自动检测 Git 存储库的意外损坏,例如当您尝试在 Dropbox 中存储时发生 - Dropbox 有时会在您(和 Git)背后修改文件,而 Git 会捕获它。不幸的是,几乎没有修复损坏的存储库的好方法——相反,Git 倾向于依赖于 Git 存储库被复制到各处的想法。你可能在其他地方有一份不错的副本,所以你把这一份完全扔掉。


    分支名称查找提交哈希 ID

    任何现有的存储库——嗯,除了一个完全空的、新鲜的、新的、no 提交的存储库之外的任何存储库——都有一些提交。这些提交形成了我们刚刚看到的后向链,例如:

    A <-B <-C
    

    我们——和 Git——需要某种方式来记录这个链中last提交的哈希 ID。

    Git 实现这一点的方式是使用 Git 所称的 referencesrefs。 refs 的形式有很多种,但三巨头是:

    • 分支名称,例如master
    • 远程跟踪名称,例如origin/master。 (Git 称这些 remote-tracking 分支名称remote-tracking 分支,我认为这是一个坏名字;我已改用 remote-tracking 名称,我认为这更难出错。)
    • 标签名称,例如v1.3

    它们实际上都是由相同的底层技术实现的,但我们在这里将它们视为单独的名称形式。 分支名称有一个特殊的属性; 所有其他名字都没有这个属性。

    其中一个名称的含义非常简单:它只是 Git 对象的实际原始哈希 ID,通常是一次提交。3 所以像 master 这样的分支名称​​点到分支中的最后次提交——在此图中提交C

    A--B--C   <-- master
    

    请注意,连接提交的箭头来自子节点并指向(不可变的)父节点,从而为我们提供了这种向后遍历的方法。我们不必费心把它们画进去。但是,branch 名称中出现的箭头,change

    当我们向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 中都是通用的。给定快照和元数据,每个 Git 将计算相同的哈希 ID。因此,如果我的存储库有这样的提交 AH - 请记住,这些单个大写字母代表唯一的、大而丑陋的哈希 ID - 我连接到 您的 存储库和 有提交H,你的仓库也必须有和我一样的提交。

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

    假设您正在接受我的新提交。我有新的提交 IJ,我的新提交 J 有一个 name 可以记住它的哈希 ID。在 my 存储库中,我有这个:

    A--B--C--D--G--H   <-- master
              \
               E
                \
                 I--J   <-- dev
    

    无论出于何种原因,我没有提交您在dev 上的F。相反,在(共享)提交E 之后,我在dev 上提交了I-J

    这就是远程跟踪名称的用武之地

    你的 Git 接受我的提交 IJ。我的提交I 有父E。所以你的仓库现在有了这个:

    A--B--C--D--G--H   <-- master
              \
               E--F   <-- dev
                \
                 I--J   <-- ???
    

    你的 Git 存储库将使用什么 name 来记住我的提交 I?最好不要使用dev:如果你的Git让你的dev指向commit I,你怎么会再次找到commit F?请记住,它有一个明显随机的哈希 ID。你永远无法猜测它。

    所以,您的 Git 所做的是使用 远程跟踪名称 来记住 my 分支。你的 Git 会这样做:

    A--B--C--D--G--H   <-- master, origin/master
              \
               E--F   <-- dev
                \
                 I--J   <-- origin/dev
    

    (假设我的master 指向提交H)。

    您的存储库中的名称origin/masterorigin/dev 是(您的)远程跟踪名称,记住我的master 和我的dev。4 此外,假设您现在查询您的 Git,要求它比较从 dev 与来自 origin/dev 的提交集,在 Git 使用的普通 walk-backwards 方法中。

    dev 开始,您将访问的提交是F,然后是E,然后是D,以此类推回到A。从origin/dev 开始,您将访问的提交是J,然后是I,然后是E,然后是D,以此类推回到A哪些提交对于哪个 walk 是唯一的?您从 dev 获得了多少从 origin/dev 无法获得的提交,反之亦然?

    算出这些,然后与你的 Git 告诉你的比较:

    # Your branch and 'origin/dev' have diverged,
    # and have 1 and 2 different commits each, respectively.
    

    我们的拼图游戏中实际上还缺少另一部分,我们将在最后一部分讨论下面的git push 时简单描述一下。


    4Git 有时称其为 tracking 而不是 remembering,但这是 Git 严重过度使用单词的另一个地方。我在短语remote-tracking中使用了它,但至少在这里它是连字符的,并使用这个词作为修饰remote的形容词。


    git pushgit fetch 不同

    上述过程中,您的 Git 从位于 origin 的 Git 上找到的分支名称创建远程跟踪名称,特定于 git fetch。当你的 Git 调用 origin 的 Git 并将 他们的 提交给 时,就会发生这种情况。

    当然,您可以让您的 Git 通过 origin 调用他们的 Git 并 send 提交。这就是git push 操作,非常相似。你的 Git 告诉他们的 Git 你有哪些提交,而他们没有。让我们画一些。我们将从这个开始:

    A--B--C--D--G--H   <-- master, origin/master
              \
               E--F   <-- dev
                \
                 I--J   <-- origin/dev
    

    现在我们将运行git checkout mastergit 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 以记住在我们添加新提交时哪个分支名称会更新。

    现在我们将创建一个新的提交。它可能不止一个,甚至none,但让我们创建一个来说明。新的提交获得了一些丑陋的哈希 ID,但我们在这里将其称为 K

                     K   <-- newfeature/v4-json (HEAD)
                    /
    A--B--C--D--G--H   <-- master, origin/master
              \
               E--F   <-- dev
                \
                 I--J   <-- origin/dev
    

    现在我们将让您的 Git 调用 Git,地址为 origin,使用:

    git push -u origin newfeature/v4-json
    

    你的 Git 拨通他们的 Git 并宣布你有提交 KH5 他们没有 K 但他们有 H 所以他们有你的Git 通过提交K 发送其快照和元数据。你的 Git 可以知道,因为他们有 H,所以他们也有 GD 以及之前的所有内容,所以你只需要向他们发送 K 及其内容。

    然后,最后,你的 Git 会问他们:现在,如果没问题,请设置你的名字 newfeature/v4-json 指向提交 K 请注意,你没有他们设置xpt/newfeature/v4-json 或类似的东西。你让他们设置他们的分支!他们实际上还没有newfeature/v4-json,所以他们可以设置一个。所以他们做到了!他们现在在他们的存储库中有一个newfeature/v4-json,指向提交K

    你的 Git 现在创建你的远程跟踪名称origin/newfeature/v4-json,指向提交K,以记住他们的newfeature/v4-json , 指向提交 K.6 但这只是意味着您的图表中有一个额外的 name,如下所示:

                     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 设置 upstream 设置。您的每个分支都可以有 一个 (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:告诉他们提交KHGDCB和/或 A 根据需要。您的其他未共享提交故意保持私密。

    6请记住,由于哈希 ID 的魔力,提交K每个 Git 无处不在 中是通用的。 每个 Git 要么有K,通过它的哈希ID,然后它是那个 提交;或者根本没有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 branch -agit branch -vv 输出中 缺少它。这表明不知何故,一些更新无声无息地失败了。 git push -u 显示它正在创建,但 git branch 输出显示它实际上并没有被创建。
    • 天啊,天啊 torek,你是我的英雄,拯救了我一年的头痛。是的,我用浅克隆做了我的本地克隆,没想到,多年前的操作对我今天的工作产生了深远的影响。谢谢一百万!
    • 我得出的结论是--shallow 是阴险的。如果它不暗示--single-branch...,它会不那么糟糕,甚至几乎无害
    猜你喜欢
    • 2015-02-25
    • 2014-08-22
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 2011-02-05
    • 2016-04-04
    相关资源
    最近更新 更多