Py学习  »  Git

git pull from origin分支的奇怪问题

Harry • 4 年前 • 960 次点击  

我的一位同事把一家分行(branch a)推到回购协议上。

然后我从branch a创建了这个分支(testbranch)的副本。

一切都很好。

随后,这位同事又向布兰卡提交了两份承诺书。

我有了git pull(从repo中获取最新的更改)

但是,我没有看到两个文件提交。

回购协议

布兰查

局部的

git checkout master
git pull
git checkout testBranch origin/BranchA
git merge master

我不知道为什么我看不到最新的提交(文件)

解决办法:

  1. 删除本地分支
  2. 创造了一个新的分支
  3. 签出主机
  4. GIT拉力
  5. 签出新分支
  6. 合并分支
  7. 我现在看到另外两次犯罪

我觉得我好像少了一步?感觉很奇怪,每次需要从特定的源/分支获取最新更改时,我都必须删除分支

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/43911
 
960 次点击  
文章 [ 2 ]  |  最新文章 4 年前
clmno
Reply   •   1 楼
clmno    5 年前

你已经做了一个新的分支 testBranch BranchA . 你的同事把改变 布兰查 . 但你还在 测试分支 . 所以您的远程分支没有要拉取的更改,这就解释了 布兰查 没有出现在 测试分支

...--o--o--*            <-- BranchA

你创建了一个brach brancha的副本。

git checkout -b testBranch

...--o--o--*            <-- BranchA, testBranch

Brancha中的新提交

            A--B--C    <-- BranchA
            /
...--o--o--*            <-- testBranch
torek
Reply   •   2 楼
torek    5 年前

你把太多的魔法归咎于树枝。-)

git的工作方式非常简单。一 分支名称 只是一个git commit hash id的名称。 git pull 即使存在,但我们很快就会看到它是什么,以及如何使用它。)

关于提交、哈希ID、分支名称和提交链

让我们稍微讨论一下这些提交哈希ID。hash id是一个由字母和数字组成的难看的大字符串,例如 0d0ac3826a3bbb9247e39e12623bbcfdd722f24c . 这唯一地标识了一些git对象——通常是commit,当我们处理分支名称时,它总是,肯定是commit。每个提交都记录其 起源 ,或前置任务提交。这允许git将提交的内容串成一个向后看的链。

这意味着我们可以 这些承诺链。如果让一个大写字母代表一个丑陋的hash id,我们会得到如下结果:

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

这个 名称 master 保存提交的实际哈希ID H . 让吉特 找到 G 在存储库内浮动的提交中。从 h Git可以得到哈希ID G ,这就是 H 的父母。所以现在Git可以找到 G 。使用 G ,Git可以找到 F ,等等,向后,向下。这里的箭头可以读为 指向: 主人 指向 h , H 指向 G 等等。

每次提交的内容完全、完全、100%冻结/只读。任何承诺都不能改变。所以我们不需要画内部箭头。但是,分支名称 改变。git添加 新的 致力于 主人 是写出一个commit对象,存储 H 新对象中的哈希ID,以及新的提交快照和任何其他 元数据 喜欢你的名字,电子邮件地址和日志信息。这将产生一个新的散列,我们将调用它 I 而不是试图猜测:

...--F--G--H--I

现在git只需要编写 在名字里 主人 ,这样 主人 现在指向 :

...--F--G--H--I   <-- master

如果你有多个分支,或者你有多个 远程跟踪名称 喜欢 origin/master origin/BranchA ,我们只需要把它们都画出来:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- origin/BranchA

(稍后我们将详细讨论远程跟踪名称。它们有点像树枝的名字,但有点扭曲。)

当您创建一个新的分支名称时,git所要做的就是使新名称指向一些现有的提交。例如,让我们创建自己的 BranchA 现在,使用 git checkout BranchA :

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- BranchA, origin/BranchA

现在让我们创建 testBranch 同时,还指出 J :

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch, BranchA, origin/BranchA

如果您现在创建一个新的提交,您的git需要知道 要更新哪个分支名称 . 所以你的Git有个特别的名字, HEAD ,所有大写字母都是这样写的。 Git将此名称附加到您的一个分支名称:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch (HEAD), BranchA, origin/BranchA

也就是说 测试分支 现在的 分支,因此是 git将更新的名称 当你奔跑 git commit 做出新的承诺。其中之一 git checkout 做的就是管理这个头部附件。


自从你 没有 布兰查 ,你可能会想: 我怎样检查它? 事实上,你 应该 想一想:这是个很好的问题。答案是你的git会 创造 你自己 布兰查 从远程跟踪名称 。所以你必须 git checkout -b testBranch 但不是 git checkout -b BranchA : -b 旗帜说 创造 ,如果没有它,git将只在名称不存在时创建 有一个远程跟踪名称 存在看起来是对的。不止这些,这是个好的开始。

由于怪癖,通常可以使用小写字母。 head 在windows和macos上,但在类unix系统(如linux)上没有。最好避免这种习惯,因为它在linux上不起作用:如果您不喜欢键入 在所有大写字母中,使用 @ ,这是魔法名称的同义词。


远程跟踪名称,或者,当有人在其他Git存储库中进行提交时会发生什么情况?

关于这些分支名称的问题是 具体到 你的 Git存储库 。你的 主人 你的 主人 。你的 布兰查 是你的 布兰查 你的 测试分支 也是你的。他们不会改变除非 改变它们。

事实上,甚至你的远程跟踪名称 原点/主 产地/布兰卡 也是你的,但让它们成为远程跟踪名的原因是你的git会 自动 更改它们,以记住您的git在其他git中看到的内容,只要您的git调用它们的git并询问它们 他们的 分支名称。也就是说,您的git有其他git存储库的url,列在 遥远的 名称 origin : 起源 是一个很长的短名称,可能很难键入url。你可以运行:

git fetch origin

你的git将调用他们的git,在下面列出的url 起源 ,并询问他们的git 他们的 树枝。他们会说: 哦,当然,给你:我的 主人 是<hash1>和我的 布兰查 是<哈希2>。 (要看这个,跑 git ls-remote origin ,就像 git fetch origin 不过,在获得远程名称和散列的列表后,它只是将它们打印出来。)

有了这个列表,你的git会继续向他们的git索要任何 新的 提交 他们 你没有。所以如果他们更新了 他们的 布兰查 ,你得到他们的新承诺。然后,不管发生了什么,您的git现在设置所有 远程跟踪名称 一开始 origin/ 。也就是说,假设他们有两个新的承诺。您自己的存储库现在如下所示:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch (HEAD), BranchA
                 \
                  K--L   <-- origin/BranchA

你自己 布兰查 测试分支 没有移动 。这些是 你的 树枝,所以它们只有在 移动它们。你的 原点/主 因为他们的 主人 没有动,但是你的 产地/布兰卡 感动,记住新的承诺 L 你刚从他们那里得到的,因为 他们的 布兰查 确实移动了,现在指向同一个提交 L .

(请记住,我们的大写字母代表实际的大而丑陋的唯一散列ID。如果他们做了新的提交,而您又做了新的提交,git保证 他们的 新的哈希ID与 每一个 你做的新提交哈希!您可以看到,使用一个活动的存储库,单个大写字母会跑得太快,而且很难使其成为唯一的。但它们更容易绘制,也更容易让我们讨论提交,所以我在这里使用它们。)

让你的分支名称移动

现在他们已经更新了 他们的 布兰查 ,你可能想拥有自己的 布兰查 也可以移动。这就是事情开始变得复杂的原因,但是让我们来看一个简单的方法。

我们从跑步开始 Git签出Brancha 再一次。这将附加 布兰查 ,以便使用 当前分支 正在使用 布兰查 。那我们就用 git merge ,在这种情况下,实际上不会进行任何合并!

git checkout BranchA
git merge origin/BranchA

之前 合并分支 ,我们的存储库中有:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch, BranchA (HEAD)
                 \
                  K--L   <-- origin/BranchA

这个 合并分支 产地/布兰卡 发现它指向 L . 看看我们现在的分行 附加到“并发现它指向 J 。它意识到,从 L 工作向后,它可以直接 J . 这意味着分支名称 布兰查 可以是“向前滑动”,就像是逆着内部的方向,向后指向的箭头。Git将此操作称为 快进 。在 合并分支 ,更像是 GIT校验 移动当前分支名称。也就是说,承诺 L 成为 当前提交 ,但它是通过 移动名称 布兰查 . 结果是:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch
                 \
                  K--L   <-- BranchA (HEAD), origin/BranchA

你现在有承诺了 L 作为你当前的承诺 L 正在填充 指数 以及 工作树 . 是时候谈谈这两个了。

索引和工作树

我们已经提到,提交中存储的文件完全、完全、100%冻结/只读。它们以一种特殊的、压缩的、仅限git的格式存储。这使git可以节省大量空间,并重用未更改的文件:如果新提交的文件与前一次提交的文件基本相同,则无需保存所有文件。旧的提交的副本被冻结,因此新的提交可以 分享 他们。(这个过程的细节在这里并不重要,但是git使用hash id,git调用的是 BLB对象 ,以实现此技巧。)

这对于Git来说是很好的,但是我们不能使用冻结的压缩Git文件来做任何事情。 其他的 。所以Git必须解冻和解压缩被冻结的文件,变成它们的日常形式,这样我们和我们计算机上的其他程序就可以了。 使用 他们。

解冻后的文件进入 工作树 ,这就是所谓的,因为那是我们研究它们的地方。在这里,我们可以做任何我们想用我们的文件。因此,对于每个文件,当前提交中都有一个冻结的副本,而工作树中有一个解冻的副本。(其他提交中也可能有冻结副本,但 现在的 提交是最有趣的,因为我们可以并且经常将它与工作树中的一个进行比较。

这个 指数 ,也被称为 分级区 或者有时 隐藏物 ,是Git特有的。其他版本控制系统也有冻结的提交和解冻的工作树,但也没有 一个索引,或者完全隐藏任何索引,这样你就不需要知道它了。另一方面,git会时不时地用索引打你的脸。你 必须 知道它,即使你不把它用于花哨的把戏。

从本质上说,索引保存的是每个文件的副本。也就是说,每个文件 当前提交 在索引中。索引副本是特殊的git-only格式。不过,与冻结提交副本不同的是,如果你愿意的话,这个副本只是半冻结的。你可以 代替 任何时候都可以用一个新的,不同的,合法的,半冷冻的拷贝。就是这样 git add does:it git确认文件的工作树副本,将其压缩为git-only格式并替换以前的索引副本。(如果新的匹配 任何 旧版本,在任何冻结的git提交中,它最终都会重新使用旧版本:节省空间!否则它就是一个新的git副本。)

制作一个 新的 在git中,commit只需要快速冻结这些索引副本。他们已经准备好了,这也是为什么 GIT提交 比其他版本控制系统快得多。但这也意味着指数可以被描述为 下一个任务是什么 。git从索引而不是从工作树构建新的提交。

你需要工作树来处理你的文件。git需要并使用索引来进行新的提交。索引和工作树副本可以不同,它是 你的 工作到 Git添加 在提交之前,工作树将复制以用更新的索引副本覆盖索引副本。

更新您的 测试分支

现在,让我们看看如何更新 测试分支 . 记住,我们跑了 git fetch 更新我们所有的 origin/* 名字,然后 Git签出Brancha git merge origin/BranchA 更新 布兰查 ,所以我们现在有了这个:

…--f--g--h<--master,源/主
\
i--j<--testbranch公司
\
K--L<--Brancha(头),产地/Brancha

我们现在需要 git checkout testBranch 对它。然后我们可以跑 git merge BranchA Git合并源/分支 :

git checkout testBranch
git merge <anything that identifies commit L>

这里的想法是让git看看commit L 。然后merge命令将查看是否可以执行它所执行的快速转发操作 布兰查 。答案是肯定的:从提交 J 直接承诺 L 。因此,在默认情况下,git会这样做,您将得到:

...--F--G--H   <-- master, origin/master
            \
             I--J
                 \
                  K--L   <-- testBranch, BranchA, origin/BranchA

请注意,我们可以做到这一点,即使我们 永远不要创造我们自己的 布兰查 ,因为不是 Git合并Brancha 我们可以跑 Git合并源/分支 。也就是说,如果我们有:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- testBranch (HEAD)
                 \
                  K--L   <-- origin/BranchA

并运行 Git合并源/分支 ,git将执行与使用名称的版本完全相同的快速转发。 布兰查 指向提交 L . 这里重要的不是分支名称,而是提交。 好吧,我们自己的分支名称,比如 测试分支 ,重要的是,我们需要让他们指出他们应该去的地方;但是 其他 名称远程跟踪名称我们只使用它们 查找提交 . 他们只是 可读性更强 而我们的git会 自动更新 吉特取出 .

因此,假设我们从未创造 布兰查 首先。假设我们做了:

$ git clone <url>
$ cd <repository>
$ git checkout -b testBranch origin/BranchA
... wait until colleague updates origin/BranchA ...
$ git fetch                      # defaults to using origin
$ git merge origin/BranchA

那我们就完蛋了,不用再摆弄了 我们的 布兰查 我们从未创造过。

如果你自己作出承诺的话,我就不提发生了什么。在这种情况下,可以得到一个真正的合并 合并分支 会看到的 可能只是快进,并将运行合并过程,然后进行类型为的提交 合并提交 . 相反,让我们来解决这个难题的最后一点, GIT拉力 .

关于 GIT拉力 (不要用它!)

我的建议 GIT拉力 作为一个初学者,你应该努力学习 避免 它。但是,其他人和文档会告诉您使用它,所以您至少应该知道它的作用。所有这些 GIT拉力 是和做就是跑 git命令。这是为了方便。问题是,有时它很方便,有时它很明显 -方便。在我看来,最好先学会使用两个底层git命令。

第一个git命令 GIT拉力 跑步就是 吉特取出 . 我们已经看到了:它会调用其他git,从中获取 它的 分支名称(和标记名称)和散列ID,并将您需要的任何提交带入您的存储库,以便您的Git可以更新所有 远程跟踪名称 . 然后就完成了:索引和工作树没有发生任何事情。跑起来很安全 吉特取出 随时 ,因为它只是添加新的提交和更新远程跟踪名称。

这个 第二 命令 GIT拉力 跑步是麻烦的来源。你可以选择 哪一个 它运行的第二个命令。通常,那是 合并分支 ,这就是我们上面看到的。但你可以让它运行 git rebase ,我们在这里没有讨论过。

不管是哪种情况, GIT拉力 将一些额外的参数传递给 合并分支 GIT重碱 命令。这些额外的争论造成了一些不便,因为它们 不同的 从你可能想要使用的参数。尤其是,如果您运行:

git pull origin master

这具有运行的效果:

git fetch origin master
git merge -m "merge branch 'master' of $url" origin/master

注意,最后一个argumentgit中的斜杠将合并现在由 原点/主 . 这个 -m (消息)包含从 起源 ,加上名字 主人 ,而不是名字 原点/主 但是 影响 对于合并,快进或实合并与合并更新的远程跟踪名称相同, 原点/主 .

如果你使用单独的 吉特取出 合并分支 命令,它们更有意义。当你使用 GIT拉力 ,列出的分支名称(如果列出一个分支名称)是 在另一个Git上 ,而不是中的远程跟踪名称 你的 Git。

同样的道理即使你有 GIT拉力 运行 GIT重碱 为你。在生命的最后一刻 -方便,决定是使用merge还是rebase是您有时应该做的决定。 之后 运行 吉特取出 . 也就是说,你应该看看 什么 吉特取出 ,以决定要运行的第二个命令。但是如果你用 GIT拉力 ,你必须做出这个决定 之前 你跑 吉特取出 所以你 不能 看。

一旦你使用了git一段时间,并且对两者都非常熟悉 合并分支 GIT重碱 , 然后 你可以开始使用 GIT拉力 安全地。(但我基本上还是没有。)


还有一个问题,Git的老版本:在Git版本1.8.4之前, GIT拉力 没有 更新远程跟踪名称。现代的git消除了这种奇怪的怪癖,但是有些系统仍然使用非常旧的git版本,所以了解它很重要。