如何将远程仓库分支添加到本地仓库

Posted

技术标签:

【中文标题】如何将远程仓库分支添加到本地仓库【英文标题】:How to get remote repo branch added to local repo 【发布时间】:2021-04-07 15:49:49 【问题描述】:

新建 - 通过创建文件夹并运行命令 git init 简而言之,从顶部创建一个本地 git 存储库。

我这里有一个本地 git 存储库(新创建的),带有 2 个分支。现在这些分支只是我创建的虚拟分支,对它来说没有什么重要的。

$ git branch
* repo2-branch1
  repo2-branch2

我这里还有一个来自 Github 的远程存储库(private),其中有一个分支 “TLA1”,现在请记住我上面提到的新创建的本地存储库以及这两个分支?我想要做的是添加这个“TLA1”分支作为我提到的我新创建的本地存储库中repo2-branch1repo2-branch2的分支之一。

假设添加了 "TLA1" 分支。所以当我输入git branch 时,我希望它是这样的。

$ git branch
* repo2-branch1
  repo2-branch2
  TLA1

当然,当我在切换到 "TLA1" 时键入 git log 时,我也会有远程存储库中的提交,正如您在图像中看到的那样,对我来说,这些提交非常重要。

我尝试过的解决方案:

我做了很多研究,发现this,我认为这已经是它,因为它与我的目标相似。但是当我尝试它时,我得到了一个错误。

$ git checkout -b TLA1 origin/TLA1
fatal: 'origin/TLA1' is not a commit and a branch 'TLA1' cannot be created from it

我也没有尝试过这个,因为这个东西可能会对我的远程仓库git reset --hard <remote>/<branch_name> 做一些事情,而且它似乎不是我找到的解决方案。

有什么解决办法吗?我真的很想在我新创建的存储库中拥有这个分支。

【问题讨论】:

git checkout TLA1?当您说“新创建的”时,您的意思是克隆吗?它与那个遥控器有任何联系吗? git branch -lagit remote -v 显示什么? 你好!我所说的newly created 的意思是我刚刚创建了一个新文件夹并在那里有一个git init 那么,如果您已经有遥控器,为什么要这样做?您是否已将该遥控器添加到本地存储库中? 正如我在问题中提到的,我从顶部开始创建一个新存储库,然后我只想将“TLA1”分支作为新创建的存储库的一部分以及我创建的虚拟分支. 我只想获取“TLA1”分支并将其带到我刚刚创建的本地仓库...所以当我输入 git branch 时,我会看到 3 个分支,当然是“现在添加了 TLA1”,当然,当我输入 git log 时,当我切换到“TLA1”时,提交也必须在那里,因为这些提交确实很重要。 【参考方案1】:

您需要先告诉 Git 跟踪远程存储库。所以你必须这样做

git remote add origin <url>

接下来你可以告诉 git 只从远程获取那个分支

git fetch origin TLA1

然后就可以切换到分支了

git checkout TLA1

【讨论】:

你好@Karthnik!谢谢!我接受你的回答,因为对我来说,这是我所看到的最准确的答案,我一生都在使用 git 我一直在做 git fetch ,因为要立即获得提交和元数据 merge 他们一个特定的分支,但我不知道一旦您在该特定分支上获取元数据,您实际上可以直接使用它来直接checkout。谢谢!【参考方案2】:

将远程添加到本地存储库,然后从中获取。

git remote add REMOTE_NAME REMOTE_URL
git fetch REMOTE_NAME
git checkout -b branch_name REMOTE_NAME/branch_name

最后一个命令从远程引用创建一个本地分支。

那么 git branch 应该会显示:

git branch

LOCAL1
LOCAL2
branch_name

【讨论】:

你好@Ouss4,非常感谢!您的解决方案与@Karthik 相同,但老实说,就我而言,不需要执行git fetch REMOTE_NAME。相反,更好的方法是 git fetch REMOTE_NAME BRANCH_NAME ,因为我只关注一个分支。但你的答案是 100% 好!请保留它,因为其他可能有类似问题的人可能会找到您的解决方案作为他们的解决方案。谢谢:D 谢谢!这也有效,但我的仓库中有很多分支,我认为没有必要获取整个仓库,但我仍然相信这个答案与可能看到它的其他人相关,所以感谢添加这个。【参考方案3】:

TL;DR

您需要先运行git fetch origin,然后才能运行git checkout TLA1

你走在正确的轨道上,但有很多东西要知道——还有很多人们发现的错误的东西,你应该小心。

要忘却的事情

在熟练使用 Git 之前,您需要un-学习一些东西。这些虚假声明如下:

“分支很重要”:这没有错,但这也不对。第一个问题是 branch 这个词,它在 Git 中基本上是模棱两可的。如果我们坚持使用两个词的短语 branch name,我们会得到更有用的东西。分支名称很重要,但仅限于人类。 Git 使用它们来帮助我们找到提交;真正重要的是提交。

“远程分支”:这个两个词的短语,如果有的话,比“分支”这个词本身更糟糕。人们用它来表示至少三种不同的东西。让我们也避免使用这个短语。 Git 文档使用术语remote-tracking branchremote-tracking branch name,它们是git branch -r 列出的名称。这句话还不错,但是里面的branch这个词是没有意义的。让我们称之为远程跟踪名称

要学习的东西

在 Git 中重要的是 提交。了解这些关于提交的事情:

每一个都有一个唯一的哈希 ID。某个提交的哈希 ID 表示 that 提交。没有其他提交(在任何地方,在 any Git 存储库中)将具有 that 哈希 ID。 那个提交——在任何地方,在any Git 存储库中——将有那个哈希ID。

提交是在不同的 Git 克隆之间共享的内容。分支名称不共享。您的 Git 克隆具有 您的 分支名称,而其他一些克隆具有 分支名称。您可能想要使用相同的名称,以保持事情的正确性,但这取决于您(尽管 Git 会在这里提供帮助,因为这是很常见的事情)。

每个提交由两部分组成:

提交的主要数据是所有文件的快照。这些文件一直被冻结:它们以压缩、只读、仅 Git 和去重的形式存储。重复数据删除处理的事实是,大多数时候,大多数新提交大多包含与上一次提交相同的文件。存储在提交中的文件被冻结,甚至不能被非 Git 程序读取(更不用说写入)这一事实当然是个问题。

提交的另一部分是它的元数据。这包括提交人的姓名、他们的电子邮件地址以及他们提交提交的日期和时间戳何时。所有这些东西也是只读的。对于 Git 本身而言,至关重要的是,Git 会在此元数据中添加一些 previous 提交的哈希 ID。我们称这些为提交的父母

提交表单链;分支名称帮助我们(和 Git)找到提交

鉴于我们有一些简单的提交序列:

... <-F <-G <-H

这里的每个字母代表一个实际的 Git 哈希 ID,我们最终得到一个线性的提交链,以提交 H 结束。如果我们知道H 的实际哈希ID,我们可以让Git 提取这个提交(见下文)。或者,我们可以让 Git 读取 H 的元数据并向我们显示提交的人......或者使用它来查找 H 的父提交 G 的实际哈希 ID。

由于GH 都持有快照,我们可以让Git 比较这两个快照。所有匹配的文件都是无趣的,因为它们匹配。任何 匹配的文件都更有趣,我们可以让 Git 找出其中的 不同 并向我们展示不同之处。这样,我们就可以看到我们改变了。 Git 不存储 更改:它只存储快照。但是我们可以看到快照随着的变化,因为提交有父级。

我们也可以让 Git 返回到 G 并使用它来查找 F,从而将 G 视为更改。从那里,我们可以回到F,并使用它来查找更早的提交,等等。但要做到这一切,我们需要链中 last 提交的实际哈希 ID。这就是分支名称的来源:像repo-branch1 这样的分支名称只是存储一些哈希ID。根据定义,存储在名称中的哈希 ID 是分支中的 last 提交。 Git 将从那里开始并向后工作。 之后是否有后续提交也没关系:

...--E--F   <-- br1
         \
          G--H   <-- br2

这里Hbr2 中的last 提交(例如在FG 之后),而提交F最后br1 中提交。通过F 向上提交在两个分支,但br1 开始或结束(取决于你如何看待它)在F 并向后工作,而br2 结束于H 并向后工作。

提取的提交

因为提交是只读的,我们实际上不能直接处理或使用它们。我们必须选择一些提交并将其设为当前提交。当我们这样做时,Git 提取所有与该提交相关的文件到一个工作区,Git 称之为 working treework-tree。这些是您可以查看和使用的文件。它们是普通的日常计算机文件,您计算机上的每个程序都可以使用。但它们实际上并不在 Git 中。

我们跑:

git checkout br2

(或 Git 2.23 或更高版本中的 git switch br2)。 Git 使用名称 br2 来查找该分支的最后一个(或 tip)提交(注意模棱两可的词,在这种情况下表示某些以 H 结尾的提交)。 Git 然后从该提交中提取文件,以便我们可以查看和使用它们,并将该提交设为当前提交,同时将该分支名称设为当前分支。我喜欢这样画:

...--E--F   <-- br1
         \
          G--H   <-- br2 (HEAD)

特殊名称HEAD附加到一个分支名称。这就是“在分支上”的含义:名称HEAD 定位到分支名称br2。分支名称本身定位提交,H,这是 Git 提取的那个。

如果我们进行 new 提交,Git 会打包一个快照,添加元数据,将新提交的 parent 设置为 current 提交H,并使用所有这些来写出新的提交。这为提交分配了新的、大而丑陋的随机(但实际上根本不是随机)哈希 ID,我将其称为 I。由于I 的父级是H,所以I 指向H。然后 Git 简单地将 I 的哈希 ID 写入当前 namebr2,给出:

...--E--F   <-- br1
         \
          G--H--I   <-- br2 (HEAD)

因此,分支名称的特殊之处在于它在我们进行新提交时会自动移动以指向新提交。 Git 通过将名称 HEAD 附加到分支名称来完成此操作。

Git 有其他名称(例如标记名称和远程跟踪名称) 指向提交(通过存储提交哈希 ID),但您不能将 HEAD 附加到它们。

远程跟踪名称和git fetch

远程跟踪名称的形式类似于 origin/TLA1:它们以 远程名称 开头,例如 origin。远程名称是您使用git remote add时使用的名称; origin 只是第一个标准。如果您使用git clone 为您运行git initgit remote add 等等,git clone 将使用origin 作为标准的第一个远程名称。 注意:您没有使用 git clone,因此当您运行 git remote add 时,名称将由您决定。

如上所述,您不能将HEAD 附加到远程跟踪名称。此外,您通常不会自己创建这些名称。你可以使用git branch -r 列出你现在拥有的那些,但是如果不创建它们,你如何获得它们?

最后一个问题的答案是git fetch 命令创建了它们。 fetch 命令非常复杂(有好有坏),我肯定不会在这里详细介绍,但我们可以相对简单地描述它:git fetch 让你的 Git 调用其他 Git 并获取来自它的东西:

首先,您的 Git 列出了所有分支名称、标签名称和其他此类名称。这些带有哈希 ID — 主要是提交哈希 ID,尽管标签名称有时会稍微复杂一些。

然后您的 Git 会通过这些名称和哈希 ID 进行选择。您的 Git 可以判断您是否有提交,因为每个 Git 都使用 相同的随机外观但非随机哈希 ID 来处理相同的提交。因此,您的 Git 会立即知道您是否有 他们的 分支的提示提交。

如果你不这样做,你的 Git 会向他们的 Git 询问他们的提交。他们也提供提交的父母,你的 Git 会检查你是否有 那些 提交。通过这种拥有/想要的序列(通过一些重要的优化,避免每次都必须列出每个哈希 ID),你的 Git 可以确定他们有哪些提交,你没有,你需要,并要求他们.

他们打包所有这些提交并将它们发送给您。这里的细节可能会有很大差异,但在通常情况下,您会看到“计数”和“压缩”等,然后您的 Git 会收到一个包含提交和其他内部 Git 对象的包。然后,您的 Git 将所有内容保存在您的存储库中。

您现在拥有了之前的所有提交,加上任何您没有的提交(除非您的 Git 不想要它们,例如单分支克隆)。

最后,您的 Git 现在创建或更新您的远程跟踪名称。对于他们拥有的每个 branch 名称,您的 Git 会为您的存储库创建或更新相应的远程跟踪名称。

这意味着你永远不会直接获得他们的分支名称。您获取他们的分支名称并将它们更改 为您的远程跟踪名称。这充当您的 Git 的分支名称的记忆。它们由git fetch 创建或更新。在您运行git fetch 之前,您不会拥有origin/TLA1

结论

重要的是提交。分支名称和其他名称可以帮助您(和 Git)find 提交。

您可以通过运行git fetch 获得远程跟踪名称。你告诉git fetch 呼叫哪个遥控器。您的 Git 会调用该遥控器并查看其分支并获取其提交,除非您已经拥有它们。然后您的 Git 会根据需要更新或创建远程跟踪名称。 (旁注:除非您告诉它,否则您的 Git 不会在此处删除“死”名称,因此一旦他们删除了某些分支名称,您将留下陈旧的远程跟踪名称。)

您可以随时创建自己的分支名称,但要创建名称,您必须有一个 commit 以使其指向。因此,您通常希望首先获得他们最新的:git fetch然后第二个 Git 命令。

另外:git pull 表示运行 git fetch,然后运行第二个 Git 命令。由于需要这两个命令来做有用的事情,所以人们喜欢git pull,它运行这两个命令。我不喜欢git pull,因为我喜欢在这两个命令之间插入命令,并且可能使用git pull 为第二个命令提供的相对较薄的选项集以外的其他命令,但这取决于你。

【讨论】:

你好@torek,首先我很感谢你的回答,因为它非常详细,太棒了!你提供了很多细节,只是一个我很感激的简单问题,但我认为我必须接受@Karthik 的回答,因为它很短并且解决了我的问题,但请保留你的回答,因为它会很有用也给其他人......我会把你的答案作为我与git进一步学习的笔记之一非常感谢!真的很感激! 谢谢你,如果我能检查所有的答案,因为它们都满足了我的担忧!打算用 git 把它作为我的终极指南之一 :) 不错的文章,@torek。如果你曾经写过关于 git 的书,请将我添加到预购清单中!

以上是关于如何将远程仓库分支添加到本地仓库的主要内容,如果未能解决你的问题,请参考以下文章

07-git-上传本地项目到仓库

Git本地仓库远程仓库操作和分支操作命令

修改git远程仓库地址

git创建远程仓库

git怎么从远程仓库拉取到本地仓库

Git——如何将本地项目提交至远程仓库(第一次)