【问题标题】:Is it possible to cherry-pick a commit from another git repository?是否可以从另一个 git 存储库中挑选提交?
【发布时间】:2011-07-04 10:50:02
【问题描述】:

我正在使用一个 git 存储库,该存储库需要来自另一个对第一个一无所知的 git 存储库的提交。

通常我会在 reflog 中使用 HEAD@{x} 进行挑选,但因为这个 .git 对这个 reflog 条目(不同的物理目录)一无所知,我该如何挑选呢,或者我可以吗?

我正在使用git-svn。我的第一个分支是使用 Subversion 存储库的 trunk 中的 git-svn,下一个分支是在 Subversion 分支上使用 git-svn

【问题讨论】:

  • 这是Ben Lee 在这个问题上开悬赏的原因:“我要把悬赏奖励给正确的答案,而不是接受的答案。我只需要等待 24 [小时] 这样做。”但是,我不明白其中哪些应该是“正确答案”,以及为什么接受的答案不是“正确”。
  • 不清楚问题的本质是什么。如果有的话,这些不同的回购有什么关系?一个是另一个的叉子吗?还是它们实际上是两个完全独立且不相关的项目?
  • @Cupcake,接受的答案很好,显然对OP有帮助,所以应该接受。我所说的“正确”实际上只是指“适合我”(根据 cmets 判断,也适合其他几个人)。我只是认为我给予赏金的人应该得到与接受的答案一样多的代表。

标签: git cherry-pick


【解决方案1】:

给出的答案是使用格式补丁,但由于问题是如何从另一个文件夹中挑选,这里有一段代码可以做到这一点:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

来自马聪comment Aug 28 '14的解释

git format-patch 命令从 some_other_repo 的提交中创建一个补丁 由其 SHA 指定(-1 仅用于单个提交)。这个补丁是 管道传送到 git am,它在本地应用补丁(-3 表示尝试 如果补丁无法完全应用,则进行三向合并)。

【讨论】:

  • 这是正确的,但如果有人可以对此进行扩展,那就太好了 - 详细说明正在发生的事情(尤其是那些标志)将非常有用。
  • @NickF,git format-patch 命令从some_other_repo 的 SHA 指定的提交创建补丁(-1 仅用于单个提交)。此补丁通过管道传送到git am,后者在本地应用补丁(-3 表示如果补丁无法干净地应用,则尝试三向合并)。希望能解释清楚。
  • 错误:补丁失败:somefile.cs:85 错误:somefile.cs:补丁不适用 您是否手动编辑了补丁?它不适用于记录在其索引中的 blob。不能回退到三向合并。补丁在 0001 处失败 添加了 GUI 部件。失败的补丁副本位于:/.git/rebase-apply/patch 解决此问题后,运行“git am --continue”。如果您希望跳过此补丁,请运行“git am --skip”。要恢复原始分支并停止修补,请运行“git am --abort”。
  • @Tom 尝试使用--ignore-whitespace。完整命令:git --git-dir=../&lt;some_other_repo&gt;/.git format-patch -k -1 --stdout &lt;commit SHA&gt; | git am -3 -k --ignore-whitespace
  • @BoomShadow 因为它更简单。添加远程和获取会带来所有其他 repo 的更改。此命令行是一次性操作。
【解决方案2】:

您需要将另一个存储库添加为远程,然后获取其更改。从那里你可以看到提交,你可以挑选它。

像这样:

git remote add other https://example.link/repository.git
git fetch other

现在您拥有所有信息,只需执行git cherry-pick

完成后,如果您不再需要它,您可能需要再次移除遥控器,使用

git remote remove other

在此处了解有关使用遥控器的更多信息:https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

【讨论】:

  • 如果我使用 git-svn 怎么办?我的第一个分支正在使用主干的 git-svn,下一个是在分支上使用 git-svn(感谢您的快速回复)
  • 如果您使用 Github,您可以通过将 .patch 附加到提交 URL 来拉取补丁,然后使用 git am &lt; d821j8djd2dj812.patch 应用它。在 GH 之外,可以按照下面的替代答案中的参考来完成类似的概念。
  • @radicand 下面哪个答案是“替代”答案?请链接到它。
  • 从另一个 repo 中挑选樱桃的详细步骤:coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
  • 您实际上并不需要添加遥控器。抓取就足够了。 ../&lt;some_other_repo&gt;/ 是一个非常好的 uri,如果你的磁盘上已经有 repo。
【解决方案3】:

这是一个远程提取合并的示例。

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

那么你可以:

git cherry-pick <first_commit>..<last_commit>

或者您甚至可以合并整个分支(仅当您确实需要合并所有内容时)

git merge projectB/master

【讨论】:

  • git merge projectB/master 非常非常错误,因为您没有应用来自单个提交的更改(就像樱桃选择会),您实际上是在合并projectB/master 中的所有更改,这些更改不包含在您自己的master 分支中。
  • 这是我的假设,这是原始发布者的意图。否则,是的,这不是他们的正确选择。
  • 这在两个存储库相关时非常有效。
  • 我从 git 存储库创建了一个副本(只是为了“玩”而不破坏原始存储库)并使其与源保持最新,Brian 的答案正是我需要,所以,Cupcake,我不得不说,这不是“错误”,而是另一个用例。但是你很高兴指出潜在的灾难:D
  • IMO 这需要成为公认的解决方案。 此外,如果您想在完成挑选后删除遥控器,请使用git remote rm projectB。还可以使用git tag -d tag-name 删除从远程仓库获取的任何标签。远程提交将不再显示在您的历史记录中,并且修剪最终会将它们从存储中删除。
【解决方案4】:

您可以做到,但需要两个步骤。方法如下:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

&lt;remote-git-url&gt; 替换为您想要从中挑选的存储库的 url 或路径。

&lt;branch&gt; 替换为您要从远程存储库中挑选的分支或标记名称。

您可以用分支中的 git SHA 替换 FETCH_HEAD

更新:根据@pkalinow 的反馈修改。

【讨论】:

  • 它适用于分支名称,但不适用于 SHA。如果您想挑选由其哈希表示的提交,请改用:git fetch &lt;repo-url&gt; &lt;branch&gt; &amp;&amp; git cherry-pick &lt;sha&gt;
  • 谢谢。这正是我需要将多个提交从一个存储库插入到另一个存储库的内容,我为此创建了该存储库。
  • 这正是我为不同客户(每个客户都有自己的存储库/分叉)的许多自定义代码实现所需要的,我们需要一种将特定提交放入我们的基础/主干的方法。谢谢!
  • 这应该是跨回购的一次性樱桃挑选的公认答案。我一直在选择已经是本地的 repos 时使用它,远程 URL 只是一个本地文件系统路径。
  • 如果您最熟悉cherry-pick,这可能是最简单的。您不需要添加完整的遥控器(尽管您可以,如果您要经常这样做)。只需获取您需要获取本地引用的分支(可以来自另一个本地目录或远程 URL),然后选择提交。
【解决方案5】:

以下是添加远程、获取分支和挑选提交的步骤

# Cloning our fork
$ git clone git@github.com:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

来源:https://coderwall.com/p/sgpksw

【讨论】:

    【解决方案6】:

    How to create and apply a patch with Git。 (从您问题的措辞来看,我假设这个其他存储库用于完全不同的代码库。如果它是相同代码库的存储库,您应该按照@CharlesB 的建议将其添加为远程。即使它是另一个代码库,我想您仍然可以将其添加为远程,但您可能不想将整个分支放入您的存储库中......)

    【讨论】:

      【解决方案7】:

      您可以按照以下方式在一行中完成。希望您在 git 存储库中需要精心挑选的更改,并且您已签出正确的分支。

      git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
      # 
      

      git fetch [branch URL] [branch to cherry-pick from] && git cherry-pick [commit ID]

      【讨论】:

        【解决方案8】:

        是的。获取存储库,然后从远程分支中挑选。

        【讨论】:

          【解决方案9】:

          假设 A 是您要从中挑选的仓库,B 是您要挑选的仓库,您可以通过将 &lt;/path/to/repo/A/&gt;/.git/objects 添加到 &lt;/path/to/repo/B&gt;/.git/objects/info/alternates 来做到这一点。如果此alternates 文件不存在,请创建它。

          这将使 repo B 访问 repo A 中的所有 git 对象,并使cherry-pick 为您工作。

          【讨论】:

            【解决方案10】:

            对于这种情况,对于某些本地化验证,必须“挑选”提交。 对于相同的存储库签出,也可能是本地提交(即尚未推送到服务器)。

            例如

            • repo1 similar 到 repo2
            • repo1 有分支 b1 - HEAD 在本地进行了 2 次提交(包括 commit_x)。
            • repo2 有分支 bb1 - 需要 to cherry-pick commit_x。

            为此,

            $ cd repo2

            repo2 $ git fetch

            repo2 $ git cherry-pick

            在上述情况下,commit_x 现在可以识别并被拾取(借助 fetch)。

            【讨论】:

              【解决方案11】:

              我的情况是,我有一个团队推送到的裸仓库,以及它旁边的一个克隆。 Makefile 中的这组行对我来说可以正常工作:

              git reset --hard
              git remote update --prune
              git pull --rebase --all
              git cherry-pick -n remotes/origin/$(BRANCH)
              

              通过保持裸 repo 的 master 为最新状态,我们能够挑选出发布到裸 repo 的提议更改。我们还有一种(更复杂的)方法来挑选多个分支进行综合审查和测试。

              如果“什么都不知道”意味着“不能用作遥控器”,那么这无济于事,但是当我在谷歌上搜索这个工作流程时出现了这个 SO 问题,所以我想我会回馈。

              【讨论】:

              • -n 表示根据 git docs 不提交,在提交之前查看更改非常重要
              【解决方案12】:

              如果您想为给定文件挑选多个提交,直到达到给定提交,请使用以下内容。

              # Directory from which to cherry-pick
              GIT_DIR=...
              # Pick changes only for this file
              FILE_PATH=...
              # Apply changes from this commit
              FIST_COMMIT=master
              # Apply changes until you reach this commit
              LAST_COMMIT=...
              
              for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
                git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
                  git am -3 -k
              done
              

              【讨论】:

                猜你喜欢
                • 2016-09-13
                • 2015-09-14
                • 1970-01-01
                • 2019-04-10
                • 1970-01-01
                • 2016-09-25
                • 2012-10-05
                • 1970-01-01
                • 2019-01-19
                相关资源
                最近更新 更多