为什么 Git 合并命令给我不同的输出
Why Git merge command gives me different ouptut
我已经使用 Git 一年了,今天我在合并分支时偶然发现了一件令人困惑的事情。这是我本地的 .config 文件部分:
[branch "develop"]
remote = origin
merge = refs/heads/develop
[branch "Feature/Sprint4.4/mybranch"]
remote = origin
merge = refs/heads/Feature/Sprint4.4/mybranch
现在我在本地分支mybranch。我按顺序执行了以下命令。
1) git pull
--> 2d6cf1e..655001e develop -> origin/develop
--> already up-to-date
2) git merge origin develop
--> already up-to-date
3) git merge origin/develop
--> merge made by recursive strategy...
....(all the changes were indicated)
7 files changed, 202 insertions(+), 181 deletions(-)
我的问题是上面的命令 (2) 和 (3) 之间的确切区别是什么,为什么输出会改变?
我知道我可以阅读 Git 文档和其他书籍,但寻找更简单语言的答案。
你在mybranch
1) git pull // This will pull changes from origin and write them into your my branch.(It will fetch for your develop branch)
--> 2d6cf1e..655001e develop -> origin/develop
--> already up-to-date
2) git merge origin develop // This will take almost no effect as you already pulled as it shows develop -> origin/develop
// This is same as git merge origin/develop develop
--> already up-to-date
3) git merge origin/develop // This will merge changes from origin/develop to mybranch
// This is same as git merge origin/develop mybranch
--> merge made by recursive strategy...
....(all the changes were indicated)
7 files changed, 202 insertions(+), 181 deletions(-)
我看到这已经得到回答和接受,但我认为接受的答案中缺少一个关键点。
你几乎不想 运行 git merge
有超过 一个 个附加参数。
换句话说,git merge origin develop
很少是个好主意;不要那样做。要了解原因,请继续阅读。
git pull
和 git merge
采用不同的参数
确实(即正确)git pull
只是 运行s git fetch
后跟 git merge
(或者,如果您指示它,git pull
后跟 git rebase
)。棘手的部分是如何它运行它们,并且pull
命令通常需要两个参数:
$ git 拉 <em>远程</em> <em>refspec</em>
但是merge
命令一般需要一个:
$git合并<em>提交</em>
注意这里的名字(remote
,refspec
,和commit
)都是不同的:这是理解命令的关键之一。另外,在谈论使用的参数数量时请注意 "generally" 一词:有时可以省略一些参数,或者使用更多参数。
什么是"remote"?
在最简单的形式中,遥控器只是一个名称,如 origin
,它指的是 git 配置文件 (.git/config
) 中的一个条目。 pull
脚本有很长的使用它的替代方法的历史,所以你可以把其他东西放在这里,但只要你只使用这些名字,事情就很好并且不那么混乱,所以让我们把它留在那。
什么是"refspec"?
一个完整的参考规范最多包含三个部分。这三者对于 git push
都很重要,但对于 git fetch
就没那么重要了,而且由于 git pull
运行s git fetch
,我们可以使用最简单的版本,即只是一个 b运行ch 或标签名称。当使用 git fetch
(因此也是 git pull
)时,您提供的 b运行ch 名称是遥控器上 b运行ch 的名称。因此:
git拉原点<em>b运行ch</em>
让你的 git 联系遥控器 origin
并询问它的 b运行ch 名为 branch
.
假设 b运行ch 名称存在于遥控器上,您的 git 将获得该 b运行ch 的最新版本(通常,更新 refs/remotes/origin/<em>b运行ch</em>
,至少如果你有 git 版本 1.8.4 或更高版本——那是,使用更新版本的 git,您的 "remote-tracking branches" 总是会更新)。
作为git pull
依赖的副作用,git fetch
也写入所有更新的b运行ch信息1 到 git 的私有 (.git
) 目录中名为 FETCH_HEAD
的文件。您真正需要知道的唯一一件事是 pull
脚本使用它(但如果您愿意,您可以阅读文件的内容)。
到目前为止的总结:git pull
运行s git fetch
并将更新存储在 FETCH_HEAD
中,有时也会存储在您的"remote-tracking branches" 像 origin/master
和 origin/develop
等等。
使用git merge
现在让我们继续git merge
。
我上面说了它"generally"需要三个参数,git merge <em>commit</em>
.
pull
命令总是给出 merge
三个参数(和很多标志,包括一些提供合并提交消息的标志)。 pull
脚本从 FETCH_HEAD
文件中获取 commit 参数——就此而言,合并提交消息。2
如果您想手动执行此操作,可以像 pull
脚本一样执行此操作,但提取和输入长 SHA-1 ID 会很痛苦。而且,无论如何,你想要做的是合并一个不同的 localb运行ch,而不是 localb运行ch,而不是 fetch
步.
这是您最初输入命令时出错的地方:
git merge origin develop
这将 两个 个参数传递给 merge
。它们都被视为提交 ID,这告诉 git merge
做一些叫做 "octopus merge" 的事情。除非你是高级 git 大师,否则你可能不想这样做。 (幸运的是,在您的情况下,鉴于您提供给 git 的多个提交 ID,无论如何都无事可做。)
我会在这里指出 origin
不像 看起来像提交 ID,develop
也不像 SHA-1。但实际上,这两个名称 do 都指定了特定的提交——如果它们没有指定,您会从 git merge
命令中收到一条错误消息。要找出 哪个 提交,您可以使用命令 git rev-parse
:
$ git rev-parse origin
a17c56c056d5fea0843b429132904c429a900229
(你的不匹配这个SHA-1,但是思路应该够清楚了)。 b运行ch 名称也解析为原始 SHA-1——我没有 develop
但我有 master
和 origin/master
所以我会在这里使用它们:
$ git rev-parse master
a17c56c056d5fea0843b429132904c429a900229
$ git rev-parse origin/master
a17c56c056d5fea0843b429132904c429a900229
(在这种情况下,两者相同,因为我的 master
现在是 origin/master
的最新版本)。
通常,b运行ch 名称解析为 b运行ch 末尾的提交。
我会重复一遍,因为它是理解 git 的另一个关键。 A b运行ch 名称解析为 b运行ch 顶端的提交, 有一个非常大且非常重要的例外,即在执行 git checkout
。由于 git checkout
是人们对 git 所做的第一件事,他们了解到 b运行ch 名称是特殊的——这对于 git checkout
是正确的,但对于大多数其他名称则不然git 命令。大多数命令只是将名称转换为原始 SHA-1,当它们这样做时,它们会得到 b运行ch.
的提示
git merge origin/develop
运行 git merge
带有符号名称,如 origin/develop
,是相当合理的:git 会为你查找原始提交 ID,并将设置默认的合并消息使用符号名称,这对以后阅读日志的人来说意义更大。如果您使用原始提交 ID,您将在日志中获得它。
合并总结: git merge origin/develop
是合理的做法。这意味着 "find the tip commit of origin/develop
and merge that, as a regular merge." 然而,git merge origin develop
不是 一个好主意,因为它意味着 "find the tip commits of origin
and develop
and do an octopus merge of those two commits."
1当你使用四参数形式时,git fetch <em>remote</em> <em>refspec</em>
,fetch
步骤只带来 你要求的 b运行ch。使用三个参数,即 git fetch <em>remote</em>
,fetch
步骤通常会带来所有 b运行切。只有两个参数,git fetch
通常会根据需要自动从 origin
中获取,并再次带来所有 b运行ches。因此,您通常可以 运行 git fetch
.
2如果您检查该文件,您会看到如下内容:
a17c56c056d5fea0843b429132904c429a900229 branch 'master' of [url]
您可能还会看到更多行,例如:
ca00f80b58d679e59fc271650f68cd25cdb72b09 not-for-merge branch 'maint' of [url]
(或者你可能不会)——这就是 git fetch
带来的所有东西。在这种特殊情况下,我 运行 git pull
没有参数,它带来了 master
和 maint
(以及更多项目)。所有提交 ID 都在 FETCH_HEAD
中结束,然后 pull
脚本通过排除所有标记为 [=264] 的内容来提取 是 "for merge" 的那个=].
我已经使用 Git 一年了,今天我在合并分支时偶然发现了一件令人困惑的事情。这是我本地的 .config 文件部分:
[branch "develop"]
remote = origin
merge = refs/heads/develop
[branch "Feature/Sprint4.4/mybranch"]
remote = origin
merge = refs/heads/Feature/Sprint4.4/mybranch
现在我在本地分支mybranch。我按顺序执行了以下命令。
1) git pull
--> 2d6cf1e..655001e develop -> origin/develop
--> already up-to-date
2) git merge origin develop
--> already up-to-date
3) git merge origin/develop
--> merge made by recursive strategy...
....(all the changes were indicated)
7 files changed, 202 insertions(+), 181 deletions(-)
我的问题是上面的命令 (2) 和 (3) 之间的确切区别是什么,为什么输出会改变?
我知道我可以阅读 Git 文档和其他书籍,但寻找更简单语言的答案。
你在mybranch
1) git pull // This will pull changes from origin and write them into your my branch.(It will fetch for your develop branch)
--> 2d6cf1e..655001e develop -> origin/develop
--> already up-to-date
2) git merge origin develop // This will take almost no effect as you already pulled as it shows develop -> origin/develop
// This is same as git merge origin/develop develop
--> already up-to-date
3) git merge origin/develop // This will merge changes from origin/develop to mybranch
// This is same as git merge origin/develop mybranch
--> merge made by recursive strategy...
....(all the changes were indicated)
7 files changed, 202 insertions(+), 181 deletions(-)
我看到这已经得到回答和接受,但我认为接受的答案中缺少一个关键点。
你几乎不想 运行 git merge
有超过 一个 个附加参数。
换句话说,git merge origin develop
很少是个好主意;不要那样做。要了解原因,请继续阅读。
git pull
和 git merge
采用不同的参数
确实(即正确)git pull
只是 运行s git fetch
后跟 git merge
(或者,如果您指示它,git pull
后跟 git rebase
)。棘手的部分是如何它运行它们,并且pull
命令通常需要两个参数:
$ git 拉 <em>远程</em> <em>refspec</em>
但是merge
命令一般需要一个:
$git合并<em>提交</em>
注意这里的名字(remote
,refspec
,和commit
)都是不同的:这是理解命令的关键之一。另外,在谈论使用的参数数量时请注意 "generally" 一词:有时可以省略一些参数,或者使用更多参数。
什么是"remote"?
在最简单的形式中,遥控器只是一个名称,如 origin
,它指的是 git 配置文件 (.git/config
) 中的一个条目。 pull
脚本有很长的使用它的替代方法的历史,所以你可以把其他东西放在这里,但只要你只使用这些名字,事情就很好并且不那么混乱,所以让我们把它留在那。
什么是"refspec"?
一个完整的参考规范最多包含三个部分。这三者对于 git push
都很重要,但对于 git fetch
就没那么重要了,而且由于 git pull
运行s git fetch
,我们可以使用最简单的版本,即只是一个 b运行ch 或标签名称。当使用 git fetch
(因此也是 git pull
)时,您提供的 b运行ch 名称是遥控器上 b运行ch 的名称。因此:
git拉原点<em>b运行ch</em>
让你的 git 联系遥控器 origin
并询问它的 b运行ch 名为 branch
.
假设 b运行ch 名称存在于遥控器上,您的 git 将获得该 b运行ch 的最新版本(通常,更新 refs/remotes/origin/<em>b运行ch</em>
,至少如果你有 git 版本 1.8.4 或更高版本——那是,使用更新版本的 git,您的 "remote-tracking branches" 总是会更新)。
作为git pull
依赖的副作用,git fetch
也写入所有更新的b运行ch信息1 到 git 的私有 (.git
) 目录中名为 FETCH_HEAD
的文件。您真正需要知道的唯一一件事是 pull
脚本使用它(但如果您愿意,您可以阅读文件的内容)。
到目前为止的总结:git pull
运行s git fetch
并将更新存储在 FETCH_HEAD
中,有时也会存储在您的"remote-tracking branches" 像 origin/master
和 origin/develop
等等。
使用git merge
现在让我们继续git merge
。
我上面说了它"generally"需要三个参数,git merge <em>commit</em>
.
pull
命令总是给出 merge
三个参数(和很多标志,包括一些提供合并提交消息的标志)。 pull
脚本从 FETCH_HEAD
文件中获取 commit 参数——就此而言,合并提交消息。2
如果您想手动执行此操作,可以像 pull
脚本一样执行此操作,但提取和输入长 SHA-1 ID 会很痛苦。而且,无论如何,你想要做的是合并一个不同的 localb运行ch,而不是 localb运行ch,而不是 fetch
步.
这是您最初输入命令时出错的地方:
git merge origin develop
这将 两个 个参数传递给 merge
。它们都被视为提交 ID,这告诉 git merge
做一些叫做 "octopus merge" 的事情。除非你是高级 git 大师,否则你可能不想这样做。 (幸运的是,在您的情况下,鉴于您提供给 git 的多个提交 ID,无论如何都无事可做。)
我会在这里指出 origin
不像 看起来像提交 ID,develop
也不像 SHA-1。但实际上,这两个名称 do 都指定了特定的提交——如果它们没有指定,您会从 git merge
命令中收到一条错误消息。要找出 哪个 提交,您可以使用命令 git rev-parse
:
$ git rev-parse origin
a17c56c056d5fea0843b429132904c429a900229
(你的不匹配这个SHA-1,但是思路应该够清楚了)。 b运行ch 名称也解析为原始 SHA-1——我没有 develop
但我有 master
和 origin/master
所以我会在这里使用它们:
$ git rev-parse master
a17c56c056d5fea0843b429132904c429a900229
$ git rev-parse origin/master
a17c56c056d5fea0843b429132904c429a900229
(在这种情况下,两者相同,因为我的 master
现在是 origin/master
的最新版本)。
通常,b运行ch 名称解析为 b运行ch 末尾的提交。
我会重复一遍,因为它是理解 git 的另一个关键。 A b运行ch 名称解析为 b运行ch 顶端的提交, 有一个非常大且非常重要的例外,即在执行 git checkout
。由于 git checkout
是人们对 git 所做的第一件事,他们了解到 b运行ch 名称是特殊的——这对于 git checkout
是正确的,但对于大多数其他名称则不然git 命令。大多数命令只是将名称转换为原始 SHA-1,当它们这样做时,它们会得到 b运行ch.
git merge origin/develop
运行 git merge
带有符号名称,如 origin/develop
,是相当合理的:git 会为你查找原始提交 ID,并将设置默认的合并消息使用符号名称,这对以后阅读日志的人来说意义更大。如果您使用原始提交 ID,您将在日志中获得它。
合并总结: git merge origin/develop
是合理的做法。这意味着 "find the tip commit of origin/develop
and merge that, as a regular merge." 然而,git merge origin develop
不是 一个好主意,因为它意味着 "find the tip commits of origin
and develop
and do an octopus merge of those two commits."
1当你使用四参数形式时,git fetch <em>remote</em> <em>refspec</em>
,fetch
步骤只带来 你要求的 b运行ch。使用三个参数,即 git fetch <em>remote</em>
,fetch
步骤通常会带来所有 b运行切。只有两个参数,git fetch
通常会根据需要自动从 origin
中获取,并再次带来所有 b运行ches。因此,您通常可以 运行 git fetch
.
2如果您检查该文件,您会看到如下内容:
a17c56c056d5fea0843b429132904c429a900229 branch 'master' of [url]
您可能还会看到更多行,例如:
ca00f80b58d679e59fc271650f68cd25cdb72b09 not-for-merge branch 'maint' of [url]
(或者你可能不会)——这就是 git fetch
带来的所有东西。在这种特殊情况下,我 运行 git pull
没有参数,它带来了 master
和 maint
(以及更多项目)。所有提交 ID 都在 FETCH_HEAD
中结束,然后 pull
脚本通过排除所有标记为 [=264] 的内容来提取 是 "for merge" 的那个=].