从不是远程的克隆中获取是什么意思?

时间:2014-01-29 16:44:42

标签: git fetch

我使用并喜欢GIT,但我正在努力理解它。

我有点卡在遥控器上,跟踪等等。

  • 我创建了一个名为main
  • 的GIT仓库
  • 我克隆main以创建第二个
  • 我做了第二次更改并提交
  • 我回到主要,我做

    git fetch ../second
    ->  * branch            HEAD       -> FETCH_HEAD
    

换句话说,我正在寻找对其克隆一无所知的原始回购。

使用gitk --all,似乎没有添加任何东西。

  • 如果我改为git pull,我在第二次所做的更改会显示出来。
  • 如果我将第二个注册为遥控器,则提取工作正如我所期望的那样。

我的问题:

  • 所以,当我从一个未链接/未跟踪/ unanything仓库取货时,它是在做什么吗?
  • 拉什么工作?

2 个答案:

答案 0 :(得分:2)

注意:使用明确的"远程"是这些日子的方式(见下文为什么)。直接命名URL是一种非常古老(并且已经过时)的方法。

如果您要运行gitk --all FETCH_HEAD,您会看到不同的内容(尝试并查看)。原因是--all仅列出refs/中的所有引用(见下文)。

遥控器和refspecs

"远程"

是什么?

具体而言,遥控器是git配置文件中的一个条目(通常在repo本身内.git/config)。或者更确切地说,是remote.name

部分下的一系列条目
[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = ssh://some.host.name/path/to/repo.git

或类似的。这一点是记录一些常见项目,这样你就不必一直重复它们。特别是,在此之后不必拼写url(和可选的push-url)。 fetch =行也很重要,如下所述。 ("镜像"与#34;常规"存储库不同。)

如果您使用存储库参数而不是URL ...

运行git fetch

如果您执行git fetch ../second,如上所示,您直接命名存储库,而不是"远程"。因此,您不需要remote "origin"部分及其所有条目,相反,您可能需要做更多的工作/打字。您可以使用ssh://...https://...等完整网址命名其他存储库;对于已在您自己的计算机上的存储库的特殊情况,您可以使用相对路径名称,如您的示例所示。

我认为最好将refspec视为识别一个"远程存储库",可能在网络上的其他某台机器上。这有助于我清楚地了解谁有权访问什么。一个"远程存储库的特例"在你自己的本地机器上是一个特例。显然,如果它在您的本地计算机上,它可以随时访问。其他遥控器往往不太容易接近。

考虑克隆的情况,例如,从某个网站(kernel.org或其他地方)git自身的源代码到笔记本电脑上。在某些时候,你拔掉笔记本电脑并随身携带 - 也许是在你没有网络访问权限的飞机上。所以"他们"允许您访问其存储库并将其复制到您的存储库中。一旦你拥有了所有东西,你就不需要他们的#34;除了偶尔与他们重新同步。

git fetch可以使用两个以上的参数

如果您运行git fetch repository refspec,则不仅会更新本地存储库中的对象,还会更新一些" ref-names" (参考文献;见下文)。 fetch的最后一个参数是" refspec"部分,(忽略一些技术性)基本上是ref-names的,用冒号分隔。例如,您可以写git fetch ssh://... master:refs/remotes/origin/master

您需要指定哪些参考名称(如果有)在您从获取的地方,应该将其对象带过来 - 但同样重要的是,该名称是什么名称( s)那些应该在"你的"库。当然,"他们"有分支master,还有分支maint(维护),next等等。最初,您可以在存储库中为它们提供相同的分支名称 - 但是在您工作之后,添加了内容并重新与它们同步,* master和您的{{1} } 是不同的。因此,您需要一个不同的名称来放置"他们的分支"当您获取其master的更新时。

使用远程名称(例如master)运行git fetch,通过origin行为您提供refspec(事实上,可以有多条fetch行,多个refspecs)。但是当你不使用遥控器时,你必须提供自己的refspecs。你没有,所以你得到了一个默认值(稍后会详细介绍)。

参考

引用包括分支和标记名称之类的内容。但是,他们 更加通用和灵活。实际上,fetch也是一个参考。参考文献有一个完整的名称空间"正在发生的事情:它们几乎全部拼写为HEAD,并且特定的的refs生活在这个空间的不同部分。你将一直使用的四个是refs/(这是一种特殊的 - 它不是以HEAD开头而且git一直在内部使用它 - 但它仍然是一个引用) ,分支(本地分支),标记远程分支

(事实上,refs/引用名称是所以特殊,如果你删除它,git决定你不再拥有一个存储库。)

Git通常会自动选择"正确的类型" ref并没有让你把它全部拼出来,但它有助于了解所有这些东西,特别是当git混淆了它的时候,把它搞清楚并做我的意思"代码做了一些你实际上并不是真的意思。

本地分支机构

本地分支位于HEAD,因此您的本地refs/heads/分支实际上是全名master。创建新分支时,这只会添加更多refs/heads/master个名称。 (那些在你本地存储库中的文件中结束。创建一个分支只需要创建一个41字节的小文件。这就是为什么在git中分支是如此快速和简单。)

通常,您不在refs/heads/部分,只需编写分支名称。 Git知道该怎么做。

标签

标签位于refs/heads/:标签refs/tags/只是v1.0。将refs/tags/v1.0--tags一起使用只是告诉它将git fetch添加到它将更新的refspec中。 (在某些版本的git中,这是"替换"而不是"添加"。)

通常,您不在refs/tags/*:refs/tags/*部分,只需编写标签名称即可。由于您正在运行refs/tags/git tag等命令,因此git知道该怎么做。

远程分支

尽管有名字,"远程分支"实际上是一个本地的东西,保存在"你的"回购。换句话说,当你在飞机上拿笔记本电脑时,它们会随身携带。

远程分支位于git fetch --tags,然后一个拥有更多名称部分,这只是远程的名称。例如,对于refs/remotes/遥控器,您可以origin跟踪远程refs/remotes/origin/mastermaster的内容。如果origin还有一个名为origin的分支,您可以跟踪maint那边的内容"在您自己的本地maint

同样,通常你会遗漏refs/remotes/origin/maint部分 - 但这一次,你保留了远程名称。所以你写的是refs/headsorigin/master

额外名称部分的一个重要原因是您可以拥有多个遥控器。如果您有遥控器origin/maintorigin,请在fred保留master - 来源的副本,并保留origin/master的副本 - -fred在master。额外名称部分的另一个重要原因是,当您编写fred/master时,git可以告诉您的意思是远程分支origin/master,而不是您的本地master }。

这些"远程分支"是master需要更新的内容。但是,为了自动更新它们,它需要知道远程名称。这就是为什么git fetch更好":它只是自动执行所有这些操作。您可以使用git fetch remote明确地将它们写出来,但确保将其全部保存在git fetch url "+refs/heads/*:refs/remotes/origin/*"下更好。

过时的方式

很久以前,git没有这些东西。相反,您运行了remote "origin",例如git fetch url refname

为了完成这项工作,git fetch ssh://... master不得破坏您的 fetch。所以它做了 - 并且仍然做 - 是去远程存储库并将所需的所有存储库对象,将它们放入存储库,然后写另一个"特殊的"参考,master。 (例如FETCH_HEADHEAD以及一些其他特殊名称,MERGE_HEAD不属于FETCH_HEAD空间。)

每次编写refspec并省略冒号时都会发生这种情况。而且,如果你完全忽略了refspec,那么 就像写了refs/一样。因此:

  • HEAD表示git fetch url master
  • git fetch url master:FETCH_HEAD表示git fetch url maint
  • git fetch url maint:FETCH_HEAD表示git fetch url

请注意,远程存储库是一个git存储库(" well duh" :-))。这意味着它有一个git fetch url HEAD:FETCH_HEAD。如果它是HEAD的典型存储库,则其fetch与其HEAD相同,因此您获得的默认值是获取master并写入进入master

FETCH_HEAD

Git' git pull命令基本上只是一种方便的方法。它意味着"与pull后跟git fetch(或git mergegit pull --rebase后跟git fetch相同,但请忽略此处)。

不过,这是一种有点奇怪和(我认为)破解便利方法的方法。 (很多内容将在git 1.9中修复。)当你运行时:

git rebase

例如,git pull origin master 做的是调用git pull"旧方式",以便这会带来git fetch' s {{1但无法更新origin。相反,它只是将填充内容的引用放入master。在那里,它对大多数命令都是不可见的,包括refs/remotes/origin/master

FETCH_HEAD的下一步是运行(实际上):

gitk --all

这会将更改合并到当前分支中,这使得大多数命令都可以看到它们,包括git pull origin master

在这种特殊情况下,您运行git merge FETCH_HEAD gitk --all,或者没有 git pull remote branch 参数的任何一个都无关紧要{ {1}}脚本阻止git pull url branch更新远程分支名称。

(在git 1.9中,带有远程名称的branch或没有能够计算远程名称的参数的pull将运行git fetch,以便更新远程分支名称。)

答案 1 :(得分:0)

Git fetch不会将任何内容集成到您的存储库中,即它只会将有关更改的信息下载到本地副本,而不是更改本身。 Git拉扯另一方面

  

在默认模式下,git pull是git fetch的缩写,后跟   git merge FETCH_HEAD。

因此,pull实际上会将来自远程存储库的更改集成到您当前的分支中,而不仅仅是将有关更改的信息提取到存储库索引中。您可能希望这样做,例如在将更改合并到本地副本之前检查对远程进行了哪些更改。 Here's a good article关于此事。

以下内容应说明正在发生的事情

> git init main
> git clone main other
> cd other
> touch file.txt
> git add file.txt
> git commit -m "Added file.txt"
master (root-commit) 027216b] Added file.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file.txt

> cd ../main
> touch a.txt
> git add a.txt 
> git commit -m "Added a.txt"
[master (root-commit) 8ac8913] Added a.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a.txt

> git fetch ../other/ master
warning: no common commits
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../other
 * branch            master     -> FETCH_HEAD

> git diff master FETCH_HEAD
diff --git a/a.txt b/a.txt         <-- a.txt does not exist in FETCH_HEAD
deleted file mode 100644           <-- a.txt does not exist in FETCH_HEAD
index e69de29..0000000
diff --git a/file.txt b/file.txt   <-- file.txt does not exist in master
new file mode 100644               <-- file.txt does not exist in master
index 0000000..e69de29

因此../other的更改已被提取到FETCH_HEAD,您可以查看差异并根据需要合并更改,而不是仅仅执行pull并冒险从远程破坏当前分支中的某些东西。

另一个选择是总是拉到新创建的分支并查看那里的差异,但这有点麻烦。