将分支A的更改应用到B分支,而不进行合并或添加提交。

137

我的情况是我有一个分支,我在其中已经对构建过程进行了大量改进(分支A),而在另一个分支中,我正在开发一个不相关的功能(分支B)。现在当我在分支B上工作时,我想将我在分支A中编写的内容拉入分支B,因为我想要更快速、更简单的构建。但是,我不想“污染”我的分支B,只是将分支A的更改添加到未暂存的更改中。

我尝试过的方法(当处于分支B时):

git merge --no-commit branchA

不能正常工作,因为它将您置于合并之内。如果不是这样,它就会完美无缺。

git checkout branchA -- .

无法工作,因为它应用的是分支A..分支B之间的更改,而不是主分支..分支A之间的更改。

还有其他事情吗?

编辑:是的,分支A上的更改已经提交。在这个例子中只有一个带有构建改进的分支,但可能会有多达N个带有构建改进的分支,我想在处理一个功能分支时应用它们。

7个回答

237

我之前也遇到过类似的问题,通过在合并命令中加入 --squash 参数,我成功地解决了它。

git merge --no-commit --squash branchA
git reset HEAD # to unstage the changes

6
这也应该有一个解释说明它正在做什么。它将分支A的更改差异暂存到您当前的分支中。 - KareemElashmawy
假设我刚将branchA的代码合并到主分支(master)中,但我忘记了一些东西,想要在这个合并提交中添加更多的代码/更改,而不会在git历史记录中显示为另一个合并提交。这种方法可行吗? - Sushmit Sagar
@Sushmit 我认为你可以使用 git commit --amend 命令,它将把新的更改附加到上次提交中。我不确定这是否适用于合并提交。 - guilffer
4
这里不需要--no-commit吧?应该是默认设置。 - Petter

18

cherry-pick -n 命令可以达到你想要的效果,但我不确定为什么你希望将构建改进作为未提交的更改 ——这只会使许多事情变得更加困难(例如合并其他更改到已修改的文件或者在进行任何变基操作时)。

在这个例子中,只有一个分支包含了构建改进,但是可能有 N 个分支包含了构建改进,而我希望在开发特性分支时应用这些改进。

在这种情况下,我会创建一个新的分支 C,在该分支中从 A 和 B(以及所有其他包含构建改进的分支)进行合并。在特性分支 B 中提交更改,然后将它们合并到 C 分支中,此时 C 分支包含了构建改进和特性分支的更改,所以你可以一起测试它们。如果需要进行更多更改,请在适当的分支中进行,而不是在 C 分支中进行,然后合并到 C 分支中。因此,永远不要在 C 分支中更改任何内容,只需将其用于集成来自其他分支的更改。

这意味着你可以在分支 C 中使用 Git 的所有功能,而不是在脏树中搞乱未提交的更改。


1
cherry-pick -n 的使用场景:我在代码的随机位置添加了很多东西,创建了一个工作副本。现在我想在提交到这个功能分支之前清理我的代码。所以我切换到一个临时分支,提交所有更改。然后回到功能分支,使用 cherry-pick 命令来挑选那个提交。是否有更好的方法来完成这个操作? - Tejas Kale

17

我并不百分之百确定自己已经清楚理解了它,但在我的情况下,我仅仅创建了两个分支之间的差异补丁,然后将这个补丁应用在B分支上。

在A分支内部:

 git diff branchA..branchB > patch.diff
 git apply patch.diff

非常好的答案,因为您使用了双点差异,这尤其有用。我试图通过PR将分支B合并到A,但它显示的差异是三个点,并且存在不准确的冲突。 - Siddhartha
2
我正需要这个,所以我创建了别名 apply-diff-from = "!f() { git diff ..$1 | git apply - ; }; f"。也许这能帮到其他人。 - 7heo.tk

9
自Git 2.23版本起,您可以使用git restore精确地实现所需的结果。 git restore提供了选项来指定将通过--staged--worktree "还原"哪些文件。它还提供了一个选项来指定将文件恢复到哪个状态,该选项为--source,默认为工作副本,并可以接受任何git对象。
因此,问题可以表述为“将工作树中的所有文件还原为branchA分支中所有文件的状态”,并且可以使用以下命令实现所需的结果:
git restore --source branchA --worktree .

不必使用所有文件(.),可以将特定文件作为参数给出。


1
这是最好的答案,也是唯一一个在所有情况下都能精确达到结果的答案(即使 branchA 和 branchB 不相关,这正是我的情况)!非常感谢!!! - ThR37

6

您应该能够挑选提交记录(使用-n以避免立即提交)。


-n 没有起作用。它说没有 -m 选项给 cherry-pick 提交失败了。 - Alejandro Sanz Díaz

5
我不确定我理解你的要求。
您可以运行合并,然后调用git reset HEAD~1
以下序列应在branchB上重放masterbranchA之间的每个提交。已经在branchB上应用的提交将被跳过。
# start from branchA
git checkout branchA
# create a temporary branch wip
git checkout -b wip
# use rebase to replay each commit between master and wip on branchB
git rebase --onto branchB master wip

# if you want to remove all the commit history and only keep the resulting diffs,
# use git reset
git reset branchB

# change the active branch
git checkout branchB
# remove temp branch
git branch -d wip

这会将我不想要的文件添加到git的暂存区。而且,只有当所有分支都从主分支的同一提交中分支出来时,它才能正常工作。否则,就会引入master..branchA范围之外的差异。 - Björn Lindqvist
@BjörnLindqvist:如果您不想在暂存区中更改,请删除“--soft”选项。您能画出分支设置的图吗? - LeGEC

0
对于那些使用带有Git Graph扩展的VSCode的用户:
注意:所有这些都可以像往常一样通过git命令行界面(CLI)来实现。
  1. 切换到你想要将更改合并到的目标分支。

  2. 打开Git图形界面。

  3. 右键点击你想要获取更改的源分支。

  4. 选择“合并到当前分支...”。

    Git图形界面 - 合并到当前分支选项

  5. 选择“压缩提交”和“不提交”选项。

    Git图形界面 - 合并到当前分支选项

  6. 在源代码控制面板上,你可以选择“取消暂存所有待处理更改”。这将把更改重新设置为未暂存状态,准备让你逐个提交为新的提交。

    VSCode源代码控制 - 取消暂存提交


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接