git remote update origin --prune 对本地更改的影响

hot*_*oup 3 git

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


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

我对这个命令的理解正确吗?如果不是,我怎么被误导了?如果我是对的,那么如果我有尚未远程推送的本地功能分支会发生什么?如果我有一个变化的分支,会发生什么远程现有/原点,但有我没有推开这些变化了吗?

提前致谢!

tor*_*rek 9

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 识别和查找提交的方式。它们是 Git 真正关心的:提交本身,以及用于识别它们的唯一哈希 ID。

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

... <-F <-G <-H
Run Code Online (Sandbox Code Playgroud)

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

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

一个分支的名字,像master或者develop,仅仅是一种方式,你的Git的优惠,让你帮记住这些散列ID之一。它只记得其中之一!根据定义,它记住的那个是最新的。如果您更改了与您的 关联的编号master,则您已经告诉您的 Git:使用不同的提交作为最新的提交。 因此,我们对图片进行了一些扩充:

...--F--G--H   <-- master
Run Code Online (Sandbox Code Playgroud)

因此,散列 IDH是Git 应视为“on” branch的最后一次提交的散列 ID master

当您进行新的提交时,开始git checkout master并执行所有常规操作直到您运行git commit,Git 会写出一个新的提交。这个新提交获得了一个新的、唯一的哈希 ID,我们可以调用它I

...--F--G--H   <-- master
            \
             I
Run Code Online (Sandbox Code Playgroud)

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

...--F--G--H
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

现在Imaster. 您/您的 Git 仍然可以找到 commit H,方法是从 at 开始I并后退一步。

如果有什么东西要覆盖你master并让它指向回H,那么找到commit将变得非常困难I,因为内部箭头都指向后。 I指向H——孩子知道它的父母——但H根本不知道I存在。(当谁制造H,制造它,H现在不能改变时,它没有!)

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

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

...--F--G--H--J   <-- ???
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

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

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

...--F--G--H--J   <-- origin/master
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

如果你想向他们的master添加提交I——或者另一个同样好的提交,你现在必须决定,你真的想要它自己,还是另一个同样好的提交?如果你想保持自己,你可以合并并进行一个有两个父级的新提交:IIIJ

...--F--G--H--J   <-- origin/master
            \  \
             I--M   <-- master
Run Code Online (Sandbox Code Playgroud)

由于合并提交M有箭头回 J I,你现在可以给他们承诺M,并要求他们的Git来设置 master指向承诺M

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

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

                L--N   <-- origin/feature/A
               /
...--F--G--H--J   <-- origin/master
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

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

                  N   [abandoned]
                 /
                L   <-- origin/feature/A
               /
...--F--G--H--J   <-- origin/master
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

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

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

...--F--G--H--J--L   <-- master, feature/A   [no origin/ -- this is THEIR Git!]
Run Code Online (Sandbox Code Playgroud)

在你的 Git 中是:

...--F--G--H--J--L   <-- origin/master, origin/feature/A
            \
             I   <-- master
Run Code Online (Sandbox Code Playgroud)

他们现在可以完全删除他们的feature/A名字。当他们这样做,你的Git站看到的你的价值观origin/feature/A

--prune但是,如果没有,您的 Git * 不会删除您的origin/feature/A. 所以你继续记住origin/feature/A指定 commit L。这不会造成任何实际伤害;你会认为,根据你的origin/*名字,他们仍然有feature/A,这意味着 commit L

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