首页 > 解决方案 > git remote update origin --prune 对本地更改的影响

问题描述

请注意:我首先看了一下这个问题,希望它能回答我的问题,但我认为我的问题略有不同!


有人告诉我,在git remote update origin --prune本地运行会迫使我的本地仓库拥有与原始仓库完全相同的分支。但是,我可以找到有关使用的大量信息/文档git remote prune origin,但不是git remote update origin --prune...

我对这个命令的理解正确吗?如果不是,我怎么被误导了?如果我是正确的,那么如果我有尚未远程推送的本地功能分支会发生什么?如果我对远程/在源上存在的分支进行了更改,我还没有推送这些更改,会发生什么?

提前致谢!

标签: git

解决方案


TL;博士

命令与命令相同。(在某些版本的 Git 中有一些错误使它们不同,但它们应该做同样的事情。)使用,更新过程只是删除存储库中存在的任何远程跟踪名称,但不再对应于存储库中的分支名称。git remote update remotegit fetch remote--pruneremote

有人告诉我,在git remote update origin --prune本地运行会迫使我的本地仓库拥有与原始仓库完全相同的分支。

这不太对。嗯,这根本不对,真的。这确实与您表达问题标题的方式有关:

影响……对局部变化

使用 Git 时,重要的是要识别出一些与大多数其他版本控制系统不同的地方。首先是分支,或者更准确地说是分支名称,并没有那么重要。分支名称喜欢master并且develop主要仅供人类使用,您可以对它们做几乎任何您想做的事情,包括任意更改它们。(我们稍后会谈到一些例外情况。)

不能改变的——对 Git 来说真正重要的是提交哈希 ID。您将在git log输出中看到这些内容:它们是大而难看的数字和字母字符串,例如b5101f929789889c2e536d915698f58d5c5c6b7a,这是 Git 存储库中的一个提交。这些数字(实际上是十六进制表示)是唯一且通用的:每个地方的 Git 都会使用该数字进行该提交。如果您没有使用此特定 Git 存储库的克隆,则不会有该提交。如果您正在使用此特定 Git 存储库的克隆并且没有此提交,您的 Git 只需要连接到另一个 Git有这个提交,你就会得到这个提交。

这些数字是 Git 识别和查找提交的方式。它们是 Git 真正关心的:提交本身,以及用于识别它们的唯一哈希 ID。

每个提交都包含一些其他早期提交的哈希 ID。通常每个提交只有一个较早的提交哈希 ID。那个较早的提交 ID 是提交的级。因此,给定一些提交哈希 ID,您的 Git 可以判断您是否有提交。如果是这样,你的 Git 可以找出哈希 ID,并告诉你是否有那个提交,然后找出它的父 ID,等等。这意味着给定任何一个提交(通过哈希 ID),您的 Git 可以找到所有提交,一个接一个,向后工作。这为绘制它们提供了一种简单的方法:

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

whereH代表一些提交哈希。Git 会找到实际的提交,读出它的父哈希 ID G,读取提交,找到它的父F,等等。当 Git 返回到第一个没有父哈希的提交时,该操作停止。

任何提交中的任何内容都不会改变。(部分原因是,实际的哈希 ID 是提交的所有内容的加密校验和。如果您要更改任何内容——甚至是一个位——您将获得一个新的、不同的哈希用于新的、不同的提交.) 因此,由于Hstore 的G哈希 ID,H将永远,永远,指向G. 因此,连接箭头的单向性几乎是无关紧要的,我们可以停止绘制它们;我们只需要记住 Git 本身必须向后工作。

分支名称,如masteror ,只是 Git 提供的一种develop方式,可让您帮助记住其中一个哈希 ID。它只记得其中一个根据定义,它记得的那个是最新的。如果您更改与您的 关联的数字master,您已经告诉您的 Git:使用不同的提交作为最新的提交。 因此,我们对图片进行了一些扩充:

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

因此,其中的哈希 IDH是Git 应视为“on”分支的最后一次master提交的 ID 。

当您进行的提交时,从git checkout master所有通常的事情开始并执行到您运行的点git commit,Git 会写出一个新的提交。这个新的提交获得了一个新的、唯一的哈希 ID,我们可以称之为I

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

写出提交并找到其加密校验和哈希 ID 后,Git 现在将该哈希 ID 写入 namemaster中,因此master指向I

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

现在Imaster. 你/你的 Git 仍然可以通过从上一步H开始并返回来找到 commit 。I

如果某些东西要覆盖你master并让它指向 back H,那么很难找到commit I,因为内部箭头都指向后面。 I指向H——孩子知道它的父母——但H根本不知道I存在。(当谁创造了H,创造了它,H现在不能改变时,它就没有了!)

出于这个原因(以及其他原因),您的分支名称是yours。除了您和您​​的 Git 之外,没有人可以将新数字写入其中。实际提交的哈希 ID 是唯一且通用的:如果其他人进行了新提交,则该新提交将获得一个其他提交永远不会拥有的新哈希 ID,并且您的 Git 会知道您是否有该提交。如果您需要它,当您将 Git 连接到他们的 Git 时,您的 Git 将从他们的 Git 获取它。但你的分支名称是的。

所以git fetch或者git remote update——同样,两者都做同样的事情——将调用其他一些Git,并从它们那里获得你没有的任何新提交。假设您git fetch origin在您正在调用的 URL 处调用 Git origin。如果您将提交添加I到您的master,并且他们将提交添加J他们的,那么您的 Git 现在具有:

...--F--G--H--J   <-- ???
            \
             I   <-- master

你的 Git 将如何找到提交J?将那个哈希 ID 写入你master的显然是一个坏主意:那输了I!那么您的 Git可以在哪里写入该哈希 ID?

Git 对此的回答是远程跟踪名称(大多数人称之为远程跟踪分支,但我认为 Git 已经过多地使用了分支这个词)。你的 Git 的名字,你的 Git 会记住origin's master,是origin/master,图片应该是:

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

如果你想向他们的I主人添加提交——或另一个同样好的提交——你现在必须决定,你真的想要它自己,还是另一个同样好的提交?如果你想保留自己,你会合并并做出一个有两个父母的新提交:IIIJ

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

由于合并提交M有返回到和的箭头 J I现在可以向他们发送提交M并要求他们的 Git 将他们 master的指向点设置为提交M

你的 Git 的每个分支都有一个远程跟踪名称

当你运行git fetch originorgit remote update origin时,你的 Git 会调用另一个 Gitorigin并询问其所有分支的列表。他们的分支当然是他们的,但是你的 Git 想要获得他们所做的任何新提交,并为你记住最新的提交。因此,如果他们有master, develop, feature/A, 和feature/B, 你的 Git 会得到他们有的任何你没有的提交,并记住他们的分支提示在你的origin/*名字下,对应于他们的分支名称:

                L--N   <-- origin/feature/A
               /
...--F--G--H--J   <-- origin/master
            \
             I   <-- master

如果他们故意通过将较旧的哈希 ID 写入其分支名称来从某些分支中删除某些提交,您的 Git 将相应地调整您的远程跟踪分支。在某些情况下,这可能会导致你的 Git 忘记他们的提交(如果你从来没有费心用自己的名字来保存它们):

                  N   [abandoned]
                 /
                L   <-- origin/feature/A
               /
...--F--G--H--J   <-- origin/master
            \
             I   <-- master

CommitN不再是可找到的,并且最终git gc会将其从您的存储库中完全删除。(这是分支名称或其他名称变得重要的地方:它们不仅可以让您找到提交,它们还可以保护来自死神收集器的提示提交。这些提示提交保护他们的父母,他们保护链中更靠后的提交,一直到根提交。)

但是,假设他们在某个时候决定该功能A已完成。他们已经将它合并回他们的主人,或者进他们的主人直接指向它:

...--F--G--H--J--L   <-- master, feature/A   [no origin/ -- this is THEIR Git!]

在你的 Git 中是:

...--F--G--H--J--L   <-- origin/master, origin/feature/A
            \
             I   <-- master

他们现在可以完全删除他们的feature/A名字。当他们这样做时,您的Git 将停止为您的origin/feature/A.

但是,如果没有--prune,您的 Git *不会删除您的origin/feature/A. 因此,您继续记住origin/feature/A指定 commit L。这不会造成任何真正的伤害。根据您的origin/*名字,您只会认为他们仍然拥有feature/A并且这意味着 commit L

是否使用--prune取决于您。我在自己的 Git 配置中自动打开它;这使我的存储库不那么混乱。


推荐阅读