为什么不应该用git拉?

Why should not use git pull?

我是 Git 的新手,大部分时间我都使用 git pull origin <my-branch> 从远程存储库获取更改。

然而,随着我获得一些经验,我观察到 git fetch 更受欢迎,但阅读了几个主题,例如What is the difference between 'git pull' and 'git fetch'? and Git: Fetch and merge, don’t pull,现在我很困惑,需要澄清是否有正当理由喜欢它,除非在获取更改之前检查更改。

The general idea behind this, git pull is git fetch + git merge, nut of course there are several drawbacks, etc.

那么,能否请您澄清一下:

1. 我应该如何从远程更新本地分支?

2.据我所知,git pull origin <my-branch>git pull origin的区别,后者除了[=18之外,还从origin获取所有分支=].真的吗?我应该更喜欢哪一个?

我不是根据文档写的,而是根据一些经验写的。虽然不多,但可能会有帮助。

  1. Git pull 是你应该用来将代码远程获取到本地的命令。
  2. git fetch 只获取元数据而不是实际代码。

一般情况下,使用单个 repo 你永远不会遇到使用 fetch 命令的情况,但如果你正在使用 fork 或有多个远程 repo,那么只有 fetch 有用或经常使用。

How I should update my local branch from remote?

我总是使用git pull(默认获取所有分支)。

不过我先设置了,since Git 2.6

git config --global pull.rebase true
git config --global rebase.autoStash true

这样,在获取之后,一个简单的 git pull 会触发我的本地提交在获取的远程分支之上的变基。

我看到的唯一缺点是您可能需要多次解决冲突,git pullgit pull 之后。但这就是 git rerere 会阻止的情况(非常罕见)。
参见“What is git-rerere, and how does it work?

关于优点:见“”。

git fetch 是告诉本地 git 从原始文件中检索最新的 meta-data 信息的命令(但不不做任何文件传输。这更像是检查是否有可用的更改)

另一方面,

git pull 这样做并从远程存储库中带来(复制)这些更改。

要记住,您的工作站上通常至少有一个项目的三个副本。

  1. 一个副本是你自己的仓库,有你自己的提交历史( 已经保存了一个,可以这么说)。
  2. 第二个副本是您正在编辑和编辑的工作副本 构建(尚未提交给您的回购协议)。
  3. 第三个副本是远程存储库的本地“缓存”副本 (可能是您克隆的原始文件)。

您可以使用 git fetch 了解自上次拉取后在远程 repo/branch 中所做的更改。这对于允许在进行实际拉取之前进行检查很有用,这可能会更改当前分支和工作副本中的文件(并可能丢失您的更改等)。

git fetch    
git diff ...origin
  1. 我应该如何从远程更新我的本地分支?

Git pull 是更新分支的安全方式。有时会因拉动而引起冲突,而这些都是边缘情况。最坏的情况是撤消 git pull

的更改
  1. 据我所知,git pull origin "my-branch" 和 git pull origin 的区别是,后者从 origin 获取所有分支。真的吗?我应该更喜欢哪一个?

如果您使用 git pull origin 而不指定“my-branch”,git 将用您当前使用的分支填充该值

I am new in Git and I have used git pull origin in most of the time to get the changes from remote repository.

它们是做不同事情的不同命令,fetch 加载所有新的远程提交。然后你可以查看它们,当你知道想要将所有这些新的远程提交实际应用到你的本地分支时,你 运行 a pull.

要清楚 运行宁 pull 相当于 运行宁 fetch 然后 merge 将远程更改合并到本地.

now I am confused and need a clarification if there is a valid reason to prefer it except from checking changes before getting them.

你不会使用一个或另一个 - 你会同时使用它们。没有偏好 - 你先取然后拉 - 或者你只是拉。

您看到的偏好可能是因为提取是一项安全操作 - 它不会改变任何内容。 Pull 确实会更改您的本地文件,您最终可能会遇到合并冲突。

  1. How I should update my local branch from remote?

运行 拉取本地功能分支没问题,但可能会有合并提交。

  1. As far as I see, the difference between git pull origin and git pull origin, the latter gets all the branches from origin besides . Is that true? And which one should I prefer?

不确定那个。

git pull:

  1. 运行s git fetch;然后
  2. (不等你确认!)运行第二个Git命令。

如果要运行两个Git命令,而git pull将运行的第二个命令是你想要 运行 秒的命令,git pull 没问题。

我个人经常喜欢插入一些附加Git命令介于 fetch 命令和另一个命令。这在使用 git pull 时是不可能的,因为它不会为你暂停。所以我经常回避git pull。 (特别是,我经常想 运行 git log 看看我在做什么。)

我还发现对于 Git 的新手,他们认为 git pull 有点神奇。通过避免它——至少在最初——支持两个单独的步骤,他们学会了如何使用 Git。使用 git pull 时,他们不会学习如何使用 Git。 (这在 2005 年左右也适用于我。)所以我鼓励新手使用单独的命令。这不仅有助于“Git 不是魔法”部分,而且有助于 second 命令 git pull 运行s是你选择的东西:

  • 您可以选择git pull 运行 git merge.
  • 您可以选择git pull 运行 git rebase.

这两个命令都结合工作,但是它们的工作方式非常不同。如果您在您的 存储库中没有做任何工作,将我所做的工作(即什么都没有)与其他人所做的工作 结合起来得到别人做的工作,所以你使用哪个命令并不重要。但是,如果您确实在您的存储库中做了一些工作,那么确实很重要。

当您将两个命令分开时,这也更加突出:

  • git merge 表示 将我的工作与他们的工作合并: 将“无”与“某事”合并 = “某事”;将“某物”与“其他东西”合并 =“第三件事”。
  • git rebase 意味着 在他们的工作之上重做我的工作: 在“某事” = “某事”之上重做“无”,但是在其他事情之上重做一些事情,嗯,您可能会看到这是怎么回事(但如果没有,请继续阅读 git rebase)。

回答您的具体问题:

  1. How I should update my local branch from remote?

这取决于您想要的结果以及您对第二个命令的确定程度。

As far as I see, the difference between git pull origin <my-branch> and git pull origin, the latter gets all the branches from origin besides <my-branch>. Is that true?

主要是。这是我们真正需要将 git pull 分解为两个步骤的地方,并观察 它给 这两个步骤中的每一个 的内容.

当您运行 git pull时,您可以提供选项。例如,这些都是调用 git pull:

的有效方法
git pull --rebase

git pull --ff-only

这些选项是矛盾的,因为 --rebasegit pull 应该 运行 git rebase 作为它的第二个命令,而 --ff-onlygit pull 应该为 git merge 第二个命令提供 --ff-only 选项,这意味着它应该 运行 git merge,而不是 git rebase.

所以一些选项控制第二个命令pull应该使用。其他选项通过 第二个命令。还有其他选项被传递给第一个 git fetch 命令。这有点令人困惑,这是学习 git fetch first.

的另一个原因

您还可以提供参数,例如您在此处建议的<my-branch>您提供的所有 non-option 参数都会传递给 git fetch 参数与选项的区别在于前面的 ---一个选项。 (Single-dash -选项为单个字母,如-j-4;double-dash --选项为多个字母,如--rebase--show-forced-updates.)

如果您提供 参数 ,例如 origin<my-branch>,这些会进入 git fetch,这会影响 git fetch 运作。使用 没有 个参数,git fetch 将:

  • 找到合适的remote来调用(一般是origin):“remote”是一种联系方式的简称其他 Git 软件,在这种情况下,将从另一个 Git 存储库读取。在这种情况下,您正在接触 GitHub 或 Bitbucket 或 GitLab 上的某些 Git 软件,也许,那里有您制作 [=] 的 Git 存储库199=]你的 Git 存储库较早。您现在想联系同一个 Git 存储库,看看他们是否有任何您的 Git 存储库还没有的新提交。 (这些提交是如何到达那里的?好吧,我们可以稍后再担心。)

  • 调用该软件并连接到该存储库。该存储库有 its 个分支和 its 个提交。该存储库中的分支不是 分店!他们是 他们的 分支机构。他们可能在其中存储不同的提交哈希 ID。

  • 根据存储在分支名称中的哈希 ID,找出他们有哪些您没有的提交。决定您想要在存储库中提交哪些内容。

如果您git fetch命令中列出一些分支名称,您的Git假设您想要更新他们所有分支机构的所有副本。因此,您的 Git 将检查他们的 mastermain,以及他们的 develop,以及他们的 feature/shortfeature/longfeature/tall 或任何。您的 Git 将确定他们是否有任何您没有的新提交,并将这些提交带到您的 Git 存储库中。

因为提交使用 普遍唯一的 标识符进行编号,您的 Git(在您的存储库上运行的软件)现在将拥有所有提交,使用 他们使用的号码相同。您的 Git 也将拥有您自己的所有提交,而他们根本没有。现在您的 Git 已完成所有提交,您的 Git 将创建或更新您所有的 remote-tracking 名称: origin/mainorigin/master 代表他们的 mainmasterorigin/develop 代表他们的 develop,依此类推。您的 Git 通过在每个 branch 名称前面粘贴 remote 名称 origin 来构建这些名称。

这些 remote-tracking 名称构成了您 Git 对它们分支位置的记忆,即您上次获得它们 Git 时的记忆。所以 git fetch 没有参数更新 所有 ,并且由于 git pull 没有参数调用 git fetch 没有参数,你得到所有 origin/* 名称已更新。使用一个参数——git pull origin——同样的事情发生了,你现在明确表示你想要使用名为 origin 的遥控器。如果那是您拥有的 only 遥控器——这是一个典型的设置——它做的事情完全一样;这里的任何其他名称,例如 git fetch belgium 或其他名称,只会给您一个错误。

但是如果你 运行 git fetch origin develop,那就告诉你的 Git,为了这个 git fetch 操作的目的,你想要你的 Git 调用他们的 Git,查看他们的所有分支,但是 将您的更新 限制为更新您的 origin/develop 所需的任何提交。如果他们在他们的 main 上有新的提交,您毕竟不会更新您的 origin/main。 (你几乎肯定会想要或必须稍后这样做,所以这并没有真正为你节省太多。事实上,由于 Git 优化的方式,它可能会在以后花费更多时间,而不是一次完成抓取。但如果你想要它就在那里。)

由于 git pull 通过 all 参数,git pull origin develop 指示您的 git fetch 步骤将自己限制在名为 develop. (同样,这将成为您的 origin/develop。)

但是现在 第二个命令 开始起作用了。有了 运行 git fetch,以及它可能使用的任何额外选项和参数,您的 git pull 现在 运行 是您选择的第二个命令。 (你确实选择了一个,对吗?始终确保你知道第二个命令 Git 将 运行 在这里!大多数人设置一个 semi-permanently,以便他们知道。)第二个命令是或者:

git rebase [options argument(s)]

或:

git merge options argument(s)

Git的pull经常在这里传递一些选项and/or参数。特别是,对于 git merge,它通过:

-m "merge branch '<branch>' of <url>"

设置合并消息,然后它传递你引入的提示提交的原始哈希ID。对于 rebase,它可能会传递 --autostash,它可能会传递一个提交哈希 ID(或者它可以让 rebase 自己计算出 @{upstream})。你真的不需要知道所有这些,但值得记住的是 git pull 做了一些额外的事情 特别是 对于 git merge 情况,设置合并消息.

这里还有最后一个警告:

git pull origin br1 br2

对新手很有诱惑力。 不要使用它。 它 运行s git fetch origin br1 br2 然后 运行s 一个 octopus merge (of HEADorigin/br1origin/br2,实际上),除非您真的知道自己在做什么,否则您不希望章鱼合并。

这导致了几个底线

如果您将 git pull 设置为 始终 运行 git rebase,那么 运行 与您自己的 git fetch 之后是您自己的 git rebase,然后是 运行ning git pull。那是因为没有要更改的合并消息。不过,在执行此操作之前,请确保您知道 rebase 的作用:rebase 比合并更复杂

如果你将git pull设置为总是运行git mergepull所做的fetch-then-merge有将合并消息设置为 可能 略微 的优点(?)比使用两个单独的命令获得的默认设置更好。比较:

merge branch 'smörgåsbord' of ssh://github.com/swedish/meatballs.git

对比:

merge branch 'origin/smörgåsbord'

没有一个真正告诉你任何有用的东西,但有些人可能比另一个更喜欢一个

注意 git pull <remote> <branch1> <branch2>,这几乎肯定会做错事(尽管如果您设置为变基,这应该只会给您一个错误;变基在这种情况下没有意义).

如果你想要运行两个命令之间的命令(例如git log)以便选择第二个命令要使用 ,您 不能 使用 do-it-all-at-once leap-before-you-look git pull。这就是为什么——以及何时——我避免 git pull.

除此之外,它们几乎是一回事,一旦您知道 git pull 如何为您提供两个 Git 命令。

如果我正在获取其他人推送的新分支,我会使用 git 获取。 假设我想查看 Mary 在她的分支 featureB 上的最新更改。

我会做:

git checkout featureB
git pull origin featureB

这将为 featureB 获取最新的 meta-data,并将其合并到我当前的 featureB 副本中。

但是如果从来没有pull过featureB,那么我就无法checkout featureB。

如果我目前已经检查了自己的分支 featureA,那么我不想执行 git pull origin featureB 因为那会获取 featureB,然后将它合并到我的 featureA 分支中。

所以我这样做:

git fetch origin featherB
git checkout featureB

现在我的本地存储库中有分支 featureB。

因为我现在在我的本地仓库中有分支 featureB,所以现在可以 下次我想从远程仓库更新它时使用结帐。

假设我检查了分支 featureA,我想获取最新版本的 featureB。 我可以做到:

git checkout featureB
git pull origin featureB