社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Git

git pull from origin分支的奇怪问题

Harry • 5 年前 • 1709 次点击  

我的一位同事把一家分行(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
 
1709 次点击  
文章 [ 2 ]  |  最新文章 5 年前
clmno
Reply   •   1 楼
clmno    6 年前

你已经做了一个新的分支 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    6 年前

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

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版本,所以了解它很重要。