我已经使用seed来启动项目并添加了更改,首先克隆种子项目,进行编辑并将remote
从origin
更改为boilerplate
,现在我已经有了可以在master上工作的项目,所以我添加了自己的repo remote。但是我想为该项目的较新版本创建一个分支,并且样板存储库已经具有一个远程分支phaser3
,我希望从根本上拉起并替换冲突,以便我可以开始迁移到新版本。这是我尝试过的:
➜ dir git:(master) git fetch boilerplate phaser3 From https://github.com/lean/phaser-es6-webpack * branch phaser3 -> FETCH_HEAD ➜ dir git:(master) git checkout phaser3 Branch 'phaser3' set up to track remote branch 'phaser3' from 'boilerplate'. Switched to a new branch 'phaser3' ➜ dir git:(phaser3) git pull Already up to date.
➜ dir git:(phaser3) git pull --rebase Already up to date. Current branch phaser3 is up to date.
所以对我来说,很明显,我已经在本地phaser3
分支中跟踪boilerplate/phaser3
,但是现在我该如何提取更新的phaser3 package.json
和其他文件两个phaser3分支之间有何不同?
答案 0 :(得分:0)
这里似乎没有什么错误。尽管如此,您的输出中还是有一些可疑的,这表明您可能正在运行Git 1.8.3或更早版本,或者可能没有。 (您可以轻松地使用git --version
进行检查。如果您的Git是2.0之前的版本,则可能需要升级。截至此答案,当前版本为v2.21。)
有趣的部分是这个位:
➜ dir git:(master) git fetch boilerplate phaser3 From https://github.com/lean/phaser-es6-webpack * branch phaser3 -> FETCH_HEAD
将此与今天下午git fetch origin master
在Linux存储库中得到的内容进行比较:
$ git fetch origin master
remote: Counting objects: 235, done.
remote: Compressing objects: 100% (160/160), done.
remote: Total 235 (delta 120), reused 124 (delta 71)
Receiving objects: 100% (235/235), 273.62 KiB | 230.00 KiB/s, done.
Resolving deltas: 100% (120/120), done.
From git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
* branch master -> FETCH_HEAD
9e98c678c2d6..54c490164523 master -> origin/master
除了多余的详细信息(计数,压缩,接收等)之外,最后两行的区别也非常重要:
* branch master -> FETCH_HEAD
9e98c678c2d6..54c490164523 master -> origin/master
他们表明我的Git已将新的哈希ID写入origin/master
。具体来说,在之前我运行了git fetch
,我得到了:
$ git rev-parse origin/master
9e98c678c2d6ae3a17cb2de55d17f69dddaa231b
之后,我跑了git fetch
,我得到了:
$ git rev-parse origin/master
54c490164523de90c42b1d89e7de3befe3284d1b
这是因为git fetch origin master
更新了我自己的Git存储库中的两个关键项目。其中之一是我的远程跟踪名称 refs/remotes/origin/master
,通常缩写为origin/master
。另一个是特殊文件.git/FETCH_HEAD
,git fetch
总是根据您告诉它要获取的内容以及从另一个Git获取的内容来编写该文件。
您的输出显示Git仅更新这些项目中的一个,即文件.git/FETCH_HEAD
。但这可能是正常现象,不是是旧版本Git的信号,因为如果我之后立即重新运行 same git fetch
,则会发生以下情况:< / p>
$ git fetch origin master
From git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
* branch master -> FETCH_HEAD
,它看起来与您自己的输出相同。因此,我怀疑您的git fetch
实际上无所作为,就像我的 second git fetch
一样,因为没有事可做。这将导致您看到的其他行为。
了解正在发生的事情(git fetch
正在做什么)的关键在于认识到分支名称对Git并不是很重要。对Git重要的 是每个 commit 。每个提交都由其哈希ID 唯一标识,该ID看起来是随机的,但实际上是其内容的加密校验和。
Git提交存储所有文件的快照以及一些元数据,其中一些数据有关该提交。元数据包括进行提交的人的姓名和电子邮件地址,何时(进行时间戳记),为什么(进行日志记录)以及—至关重要地—提交的父哈希ID 。
这是该特定存储库中的示例提交。其哈希ID为d1f0301b3333eef5efbfa1fe0f0edbea01863d5d
:
$ git cat-file -p d1f0301b3333eef5efbfa1fe0f0edbea01863d5d | sed 's/@/ /'
tree 86c897e94952090eee579ed47f49cc7006c41fd6
parent 6b4703768268d09ac928c64474fd686adf4574f9
author Thomas Gleixner <tglx linutronix.de> 1533300299 +0200
committer Thomas Gleixner <tglx linutronix.de> 1533302341 +0200
genirq: Make force irq threading setup more robust
The support of force threading interrupts which are set up with both a
primary and a threaded handler wreckaged the setup of regular requested
threaded interrupts (primary handler == NULL).
[snip]
这不是我们通常看待提交的方式-多数时候,例如,我们可能会使用git show
或git log
,而那些 compare 提交给较早的提交,以便我们可以看到两个快照中的不同之处。这就像将今天的温暖或多雨与昨天的温暖或多雨进行比较:它告诉我们发生了什么变化,这对我们来说有时比绝对状态更重要。但这确实显示了提交中的内容:它有一个 tree (带有一些内部Git哈希ID),一个 parent 和另一个提交的hash ID,以及作者和提交者并记录消息。 (有些提交有更多内容。)Git就是通过树来存储快照的。 parent
行告诉我们哪个提交在此提交之前。
结果是,给定了一些Git提交哈希ID,Git总是可以找到在之前的提交。实际上,父行指向另一个较早的提交。因此,如果我们有很长的提交链:
... <-F <-G <-H ...
我们可以选择以下提交之一,并沿其箭头向后退到上一个提交:从H
到G
,然后到F
,然后等等。
这里的问题是这些散列ID完全随机出现,并且部分取决于某人制造它们的时间,精确到秒。例如,Thomas Gleixner在时间1533300299 +0200
进行了提交。 1 所有这些详细信息都进入了提交哈希ID。这意味着我们无法知道哈希ID是什么-它是有效随机的。那么我们怎么知道 latest 提交是哪个提交?
答案是Git通过让我们创建分支名称帮助我们。我们告诉Git:以诸如master
或phaser3
之类的名称存储最新/最新提交的哈希ID。给定 ID ,Git可以找到提交本身。该提交存储了一个父ID,因此Git也可以找到该父ID。父级存储另一个父级ID(实际上就是该提交的祖父母),以便Git可以找到该祖父级,并且该提交存储了另一个父级ID,依此类推。
事实上,历史不过是通过从每个提交转到其父目录而找到的一组提交。从一些起点开始,并进行反向访问,这些提交 是Git存储库中的历史。起点是存储库中的所有名称:分支名称,标签名称(如v2.1
和远程跟踪名称(如origin/master
或{ {1}}。 2
1 好,那是他创作(原始版本的)提交,但后来他提交该提交在1533302341, 34分钟2秒后。
2 存储库可以在经过boilerplate/phaser3
或git rebase
之类的各种操作之后,包含没有< / em>通过此遍历所有可提交的名称(从某个名称开始)进程。这些残留或垃圾提交最终会由Git的垃圾收集器 git commit --amend
清除并丢弃。请注意,git gc
至少进行了许多其他内部管理和性能改进工作,或旨在提高性能的工作。所有这些操作都是自动完成的-正常情况下无需手动运行。
您运行了git gc
,而您的Git则这样说:
git checkout phaser3
通常,当您说Branch 'phaser3' set up to track remote branch 'phaser3' from 'boilerplate'.
Switched to a new branch 'phaser3'
时,Git所做的只是在您的存储库中浏览 {1>}分支的 { / em>。该分支名称标识了应视为分支的 tip 的最新/最新提交。 Git将提交的内容提取到索引和工作树中,以便您可以查看并使用它。
有时候,您告诉Git签出一个分支,而您没有该分支。不仅会失败,而且仍然会发生:
git checkout somebranch
-您的Git首先列出您自己的分支,例如somebranch
:
$ git checkout nosuchbranch
error: pathspec 'nosuchbranch' did not match any file(s) known to git
您要输入的名称不在列表中,但是Git尚未准备好放弃。现在,它将检查您的所有远程跟踪名称,您可以使用git branch
列出这些名称。结果取决于您拥有哪些 remoting (大多数人在他们的存储库中只有一个名为$ git branch
* master
的人)以及您的Git记住的名称 >来自这些遥控器:
git branch -r
我要了origin
,但这些都不像。但是,如果我要问$ git branch -r
origin/develop
origin/feature2
origin/master
upstream/master
upstream/develop
,该怎么办?
Git会扫描所有这些内容,并且将有一个与nosuchbranch
完全匹配的名称,即feature2
。因此,我的Git会说:啊哈,您希望我使用feature2
作为提交来创建新的origin/feature2
!现在,我可能会:
feature2
名称分别为origin/feature2
和... <-H <-I <-J <-- feature2 (HEAD), origin/feature2
的 都记住提交feature2
的哈希ID。
请注意,在这种特殊情况下-如果我跑步,我没有origin/feature2
但J
和 develop
都有一个- / p>
origin
我的Git会放弃,因为它不知道是否应该从upstream
或git checkout develop
制作新的develop
。即使它们都标识了 same 提交(例如,我在图中未绘制的origin/develop
提交),我的Git也不知道这两个中的哪个用作<我的新upstream/develop
的em>上游设置。我在这里可以做的是:
L
告诉我的Git:使用develop
,新建一个git checkout --track origin/develop
,其中origin/develop
从develop
的{{1}更新并推送到}。
我们在这里进行的非常快,并没有详细说明所有的工作原理,但是我会在这里再次提及,这将设置新创建的上游设置科。分支的上游是当您运行develop
时Git如何决定说“超前”和/或“落后”,以及如果您运行origin
或{{1}时Git如何知道要使用哪些提交},不带参数。上游指示develop
或git status
在不提供额外参数的情况下将执行的操作,以及在拥有多个远程控制器时将使用哪个远程git merge
。因此,上游设置非常有用。
git rebase
什么也不做,因为没有新的提交:以我喜欢在StackOverflow上绘制提交的方式绘制图形时,您的图形如下所示:
git pull
或者像这样:
git push
git fetch
所做的工作是复制提交您具有的权限(例如,在此图中的提交git pull --rebase
)到之后的新提交他们的最后一次提交。在这种情况下,可以将...--G--H <-- phaser3 (HEAD), boilerplate/phaser3
复制到...--G--H <-- boilerplate/phaser3
\
I <-- phaser3
之后的新提交中,而不是git rebase
现在所在的位置,但是I
已经在I
之后,因此无需进行任何此类复制。 (并且在两个名称都指向 same commit H
的情况下,没有要复制的提交,这也意味着没有工作要做。)
I
的上游是I
。名称H
本身通常只是H
的缩写; Git称之为远程。
https://github.com/lean/phaser-es6-webpack
上有完整的Git存储库;它有自己的四个分支。您的存储库已将其phaser3
分支(即存储在该名称中的哈希ID boilerplate/phaser3
)复制到您自己的远程跟踪名称boilerplate
中。 / p>
https://github.com/lean/phaser-es6-webpack
和phaser3
命令是将提交从一个存储库转移到另一个存储库的命令。通常,发送方发送提交者尚未收到的提交,因此最终,接收方拥有发送者所拥有的一切,如果发送者已经拥有了东西,则可能还要更多。将提交从发送方发送到接收方之后,接收方现在需要更新一些名称或名称来记住新的提交。
使用c9584e75521a3b94d4f883a246aad134b83dc12d
时,接收者(您!),或者说是Git,会更新您的远程跟踪名称。您以他们的名字boilerplate/phaser3
为名,并以您的远程名字git fetch
为前缀,并在两者之间加一个斜杠。这样您就可以git push
来记住他们的提交了。
使用git fetch
时,发送者(再次由您负责)要求接收者在接收者中设置一些名称。 您选择您要求他们设置的名称。如果该名称是phaser3
,那么您是在要求他们更改 他们的 boilerplate
。他们没有远程跟踪名称:此处没有boilerplate/phaser3
。您要他们更改他们的名称。因此,通常,您应该确保无论您发送给他们的是什么新提交,这些新提交都将其现有提交作为历史记录的一部分。