others - 如何使用git-merge选择性合并文件 ?

我新项目使用git,该项目有两个并行的--但目前仍处于试验阶段的开发分支:

  • master :导入现有代码库以及一些我通常确定的插件
  • exp1 :实验分支#1
  • exp2 :实验分支#2

exp1和exp2表示两种不同的架构,

将文件从一个开发分支合并到另一个开发分支,而不留下其他内容的最佳方法是什么?

时间:

你可以使用cherry-pick命令从一个分支中获取单个提交。

如果需要更改不是单独提交,则使用下面所示的方法将提交拆分为单个提交 ,使用git rebase -i来编辑原始提交,然后git reset HEAD^有选择地还原更改,然后将git commit提交到历史记录中。

Red Hat Magazine中还有另一个不错的方法,它们使用git add --patch或可能的git add --interactive,如果你想拆分不同的文件(在该网页中搜索"分割")。

我在寻找答案的时候发现了这个 。

摘要:

  • 从你要合并的分支中签出路径,

    $ git checkout source_branch -- <paths>...

  • 如果需要选择性地合并更改,请使用重置,然后添加,

    $ git reset <paths>...
    $ git add -p <paths>...

  • 最后提交

    $ git commit -m"'Merge' these changes"

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


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

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

no commit选项将暂存由Git合并的文件,而不实际提交它们,这样你就有机会修改合并后的文件,然后自己提交。

根据你想要合并文件的方式,有四种情况:

1)你想要真正的合并,在这种情况下,你接受合并文件的方式,Git合并它们,然后提交它们。

2)有些文件你不想合并,例如,要保留当前分支中的版本,并忽略要合并的分支中的版本。

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


git checkout HEAD file1

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

3)如果你想要branchX中的版本(而不是真正的合并),请运行:


git checkout branchX file1

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

4)最后一种情况是,如果你只想在file1中选择特定的合并,在这种情况下,您可以直接编辑修改后的file1,将其更新为您想要的file1版本,然后提交。

如果Git无法自动合并文件,它将报告为"unmerged"文件并生成一个副本,你需要手动解决冲突。

用一个例子进一步说明,假设你要将branchX合并到当前分支中:


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

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

例如:


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中的更改已组合在一起,没有冲突。

通过运行git diff cached文件来检查合并的完成方式,例如:


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

如果发现某些合并不受欢迎,可以直接编辑文件,保存,然后提交。

如果不希望合并file1并希望保留当前分支中的版本,请运行:


git checkout HEAD file1

如果你不想合并file2而只想要branchX中的版本,请运行,


git checkout branchX file2

如果你希望file3自动合并,请不要执行操作,Git已经在这个时候合并了它。

上面的file4是Git失败的合并,这意味着在两个分支都有变化,这是你需要手动解决冲突的地方,通过直接编辑文件或在要使file4成为分支的版本中运行该版本的checkout命令来丢弃合并的文件。

最后,不要忘记提交。

 
git commit

 

我不喜欢上面的方法。 使用cherry-pick是很好的选择,但如果你想把所有的修改都带来,除了一些缺点。 这是我的方法。

没有 --interactive 参数可以传递给 git merge 。

下面是另一个选项:

你有一些分支中的更改与'母版''功能'和你想带的一些但不是全部,他们喜欢以一种不草率的方式( 例如 。 你不想在每个人面前挑选和提交


git checkout feature
git checkout -b temp
git rebase -i master

# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change

# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git checkout master
git pull. temp
git branch -d temp

所以只需将它的打包为一个shell脚本,将主控形状更改为 $to 并将特性更改为 $from,你就可以:


#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull. ${from}_tmp
git branch -d ${from}_tmp

还有另一种方法:

 
git checkout -p

 

它是git checkoutgit 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.

1800信息的答案完全正确。 作为一个 git noob,尽管,"使用 git cherry-pick"未足以让我要解决这问题,不在互联网上稍微挖所以我觉得应该发布一个更详细的指导,以防修改其他人也以类似的船只。

我的用例希望有选择地从其他人的github中选择更改。 如果你已经有一个本地分支,你只需要执行步骤 2和 5 -7.

  1. 创建一个带有所需更改的本地分支。

    $ git branch mybranch <base branch>

  2. switch 进入它。

    $ git checkout mybranch

  3. 从其他人的帐户中提取所需的更改。 如果你还没有将它们添加为远程。

    $ git remote add repos-w-changes <git url>

  4. 从分支中提取所有内容。

    $ git pull repos-w-changes branch-i-want

  5. 查看提交日志以查看所需的更改:

    $ git log

  6. switch 返回到要将更改拖入分支的分支。

    $ git checkout originalbranch

  7. 樱桃挑选你的提交,一个一个,和哈希。

    $ git cherry-pick -x hash-of-commit

Hat提示:http://www.sourcemage.org/Git_Guide

假设你有masterexp1exp2分支,你想将一个实验分支中的一个文件合并到主文件中,我可以这样做:


git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# save these files as a stash
git stash
# merge stash with master
git merge stash

这为你提供你想要的每个文件的文件差异,

-s recursive -X ignore-all-space

从两个分支,而用从另一个简单的方法,以实际合并 branch,的特定文件,而不仅仅是更换特别的档案。

第一步:差异分支

git diff branch_b> my_patch_file.patch

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

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

git apply -p1 --include=pattern/matching/the/path/to/file/or/folder

关于选项的有用说明

你可以在包含模式中使用 * 作为通配符。

不需要转义斜线。

另外,你可以使用 --exclude,并将它应用到除匹配该模式的文件之外的所有文件,或者将补丁与 R 一起使用

使用-p1选项是一个缩写形式延用了 *unix 补片命令和这一事实的增补程序内容文件预先准备与 a/ 每个文件名或者 b/ ( 或者更多取决于补丁文件的生成方式) 哪个你应该去掉,以便它可以解码,真正的文件以文件的路径补丁需要将策略应用到了。

查看git-apply的手册页了解更多选项。

第三步:没有第三步

显然,你需要提交你的更改,但是在提交提交之前,你还没有其他相关的调整。

这就是你如何让历史从另一个分支跟踪,哪怕你的"简单"合并会带来一些麻烦,即使一个更多的合并会带来你不想要的更多改变。

首先,你将采取预先声明的异常步骤,即你将要提交的是一个合并,而没有git对工作目录中的文件执行任何操作:


git merge --no-ff --no-commit -s ours branchname1

。其中"branchname"是你要合并的任何内容。 如果你马上提交,它将不会做任何改变,但它仍然会显示来自另一个分支的祖先。 如果需要,可以将更多的branches/tags/etc. 添加到 命令行 中。 此时,没有要提交的更改,因此从其他修订中获取文件,下一个。


git checkout branchname1 -- file1 file2 etc

如果要从多个其他分支合并,请按需要重复。


git checkout branchname2 -- file3 file4 etc

现在,来自另一个分支的文件在索引中,准备提交,并带有历史。

 
git commit

 

在提交消息中你会有很多解释。

请注意,如果不清楚,这可能会造成问题。 它不是"分支"的精髓,cherry-pick是一种更加诚实的方式来做你要做的事情,这里。 如果你想为同一分支上上次没有带来的其他文件执行另一个"合并",它将阻止你使用"已经更新到最新日期"消息。 这是不分支的症状,在"来自"分支中应该有多个不同分支。

可以将Myclass.java文件从feature1分支合并到master分支,即使Myclass.javamaster上不存在,它也会工作。


git checkout master
git checkout feature1 Myclass.java

...