如何拉不同的远程分支并合并冲突

时间:2019-03-20 19:32:27

标签: git git-remote boilerplate

我已经使用seed来启动项目并添加了更改,首先克隆种子项目,进行编辑并将remoteorigin更改为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分支之间有何不同?

1 个答案:

答案 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_HEADgit 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 showgit log,而那些 compare 提交给较早的提交,以便我们可以看到两个快照中的不同之处。这就像将今天的温暖或多雨与昨天的温暖或多雨进行比较:它告诉我们发生了什么变化,这对我们来说有时比绝对状态更重要。但这确实显示了提交中的内容:它有一个 tree (带有一些内部Git哈希ID),一个 parent 和另一个提交的hash ID,以及作者和提交者并记录消息。 (有些提交有更多内容。)Git就是通过树来存储快照的。 parent行告诉我们哪个提交在此提交之前。

结果是,给定了一些Git提交哈希ID,Git总是可以找到在之前的提交。实际上,父行指向另一个较早的提交。因此,如果我们有很长的提交链:

... <-F <-G <-H ...

我们可以选择以下提交之一,并沿其箭头向后退到上一个提交:从HG,然后到F,然后等等。

这里的问题是这些散列ID完全随机出现,并且部分取决于某人制造它们的时间,精确到秒。例如,Thomas Gleixner在时间1533300299 +0200进行了提交。 1 所有这些详细信息都进入了提交哈希ID。这意味着我们无法知道哈希ID是什么-它是有效随机的。那么我们怎么知道 latest 提交是哪个提交?

答案是Git通过让我们创建分支名称帮助我们。我们告诉Git:以诸如masterphaser3 之类的名称存储最新/最新提交的哈希ID。给定 ID ,Git可以找到提交本身。该提交存储了一个父ID,因此Git也可以找到该父ID。父级存储另一个父级ID(实际上就是该提交的祖父母),以便Git可以找到该祖父级,并且该提交存储了另一个父级ID,依此类推。

事实上,历史不过是通过从每个提交转到其父目录而找到的一组提交。从一些起点开始,并进行反向访问,这些提交 是Git存储库中的历史。起点是存储库中的所有名称:分支名称,标签名称(如v2.1远程跟踪名称(如origin/master或{ {1}}。 2


1 好,那是他创作(原始版本的)提交,但后来他提交该提交在1533302341, 34分钟2秒后。

2 存储库可以在经过boilerplate/phaser3git 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所做的只是在您的存储库中浏览 {}分支的 { / 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/feature2J develop都有一个- / p>

origin

我的Git会放弃,因为它不知道是否应该从upstreamgit checkout develop 制作新的develop。即使它们都标识了 same 提交(例如,我在图中未绘制的origin/develop提交),我的Git也不知道这两个中的哪个用作<我的新upstream/develop的em>上游设置。我在这里可以做的是:

L

告诉我的Git:使用develop,新建一个git checkout --track origin/develop ,其中origin/developdevelop的{​​{1}更新并推送到}。

我们在这里进行的非常快,并没有详细说明所有的工作原理,但是我会在这里再次提及,这将设置新创建的上游设置科。分支的上游是当您运行develop时Git如何决定说“超前”和/或“落后”,以及如果您运行origin或{{1}时Git如何知道要使用哪些提交},不带参数。上游指示developgit 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-webpackphaser3命令是将提交从一个存储库转移到另一个存储库的命令。通常,发送方发送提交者尚未收到的提交,因此最终,接收方拥有发送者所拥有的一切,如果发送者已经拥有了东西,则可能还要更多。将提交从发送方发送到接收方之后,接收方现在需要更新一些名称或名称来记住新的提交。

使用c9584e75521a3b94d4f883a246aad134b83dc12d时,接收者(您!),或者说是Git,会更新您的远程跟踪名称。您以他们的名字boilerplate/phaser3为名,并以您的远程名字git fetch为前缀,并在两者之间加一个斜杠。这样您就可以git push来记住他们的提交了。

使用git fetch时,发送者(再次由您负责)要求接收者在接收者中设置一些名称。 选择您要求他们设置的名称。如果该名称是phaser3,那么您是在要求他们更改 他们的 boilerplate。他们没有远程跟踪名称:此处没有boilerplate/phaser3。您要他们更改他们的名称。因此,通常,您应该确保无论您发送给他们的是什么新提交,这些新提交都将其现有提交作为历史记录的一部分。

相关问题