【问题标题】:Why Git merge command gives me different ouptut为什么 Git 合并命令给了我不同的输出
【发布时间】:2015-10-25 11:29:29
【问题描述】:

我已经使用 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 文档和其他书籍,但可以寻找更简单的语言的答案。

【问题讨论】:

  • 你检查this了吗?
  • git merge origin develop 会将源合并到您的本地主服务器中。 git merge origin/develop 会将 origin/develop 合并到您本地的 mybranch 中。
  • @Jan 我认为您提供的链接与我不相关,因为我正在拉取然后使用具有不同语义的合并,这就是我想知道的区别。
  • @Foolish 我没有明白你所说的本地大师的意思,我没有 master 分支。只有开发和其他本地分支。命令(2)中的develop参数如果将更改合并到本地master中意味着什么?
  • 对不起,我的意思是develop。认为它是开发而不是掌握。

标签: git git-merge


【解决方案1】:

我看到这已经被回答并接受了,但我认为接受的答案缺少关键的一点。

你几乎不想运行git merge 有多个一个个额外的参数。

换句话说,git merge origin develop 很少是一个好主意;不要那样做。要了解原因,请继续阅读。


git pullgit merge 采用不同的参数

git pull 确实(即,它是正确的)只是运行 git fetch 后跟 git merge(或者,如果您指示它,git pull 后跟 git rebase)。棘手的部分是如何运行它们,并且pull 命令通常需要两个参数:

$ git pull <em>remote</em> <em>refspec</em>

merge 命令一般需要一个

$ git merge <em>commit</em>

注意这里的名字(remoterefspeccommit)都是不同的: 这是理解命令的关键之一。另外,在谈到使用的参数数量时,请注意“一般”一词:有时可以省略一些参数,或者使用更多参数。

什么是“远程”?

在最简单的形式中,远程只是一个名称,如origin,它引用您的 git 配置文件 (.git/config) 中的条目。 pull 脚本有很长的使用它的替代方法的历史,所以你可以把其他的东西放在这里,但只要你使用这些名字,事情就会很好地工作并且不那么混乱,所以让我们把它留在那里。

什么是“参考规范”?

完整的 refspec 最多包含三个部分。所有这三个对于git push 都很重要,但对于git fetch 则更重要,并且由于git pull 运行git fetch,我们可以使用最简单的版本,它只是一个分支或标签名称。当使用git fetch(因此也使用git pull)时,您提供的分支名称是远程上的分支名称。因此:

git pull origin <em>branch</em>

让你的 git 联系远程 origin 并询问其名为 branch 的分支。

假设分支名称存在于远程,您的 git 将获取该分支的最新版本(并且通常也会更新 refs/remotes/origin/<em>branch</em>,至少如果您的 git 版本为 1.8.4 或更高版本 - 也就是说,使用较新版本的 git,您的“远程跟踪分支”总是会更新)。

作为git pull 所依赖的副作用,git fetch 将其所有更新的分支信息1 写入 git 私有 ( .git) 目录。您真正需要了解的唯一一件事是 pull 脚本使用它(但您可以根据需要阅读文件的内容)。

到目前为止的总结:git pull 运行 git fetch 并将更新存储在 FETCH_HEAD,有时还存储在您的“远程跟踪分支”中,例如 origin/masterorigin/develop 等等开。


使用git merge

现在让我们转到git merge

我在上面说过,它“通常”需要三个参数,git merge <em>commit</em>

pull 命令总是给merge 三个参数(以及很多标志,包括一些提供合并提交消息的标志)。 pull 脚本从 FETCH_HEAD 文件中获取 commit 参数以及合并提交消息。2

如果您想手动执行此操作,您可以像 pull 脚本一样执行此操作,但提取和输入长 SHA-1 ID 会很痛苦。而且,无论如何,您想要做的是合并一个不同的 本地 分支,而不是由 fetch 步骤带来的提交的原始 SHA-1。

这是您最初输入命令时出错的地方:

git merge origin develop

这会将两个参数传递给merge。它们都被视为提交 ID,这告诉 git merge 执行称为“章鱼合并”的操作。除非您是高级 git 大师,否则您可能不想这样做。 (幸运的是,考虑到您给 git 的多个提交 ID,就您而言,无论如何都无事可做。)

我会在这里注意到origin 确实 看起来像一个提交ID,并且develop 也不像一个SHA-1。但事实上,这两个名称都确实 命名了特定的提交——如果它们没有,你会从你的git merge 命令中得到一个错误消息。要找出哪些提交,您可以使用命令git rev-parse

$ git rev-parse origin
a17c56c056d5fea0843b429132904c429a900229

(你的不会匹配这个 SHA-1,但这个想法应该足够清楚)。分支名称也解析为原始 SHA-1——我没有 develop,但我有 masterorigin/master,所以我将在这里使用它们:

$ git rev-parse master
a17c56c056d5fea0843b429132904c429a900229
$ git rev-parse origin/master
a17c56c056d5fea0843b429132904c429a900229

(在这种情况下,这两个是相同的,因为我的master 现在是最新的origin/master)。

通常,分支名称解析为分支顶端的提交。

我会重复一遍,因为它是理解 git 的另一个关键。 分支名称解析为分支顶端的提交,有一个非常大且非常重要的例外,即在执行git checkout 时。由于git checkout 是人们使用 git 做的第一件事,他们知道分支名称是特殊的——git checkout 是这样,但对于大多数其他 git 命令来说却不是。大多数命令只是将名称转换为原始 SHA-1,当它们这样做时,它们会得到分支的尖端。

git merge origin/develop

用符号名运行git merge,比如origin/develop,是很合理的:git会为你查找原始提交ID,并设置默认的合并消息使用符号名,这意味着更多给稍后阅读日志的人。如果您使用原始提交 ID,您会在日志中得到它。

合并总结: git merge origin/develop 是一个合理的做法。这意味着“找到origin/develop 的提示提交并将其合并,作为常规合并。”但是,git merge origin develop不是一个好主意,因为它意味着“找到 origindevelop 的提示提交,并对这两个提交进行章鱼合并。”


1当您使用四参数形式git fetch <em>remote</em> <em>refspec</em> 时,fetch 步骤带来您要求的一个分支。使用三个参数,即git fetch <em>remote</em>fetch 步骤通常会带来所有分支。只需两个参数,git fetch 通常会根据需要自动从origin 获取,并再次带来所有分支。因此,您通常可以只运行git fetch

2如果您检查文件,您会看到如下内容:

a17c56c056d5fea0843b429132904c429a900229        branch 'master' of [url]

您可能还会看到更多行,例如:

ca00f80b58d679e59fc271650f68cd25cdb72b09    not-for-merge   branch 'maint' of [url]

(或者你可能不会)——这就是git fetch 带来的所有东西。在这种特殊情况下,我运行git pull 没有参数,它带来了mastermaint(以及更多项目)。所有提交 ID 都在 FETCH_HEAD 中结束,然后 pull 脚本通过排除所有标记为“不合并”的提交 ID 来提取 “合并”的提交 ID。

【讨论】:

    【解决方案2】:

    你在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(-)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 2023-03-14
      • 1970-01-01
      • 2016-10-10
      相关资源
      最近更新 更多