我正在一个新项目中使用Git,该项目有两个并行但目前处于试验阶段的开发分支:

master:导入现有的代码库,再加上一些我通常确信的修改exp1:实验分支#1exp2:实验分支#2

exp1和exp2表示两种非常不同的体系结构方法。在我进一步相处之前,我无法知道哪一个(如果有的话)会起作用。当我在一个分支中取得进展时,我有时会对另一个分支进行有用的编辑,并希望仅合并这些编辑。

将一个开发分支中的选择性更改合并到另一个分支中,同时保留其他所有内容的最佳方法是什么?

我考虑过的方法:

gitmerge——无需提交,然后手动取消大量编辑,我不想在分支之间共享这些编辑。手动将通用文件复制到临时目录中,然后git checkout移动到另一个分支,然后更多地手动将临时目录复制到工作树中。在上述基础上的变化。暂时放弃exp分支,使用另外两个本地存储库进行实验。这使得手动复制文件更加简单。

所有这三种方法都显得乏味且容易出错。我希望有更好的方法;类似于过滤器路径参数,可以使gitmerge更有选择性。


当前回答

如果您没有太多的文件被更改,这将使您没有额外的提交。

1.临时复制分支$git结帐-b temp_branch

2.重置为上次所需提交$git reset--hard HEAD~n,其中n是需要返回的提交次数

3.从原始分支签出每个文件$git签出原点/original_branch文件名.ext

现在,如果需要,您可以提交并强制推送(覆盖远程)。

其他回答

简单的方法是,实际上合并来自两个分支的特定文件,而不仅仅是用另一个分支的文件替换特定文件。

第一步:区分分支

git diff branch_b>my_patch_file.patch

创建当前分支和branch_b之间差异的修补程序文件

第二步:对匹配模式的文件应用补丁

git apply-p1--include=pattern/匹配/the/path/to/file/或/folder my_patch_file.patch

关于选项的有用说明

您可以在include模式中使用*作为通配符。

斜杠不需要逃避。

此外,您可以改用--exclude并将其应用于除与模式匹配的文件之外的所有文件,或使用-R反转补丁

-p1选项是*Unix修补程序命令的一个保留,并且事实上,修补程序文件的内容在每个文件名前面加上/或b/(或更多,取决于修补程序文件是如何生成的),您需要删除这些文件,这样它就可以找出真正的文件到需要应用修补程序的文件的路径。

查看git应用程序的手册页以了解更多选项。

第三步:没有第三步

很明显,你想提交你的更改,但谁能说你在提交之前没有其他相关的调整。

我喜欢前面的“git交互式合并”答案,但有一个更简单。让Git使用交互式和到以下内容的重基组合为您实现这一点:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o master

因此,您需要从“feature”分支(分支点“A”)中获取C1和C2,但目前没有其他分支。

# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp

正如前面的回答一样,这会让您进入交互式编辑器,在其中选择C1和C2的“pick”行(如上所述)。保存并退出,然后它将继续重新创建数据库,并为您提供分支“temp”和主机+C1+C2的HEAD:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o-master--C1---C2 [HEAD, temp]

然后,您只需将master更新为HEAD并删除临时分支即可:

# git branch -f master HEAD
# git branch -d temp

还有另一条路要走:

git checkout -p

它是git checkout和git add-p的混合体,可能正是您想要的:

   -p, --patch
       Interactively select hunks in the difference between the <tree-ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree-ish> was specified, the index).

       This means that you can use git checkout -p to selectively discard
       edits from your current working tree. See the “Interactive Mode”
       section of git-add(1) to learn how to operate the --patch mode.

这是我合并选定文件的工作流。

# Make a new branch (this will be temporary)
git checkout -b newbranch

# Grab the changes
git merge --no-commit  featurebranch

# Unstage those changes
git reset HEAD
(You can now see the files from the merge are unstaged)

# Now you can chose which files are to be merged.
git add -p

# Remember to "git add" any new files you wish to keep
git commit

要有选择地将文件从一个分支合并到另一个分支,请运行

git merge --no-ff --no-commit branchX

其中branchX是要从中合并到当前分支的分支。

--no commit选项将暂存已被Git合并的文件,而无需实际提交。这将使您有机会根据需要修改合并的文件,然后自己提交。

根据您希望合并文件的方式,有四种情况:

1) 你想要真正的合并。

在这种情况下,您接受合并文件的方式是Git自动合并文件,然后提交它们。

2) 有些文件您不想合并。

例如,您希望保留当前分支中的版本,而忽略要从中合并的分支的版本。

要选择当前分支中的版本,请运行:

git checkout HEAD file1

这将在当前分支中检索file1的版本,并覆盖Git自动合并的file1。

3) 如果您希望branchX中的版本(而不是真正的合并)。

Run:

git checkout branchX file1

这将在branchX中检索file1的版本,并覆盖Git自动合并的file1。

4) 最后一种情况是,如果只选择文件1中的特定合并。

在这种情况下,您可以直接编辑修改后的file1,将其更新为您希望的file1版本,然后提交。

如果Git无法自动合并文件,它将报告该文件为“未合并”,并生成一个副本,您需要手动解决冲突。


为了用示例进一步解释,假设您希望将branchX合并到当前分支中:

git merge --no-ff --no-commit branchX

然后运行gitstatus命令查看修改文件的状态。

例如:

git status

# On branch master
# Changes to be committed:
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      file4
#

其中,file1、file2和file3是git已成功自动合并的文件。

这意味着所有这三个文件的master和branchX中的更改都已合并在一起,没有任何冲突。

您可以通过运行gitdiff-cached来检查合并是如何完成的;

git diff --cached file1
git diff --cached file2
git diff --cached file3

如果您发现不需要合并,那么可以

直接编辑文件拯救git提交

如果您不想合并文件1并希望在当前分支中保留版本

Run

git checkout HEAD file1

如果您不想合并file2,只想在branchX中使用版本

Run

git checkout branchX file2

如果希望自动合并file3,请不要执行任何操作。

Git目前已经将其合并。

上面的文件4是Git失败的合并。这意味着在同一行上发生的两个分支中都有更改。这是您需要手动解决冲突的地方。您可以通过直接编辑文件或为希望file4成为的分支中的版本运行签出命令来放弃合并的文件。

最后,不要忘记gitcommit。