我在一个新项目上使用git,它有两个并行 - 但目前是实验性的 - 开发分支:
-
master
:导入现有的代码库加上一些我一般都知道的mod -
exp1
:实验分支#1 -
exp2
:实验分支#2
exp1
和 exp2
代表两种截然不同的架构方法 . 直到我走得更远,我无法知道哪一个(如果有的话)会起作用 . 当我在一个分支中取得进展时,我有时会在另一个分支中进行编辑,并且只想合并那些 .
What is the best way to merge selective changes from one development branch to another while leaving behind everything else?
我考虑过的方法:
-
git merge --no-commit
然后手动取消大量编辑,我不想在分支之间进行通用 . -
手动将公共文件复制到临时目录,然后
git checkout
移动到另一个分支,然后更多地手动从临时目录复制到工作树中 . -
以上的变化 . 现在放弃
exp
分支并使用另外两个本地存储库进行实验 . 这使得手动复制文件更加简单 .
所有这三种方法看起来都很乏味且容易出错 . 我希望有更好的方法;类似于过滤器路径参数的东西会使 git-merge
更具选择性 .
24 回答
我会做的
这样,您可以限制分支的文件模式的提交范围 .
被盗:http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
您可以使用cherry-pick命令从一个分支获取单个提交 .
如果您想要的更改不在单独提交中,请使用此处显示的方法split the commit into individual commits . 粗略地说,您使用
git rebase -i
来获取原始提交进行编辑,然后git reset HEAD^
选择性地还原更改,然后git commit
将该位提交为历史记录中的新提交 .There is another nice method here在Red Hat Magazine中,他们使用
git add --patch
或者可能git add --interactive
,如果你想将不同的更改分成单个文件(在该页面中搜索"split"),它允许你只添加一部分大块 .拆分更改后,您现在可以选择您想要的更改 .
我有与上面提到的完全相同的问题 . 但我发现this更清楚地解释了答案 .
摘要:
提示:它也可以在没有
--
的情况下工作,如链接帖子中所见 .或者,使用重置,然后使用选项
-p
添加,要有选择地将文件从一个分支合并到另一个分支,请运行
其中
branchX
是您要合并到当前分支的分支 .--no-commit
选项将暂存已由Git合并而不实际提交它们的文件 . 这将使您有机会根据需要修改合并的文件,然后自己提交 .根据您要合并文件的方式,有四种情况:
1)您想要真正的合并 .
在这种情况下,您接受合并文件的方式是Git自动合并它们然后提交它们 .
2)有些文件您不想合并 .
例如,您希望保留当前分支中的版本并忽略要合并的分支中的版本 .
要选择当前分支中的版本,请运行:
这将检索当前分支中
file1
的版本并覆盖Git的file1
automerged .3)如果你想在branchX中使用该版本(而不是真正的合并) .
跑:
这将在
branchX
中检索file1
的版本并覆盖由Git自动合并的file1
.4)最后一种情况是,如果要仅选择file1中的特定合并 .
在这种情况下,您可以直接编辑修改后的
file1
,将其更新为您想要的file1
版本,然后提交 .如果Git无法自动合并文件,它会将文件报告为“未合并”并生成一个副本,您需要手动解决冲突 .
为了进一步解释一个例子,假设您要将
branchX
合并到当前分支中:然后运行
git status
命令以查看已修改文件的状态 .例如:
file1
,file2
和file3
是git已成功自动合并的文件 .这意味着所有这三个文件的
master
和branchX
中的更改已合并在一起而没有任何冲突 .您可以通过运行
git diff --cached
来检查合并的完成方式;如果您发现某些合并不受欢迎,那么您可以
直接编辑文件
保存
git commit
如果您不想合并file1并希望在当前分支中保留该版本
跑
如果您不想合并file2并且只想在branchX中使用该版本
跑
如果您希望自动合并file3,请不要这样做任何东西 .
Git已经在这一点上合并了它 .
file4
上面是Git失败的合并 . 这意味着在同一行上发生的两个分支都发生了变化 . 您需要手动解决冲突 . 您可以通过直接编辑文件或对希望file4
成为分支的版本运行checkout命令来放弃合并 .最后,别忘了
git commit
.我不喜欢上述方法 . 使用cherry-pick非常适合选择单个更改,但如果您想要引入除了一些不良更改之外的所有更改,那将是一种痛苦 . 这是我的方法 .
没有
--interactive
参数可以传递给git merge .这是替代方案:
你在分支'功能'中有一些变化,你想要以一种不邋way的方式将一些但不是全部的变为'master'(即你不想挑选并提交每一个)
所以只需将它包装在shell脚本中,将master更改为$ to并将功能更改为$ from,您就可以了:
还有另外一种方法:
它是
git checkout
和git add -p
之间的混合,可能正是您正在寻找的:虽然其中一些答案非常好,但我觉得没有人真正回答OP的原始约束:从特定分支中选择特定文件 . 这个解决方案可以做到这一点,但如果有很多文件可能会很乏味 .
假设你有
master
,exp1
和exp2
分支 . 您希望将每个实验分支中的一个文件合并为主文件 . 我会做这样的事情:这将为您提供所需的每个文件的文件内差异 . 而已 . 没什么 . 在版本之间进行完全不同的文件更改很有用 - 在我的例子中,将应用程序从Rails 2更改为Rails 3 .
EDIT :这将合并文件,但会进行智能合并 . 我无法弄清楚如何使用这种方法获取文件内差异信息(也许它仍然会出现极端差异 . 除非你使用
-s recursive -X ignore-all-space
选项,否则像空白一样的烦人的小东西会被合并回来)1800 INFORMATION的答案完全正确 . 然而,作为一个git noob,“使用git cherry-pick”还不足以让我在互联网上更多地挖掘这一点,所以我想我会发布一个更详细的指南以防其他人在类似的船 .
我的用例是想要有选择地将其他人的github分支中的更改转换为我自己的 . 如果您已经有一个包含更改的本地分支,则只需执行步骤2和5-7 .
$ git branch mybranch <base branch>
$ git checkout mybranch
$ git remote add repos-w-changes <git url>
$ git pull repos-w-changes branch-i-want
$ git log
$ git checkout originalbranch
$ git cherry-pick -x hash-of-commit
帽子提示:http://www.sourcemage.org/Git_Guide
以下是如何使用
feature1
分支中的Myclass.java
替换master
分支中的Myclass.java
文件 . 即使master
上不存在Myclass.java
,它也会起作用 .请注意,这将覆盖 - 而不是合并 - 而忽略主分支中的本地更改 .
实际合并来自两个分支的特定文件的简单方法,不仅仅是将特定文件替换为来自另一个分支的文件 .
第一步:扩散分支
git diff branch_b > my_patch_file.patch
创建当前分支和branch_b之间差异的补丁文件
第二步:在匹配模式的文件上应用补丁
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
有关选项的有用说明
您可以在包含模式中使用
*
作为通配符 .斜杠不需要转义 .
此外,您可以使用--exclude将其应用于除匹配模式的文件之外的所有内容,或者使用-R反转补丁
-p1选项是来自* unix patch命令的保留,以及补丁文件的内容在每个文件名前加上
a/
或b/
(或更多,具体取决于补丁文件的生成方式)这一事实,您需要将其删除,以便它可以找出需要应用补丁的文件路径的真实文件 .查看git-apply的手册页以获取更多选项 .
第三步:没有第三步
显然你想要提交你的更改,但是谁说你在提交之前没有其他相关的调整 .
以下是如何让历史记录只关注来自另一个分支的几个文件,即使更“简单”的合并会带来更多您不想要的更改 .
首先,你将采取不同寻常的步骤,事先声明你将要提交的是一个合并,没有git做任何事情到工作目录中的文件:
. . . 其中“branchname”是你声称要合并的东西 . 如果你马上提交,它将不做任何改变,但它仍然显示来自另一个分支的祖先 . 您可以添加更多分支/标签/等 . 如果需要,也可以到命令行 . 此时,提交没有任何更改,因此请从其他修订中获取文件 .
如果您要从多个其他分支合并,请根据需要重复 .
现在,来自其他分支的文件位于索引中,准备提交,具有历史记录 .
并且你将在该提交消息中做很多解释 .
但请注意,如果不清楚,这是搞乱的事情要做 . 它不符合“分支”的精神,而樱桃选择是一种更诚实的方式来做你正在做的事情,在这里 . 如果你想为你上次没有带来的同一个分支上的其他文件做另一个“合并”,它会阻止你发送一条“已经是最新的”消息 . 这是我们应该拥有的不分支的症状,在“from”分支中应该是多个不同的分支 .
我知道我有点晚了,但这是我合并选择性文件的工作流程 .
我发现this post包含最简单的答案 . 仅仅做:
例:
有关详细信息,请参阅帖子 .
最简单的方法是将您的仓库设置为要合并的分支然后运行,
如果你跑
你会看到文件已经上演了......
然后跑
简单 .
奇怪的是,git仍然没有这么方便的工具"out of the box" . 当我通过当前版本分支中的 just some 错误修正更新一些旧版本分支(仍然有很多软件用户)时,我会大量使用它 . 在这种情况下,通常需要从trunk中的文件中快速获取代码行,忽略了许多其他更改(不应该进入旧版本)...当然需要 interactive three-way merge case,
git checkout --patch <branch> <file path>
不适用于此选择性合并目的 .You can do it easily:
只需将此行添加到全局
.gitconfig
或本地.git/config
文件中的[alias]
部分:它意味着你使用Beyond Compare . 如果需要,只需更改为您选择的软件即可 . 或者,如果您不需要交互式选择性合并,则可以将其更改为三向自动合并:
然后像这样使用:
这将为您提供其他分支中任何文件的真正选择性 tree-way 合并机会 .
我有与上面提到的完全相同的问题 . 但我发现this git blog更清楚地解释了答案 .
来自以上链接的命令:
这不完全是你想要的,但它对我有用:
这是一些答案的混合 .
我喜欢上面的'git-interactive-merge'答案,但有一个更简单 . 让git使用交互式的rebase组合为你做这个:
所以情况是你想要来自'feature'分支的C1和C2(分支点'A'),但现在不需要其余的 .
如上所述,您将进入交互式编辑器,在该编辑器中为C1和C2选择“拾取”行(如上所述) . 保存并退出,然后它将继续使用rebase并在主C1 C1处给你分支'temp'和HEAD:
然后你可以将master更新为HEAD并删除temp分支,你很高兴:
我知道这个问题很老,还有很多其他答案,但是我编写了自己的脚本'pmerge'来部分合并目录 . 这是一项正在进行的工作,我仍在学习git和bash脚本 .
此命令使用
git merge --no-commit
,然后取消应用与提供的路径不匹配的更改 .用法:
git pmerge branch path
示例:
git merge develop src/
我没有广泛测试过它 . 工作目录应该没有任何未提交的更改和未跟踪的文件 .
您可以使用
read-tree
将给定的远程树读取或合并到当前索引中,例如:要执行合并,请改用
-m
.另见:How do I merge a sub directory in git?
当两个分支的当前提交之间只有少数文件发生变化时,我通过浏览不同的文件手动合并更改 .
git difftoll <branch-1>..<branch-2>
按文件选择性合并/提交的简单方法:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
如果您没有太多已更改的文件,这将使您无需额外提交 .
1. Duplicate branch temporarily
$ git checkout -b temp_branch
2. Reset to last wanted commit
$ git reset --hard HEAD~n
,其中n
是您需要返回的提交数3. Checkout each file from original branch
$ git checkout origin/original_branch filename.ext
现在,如果需要,您可以提交并强制推送(覆盖远程) .
如果您只需要合并特定目录并离开其他一切完好但保存历史,你可以尝试这个...在你实验之前创建一个新的
target-branch
master
.以下步骤假设您有两个分支
target-branch
和source-branch
,并且要合并的目录dir-to-merge
位于source-branch
中 . 还假设您在目标中有其他目录,如dir-to-retain
,您不想更改并保留历史记录 . 此外,假设dir-to-merge
中存在合并冲突 .