是git pull和push存储库范围的操作还是分支特定的?

时间:2014-03-12 20:44:25

标签: git git-push git-pull git-fetch

试图在git上获得真正的处理:)git是否会进行存储库扩展操作?这意味着,它是否会更新存储库中的本地分支(跟踪远程分支),还是只为当前签出的分支进行获取和合并?

推送是否同样如此?什么 - 所有做推拉操作?

任何帮助都会摇滚!

另外,fetch做了什么?它是否获取特定分支的信息(.git文件夹中的文件)?或者.git文件夹在整个仓库中是否一致?如果我取而不是克隆,那么之后我就无法做任何事情了,取出后该怎么办?

2 个答案:

答案 0 :(得分:2)

git pull只是git fetchgit merge的组合。

git fetch将更新所有远程分支,git merge将通过合并相应的远程分支来更新当前分支。

普通git push的确切行为取决于git config push.default的输出。 最近的git版本将其设置为simple,它只会推送当前分支。

有关命令行选项的确切含义,请使用git help pushgit help pull

git clone只是git initgit remote addgit fetchgit checkout的组合。

您的.git文件夹 是您的本地存储库,其中包含所有文件的完整历史记录。 .git文件夹外的文件是您的“工作树”。更改文件需要工作树,但git log等大多数其他git命令不需要。

答案 1 :(得分:1)

TL; DR摘要:"它取决于"。

答案是"两者都没有",真的。或者"它取决于"。或类似的东西!

首先,需要考虑两个基本操作:fetchpush。 (pull操作只是构建在fetch之上的shell脚本,因此一旦您知道 如何工作,我们就可以正确解释pull。)< / p>

fetchpush都有访问到整个存储库。但一般来说,它们不能通过线路(或其他通信信道)发送整个存储库。它们基于引用工作。

fetch和push操作通常采用&#34; refspecs&#34 ;,它们是引用对(远程:本地和本地:远程分别)和一个可选的&#34; force&#34;标志前缀+。但是,它们只能给出一个简单的引用,并且可以使用-f--force指定强制标记。

这两个命令已经存在了很长时间,并积累了许多旧的东西&#34;。 &#34;现代&#34;使用远程存储库的方法是通过名为&#34; remote&#34;的东西,使用git remote add来创建它们(并且git clone默认创建一个名为origin的东西。这些变成了.git/config文件中的条目:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = ssh://...

url =行提供了抓取和推送的网址,但如果需要,可以添加额外的pushurl =行,以便推送到其他位置。 (有#34;老方法&#34;直接运行提取和推送并提供URL,等等,但是让我们忽略所有这些......遥控器要好得多!)这也提供了refspecs -well,一个refspec,在这种情况下为git fetch

git ls-remote

完成后,让我们完全从另一个命令git ls-remote开始。这类似于fetch,但实际上没有取任何东西:

$ git ls-remote origin
676699a0e0cdfd97521f3524c763222f1c30a094    HEAD
222c4dd303570d096f0346c3cd1dff6ea2c84f83    refs/heads/branch
676699a0e0cdfd97521f3524c763222f1c30a094    refs/heads/master
d41117433d7b4431a188c0eddec878646bf399c3    refs/tags/tag-foo

这告诉我们名为origin的远程名称有三个引用名称。两个是分支,一个是标签。 (特殊HEAD ref与refs/heads/master具有相同的SHA-1,因此git会猜测远程在分支master上的#34;&#34;为{{1}可能会说。远程协议中存在各种错误:git应该能够说&#34; git status是一个符号引用,指向HEAD&#34;,所以您的结果不必猜测。这将解决两个分支具有与refs/heads/master相同的SHA-1的情况。)

git fetch

当您运行HEAD时,获取操作会以相同的git fetch origin开始,或多或少,从而查看所有分支和标记。如果你使用ls-remote它也会带来所有标签,否则它会带来相当复杂的 1 带来所有分支和一些标签。它也会看到所有其他引用,但默认情况下,它不会带来那些:例如,远程可能有--tagsrefs/notes/commits使用它,但是那个人没有过来。

但是,当你改变赋予git notes的refspec时,你会改变被带来的东西。默认值是git fetch.git/config中的默认值。这个refspec说要将所有fetch = +refs/heads/*:refs/remotes/origin/*个引用 - 所有分支 - 带到本地,并使用与远程分支名称相同的名称将它们存储在refs/heads/*下。使用refs/remotes/origin/会添加一个额外的refspec:--tags。这就是git如何带来所有标签:匹配refs/tags/*:refs/tags/*的所有标签,都是匹配名称下的本地refs/tags/*

(您可以添加更多refs/tags/行并带来更多内容。有关示例,请参阅this answer&#34;远程标记&#34;。

现在,只要引用引用名称就不会有好处,除非git还带来任何必需的底层对象 2 由他们的SHA-1识别。我们假设您已经fetch =,但不是676699a...。 (您在222c4dd...上更新了最新信息,但master上没有更新。也许您甚至还没有拥有分支branch。)获取操作需要确保带来该提交。该提交可能需要各种文件和先前的提交,等等。所以你的branch与遥控器上正在查看另一个git存储库的东西进行通信,并且他们进行了一些对话,每个人都告诉对方他们现在拥有什么样的SHA-1,以及哪些是他们仍然需要。如果您需要git fetch,则会询问另一端&#34;我还需要使用 222c4dd...&#34;,检查是否有那些,如果没有,将它们添加到列表中,一旦添加就更详细地检查它们,等等。

最终同意交换什么,他们的git会向你发送对象 - 通常是在&#34;薄包&#34;如果可能(详细信息取决于传输) - 并且您的git根据需要解压缩和/或重新打包它们,然后更新您的本地引用以获取任何新分支,标记或其他引用。 (默认情况下,你的git只是将他们的分支存储在你的&#34;远程分支&#34; - 你的副本#34;他们最后一次与他们交谈的内容&#34; - 但是更新你的< / em>标签。也就是说,没有&#34;远程标签&#34;,只是&#34;远程分支&#34;。)

一个重要的git fetch特例

作为一种特殊情况,如果你给222c4dd...超出遥控器名称的任何参数 - 如:

git fetch

例如 - 这些 refspecs覆盖配置文件中的那些(在1.8.4之前的git版本中)阻止更新&#34;远程分支&#34 ;。这通常会限制所取得的东西,有时甚至是相当多的。 (在1.8.4及更高版本中,它们仍限制获取,但远程分支无论如何都会更新,这更有意义。)这里,一个缺少冒号的refspec - 就像上面的那个 - 是不是< / em>被视为两面都有相同的名称。相反,&#34;他们的&#34;像往常一样收集分支,但SHA-1和分支名称写入git fetch origin master

(这是有充分理由的:如果.git/FETCH_HEAD更新了git fetch origin master,您将丢失所有新提交的内容!所以您希望它仅更新master和/或origin/master。)

git push

FETCH_HEAD操作与push非常相似。但它并不是完全对称的:你不会推到一个远程分支机构,一般情况下,你只需要向右推进一个分支机构&#34;。例如,在推送您的分支fetch时,您的本地引用为master,其本地引用也是 refs/heads/master。它肯定不是refs/heads/master。所以用于推送的refspec通常要简单得多。

如果您只是运行refs/remotes/yoursystem/master(或git push),那么仍然需要提供一些refspec(s)。

git配置文件git push origin中有一个(某种新的)控制旋钮,允许您配置git推送的引用。在当前版本的git中,默认为push.default。在git 2.0中,它将被更改为matching。总共有五种设置:

  • simple:产生错误
  • nothing:将您所在的分支推到同一个名称
  • current:将您所在的分支推送到其上游名称
  • upstream:与上游类似,但要求上游名称与本地名称匹配
  • simple:推送所有具有相同名称的分支

其中一些需要进一步解释。 &#34;上游名称&#34;是另一端的分支名称。假设您有一个名为matching的远程分支,并为此创建了一个本地跟踪分支,但称之为origin/feature,因为您已经在处理另一个feature2分支(尚未在feature上创建)。因此,您的本地origin上游有feature2(而您的remote/origin根本没有上游)。推送到feature将跟随映射,并将upstream推送到feature2。推送feature将拒绝该尝试。

因此,如果你simple没有refspec,git会查找默认配置 3 并根据它构建refspec。对于git push案例,它会推送您和他们都拥有的每个分支(因此,如果您同时拥有matchingmaster,请将branch推送到master和你的masterbranch),但是只有你们中的一个人没有对分支做任何事情。

如果你给出一些明确的refspec,那么所有这些都没有实际意义:push操作会推送你给它的refspec。此外,没有冒号的refspec意味着&#34;在两端使用相同的名称&#34;,因此branch是编写完整长版本master的简便方法。

与fetch一样,你的git和他们的git进行通信,以确定需要发送哪些存储库对象(如果有的话)来完成推送。

git pull

refs/heads/master:refs/heads/master操作运行git pull的四字形式。

它的第一步是找出使用什么遥控器。如果你说出一个名字:

git fetch

它取你给它的名字;否则,它会查看您所在的分支(让我们说git pull origin master ),然后查看master以查找.git/config(可能是branch.master.remote)。

然后,它计算出要使用的分支。如果你命名一个,它会使用它;否则,它使用origin,这是另一端的分支的名称(通常只是branch.master.merge)。然后它使用这些参数运行master

这意味着获取只会带来有趣的&#34;分支,在本例中为git fetch,并将SHA-1放在master中。 (如果你有git 1.8.4或更新版本,它也会更新FETCH_HEAD。)

最后,origin/master运行pullmerge,这取决于配置条目以及是否使用rebase运行它。您将合并或重新绑定的提交是其SHA-1现在存储在--rebase中的提交。

请注意,这只会合并或重新绑定您当前的分支。


1 如手册中所述,fetch默认为&#34;标记&#34;技巧:它查看标签中的SHA-1,并查看它们是否存在于您的存储库中。对于那些曾经或将要成为的人来说,它会带来那个标签。您可以使用FETCH_HEAD关闭此功能。

2 对象是存储库实际存储的东西:&#34; blobs&#34; (文件),树(充满文件或更多目录的目录),提交和&#34;带注释的标签&#34;。每个都有一个唯一的SHA-1名称。

3 但是,您可以使用每个分支配置--no-tagsbranch.name.pushremote覆盖此设置。通过转动许多配置旋钮,你可以制作出难以理解的大量效果。