如何有选择地合并或选择 Git 中另一个分支的更改?
我正在一个新项目上使用 Git,该项目有两个并行的(但目前是实验性的)开发分支:
master
:导入现有代码库以及我通常确信的一些修改exp1
:实验分支#1exp2
:实验分支#2
exp1
和 exp2
代表两种截然不同的架构方法。 在我进一步了解之前,我无法知道哪一个(如果有的话)会起作用。 当我在一个分支中取得进展时,有时我会进行一些在另一分支中有用的编辑,并且想合并这些内容。
将选择性更改从一个开发分支合并到另一个开发分支,同时保留其他所有内容的最佳方法是什么?
我考虑过的方法:
git merge --no-commit
然后手动取消暂存大量我不想在分支之间共享的编辑。手动将常用文件复制到临时目录中,然后通过 git checkout 移动到另一个分支,然后从临时目录中手动复制到工作树中。
上述内容的变体。 暂时放弃
exp
分支并使用两个额外的本地存储库进行实验。 这使得手动复制文件变得更加简单。
所有这三种方法似乎都很乏味且容易出错。 我希望有更好的方法; 类似于过滤器路径参数,可以使 git-merge 更具选择性。
I'm using Git on a new project that has two parallel -- but currently experimental -- development branches:
master
: import of existing codebase plus a few modifications that I'm generally sure ofexp1
: experimental branch #1exp2
: experimental branch #2
exp1
and exp2
represent two very different architectural approaches. Until I get further along I have no way of knowing which one (if either) will work. As I make progress in one branch I sometimes have edits that would be useful in the other branch and would like to merge just those.
What is the best way to merge selective changes from one development branch to another while leaving behind everything else?
Approaches I've considered:
git merge --no-commit
followed by manual unstaging of a large number of edits that I don't want to make common between the branches.Manual copying of common files into a temporary directory followed by
git checkout
to move to the other branch and then more manual copying out of the temporary directory into the working tree.A variation on the above. Abandon the
exp
branches for now and use two additional local repositories for experimentation. This makes the manual copying of files much more straightforward.
All three of these approaches seem tedious and error-prone. I'm hoping there is a better approach; something akin to a filter path parameter that would make git-merge
more selective.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(29)
tl;dr
我遇到了与您上面提到的完全相同的问题。 但我发现 这更清楚地解释了答案。
摘要:
检查要合并的分支的路径,
或有选择地合并块
或者,使用重置,然后使用选项添加
-p
,最后提交
tl;dr
I had the exact same problem as mentioned by you above. But I found this clearer in explaining the answer.
Summary:
Check out the path(s) from the branch you want to merge,
or to selectively merge hunks
Alternatively, use reset and then add with the option
-p
,Finally commit
您可以使用 cherry-pick 命令从一个分支获取单独的提交。
如果您想要的更改不在单独的提交中,则使用此处显示的方法将提交拆分为单独的提交提交。 粗略地说,您使用 git rebase -i 来编辑原始提交,然后使用 git reset HEAD^ 选择性地恢复更改,然后使用 git commit 来编辑> 将该位作为历史记录中的新提交提交。
红帽杂志中还有另一种不错的方法,他们使用
git add --patch
或可能的git add --interactive
来允许如果您想将不同的更改拆分为单个文件(在该页面中搜索“拆分”),您可以仅添加大块的一部分。拆分更改后,您现在可以只选择您想要的更改。
You use the cherry-pick command to get individual commits from one branch.
If the change(s) you want are not in individual commits, then use the method shown here to split the commit into individual commits. Roughly speaking, you use
git rebase -i
to get the original commit to edit, thengit reset HEAD^
to selectively revert changes, thengit commit
to commit that bit as a new commit in the history.There is another nice method here in Red Hat Magazine, where they use
git add --patch
or possiblygit add --interactive
which allows you to add just parts of a hunk, if you want to split different changes to an individual file (search in that page for "split").Having split the changes, you can now cherry-pick just the ones you want.
要有选择地将文件从一个分支合并到另一个分支,请运行
其中
branchX
是要合并到当前分支的分支。--no-commit
选项将暂存已被 Git 合并的文件,而不实际提交它们。 这将使您有机会根据需要修改合并的文件,然后自行提交它们。根据您想要合并文件的方式,有四种情况:
1) 您想要真正的合并。
在这种情况下,您可以按照 Git 自动合并文件的方式接受合并的文件,然后提交它们。
2) 有一些文件您不想合并。
例如,您希望保留当前分支中的版本并忽略要合并的分支中的版本。
要选择当前分支中的版本,请运行:
这将检索当前分支中
file1
的版本,并覆盖 Git 自动合并的file1
。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
中的版本Run
如果您希望自动合并
file3
,则不要做任何事情。此时 Git 已经将其合并了。
上面的
file4
是 Git 合并失败的结果。 这意味着同一行上的两个分支都发生了变化。 这是您需要手动解决冲突的地方。 您可以通过直接编辑文件或运行您想要file4
成为的分支中的版本的 checkout 命令来放弃合并完成的内容。最后,不要忘记
git commit
。To selectively merge files from one branch into another branch, run
where
branchX
is the branch you want to merge from into the current branch.The
--no-commit
option will stage the files that have been merged by Git without actually committing them. This will give you the opportunity to modify the merged files however you want to and then commit them yourself.Depending on how you want to merge files, there are four cases:
1) You want a true merge.
In this case, you accept the merged files the way Git merged them automatically and then commit them.
2) There are some files you don't want to merge.
For example, you want to retain the version in the current branch and ignore the version in the branch you are merging from.
To select the version in the current branch, run:
This will retrieve the version of
file1
in the current branch and overwrite thefile1
automerged by Git.3) If you want the version in branchX (and not a true merge).
Run:
This will retrieve the version of
file1
inbranchX
and overwritefile1
auto-merged by Git.4) The last case is if you want to select only specific merges in
file1
.In this case, you can edit the modified
file1
directly, update it to whatever you'd want the version offile1
to become, and then commit.If Git cannot merge a file automatically, it will report the file as "unmerged" and produce a copy where you will need to resolve the conflicts manually.
To explain further with an example, let's say you want to merge
branchX
into the current branch:You then run the
git status
command to view the status of modified files.For example:
Where
file1
,file2
, andfile3
are the files git have successfully auto-merged.What this means is that changes in the
master
andbranchX
for all those three files have been combined together without any conflicts.You can inspect how the merge was done by running the
git diff --cached
;If you find some merge undesirable then you can
git commit
If you don't want to merge
file1
and want to retain the version in the current branchRun
If you don't want to merge
file2
and only want the version inbranchX
Run
If you want
file3
to be merged automatically, don't do anything.Git has already merged it at this point.
file4
above is a failed merge by Git. This means there are changes in both branches that occur on the same line. This is where you will need to resolve the conflicts manually. You can discard the merged done by editing the file directly or running the checkout command for the version in the branch you wantfile4
to become.Finally, don't forget to
git commit
.我不喜欢上述方法。 使用cherry-pick 非常适合挑选单个更改,但如果您想引入除了一些不好的更改之外的所有更改,那就很痛苦了。 这是我的方法。
没有可以传递给 git merge 的
--interactive
参数。这是另一种选择:
您在分支“功能”中进行了一些更改,并且您希望以一种不马虎的方式将其中一些但不是全部更改到“主”(即您不想挑选并提交每个更改)
因此,只需将其包装在 shell 脚本中,将 master 更改为 $to 并将 feature 更改为 $from 即可:
I don't like the above approaches. Using cherry-pick is great for picking a single change, but it is a pain if you want to bring in all the changes except for some bad ones. Here is my approach.
There is no
--interactive
argument you can pass to git merge.Here is the alternative:
You have some changes in branch 'feature' and you want to bring some but not all of them over to 'master' in a not sloppy way (i.e. you don't want to cherry pick and commit each one)
So just wrap that in a shell script, change master into $to and change feature into $from and you are good to go:
还有另一种方法:
它是 git checkout 和 git add -p 之间的混合,可能正是您正在寻找的东西:
There is another way to go:
It is a mix between
git checkout
andgit add -p
and might quite be exactly what you are looking for:虽然其中一些答案非常好,但我觉得没有一个真正回答了OP的原始约束:从特定分支中选择特定文件。 这个解决方案可以做到这一点,但如果有很多文件,它可能会很乏味。
假设您有
master
、exp1
和exp2
分支。 您想要将每个实验分支中的一个文件合并到 master 中。 我会做这样的事情:这将为您提供您想要的每个文件的文件内差异。 而已。 一点也没有少。 在版本之间进行完全不同的文件更改非常有用 - 就我而言,从 Ruby on Rails 2 到 Ruby on Rails 3。
这将合并文件,但它会进行智能合并。 我无法弄清楚如何使用此方法来获取文件内差异信息(也许对于极端差异仍然如此。除非您使用
-s recursive -X ,否则像空格这样烦人的小东西会被合并回来忽略所有空格
选项)While some of these answers are pretty good, I feel like none actually answered the OP's original constraint: selecting particular files from particular branches. This solution does that, but it may be tedious if there are many files.
Let’s say you have the
master
,exp1
, andexp2
branches. You want to merge one file from each of the experimental branches into master. I would do something like this:This will give you in-file diffs for each of the files you want. Nothing more. Nothing less. It's useful you have radically different file changes between versions --in my case, changing an application from Ruby on Rails 2 to Ruby on Rails 3.
This will merge files, but it does a smart merge. I wasn't able to figure out how to use this method to get in-file diff information (maybe it still will for extreme differences. Annoying small things like whitespace get merged back in unless you use the
-s recursive -X ignore-all-space
option)1800 条信息答案是完全正确的。 不过,作为 Git 的新手,“使用 gitcherry-pick”不足以让我在没有在互联网上进行更多挖掘的情况下弄清楚这一点,所以我想我应该发布一个更详细的指南,以防其他人在类似的船上。
我的用例是希望有选择地将更改从其他人的 GitHub 分支拉到我自己的分支中。 如果您已经有一个进行了更改的本地分支,则只需执行步骤 2 和 5-7。
使用您想要引入的更改创建(如果未创建)本地分支。
$ gitbranch mybranch <基本分支>
切换到它。
$ git checkout mybranch
从其他人的帐户中提取您想要的更改。 如果您还没有添加,您需要将它们添加为遥控器。
$ git remote add repos-w-changes
从其分支中拉取所有内容。
$ git pull repos-w-changes 分支-i-want
查看提交日志以查看您想要哪些更改:
$ git 日志
切换回要将更改拉入的分支。
$ git checkoutoriginalbranch
用哈希值逐一挑选您的提交。
$ gitcherry-pick -x 提交哈希
帽子提示:http://www.sourcemage.org/Git_Guide(存档副本)
1800 INFORMATION's answer is completely correct. As someone new to Git, though, "use git cherry-pick" wasn't enough for me to figure this out without a bit more digging on the Internet, so I thought I'd post a more detailed guide in case anyone else is in a similar boat.
My use case was wanting to selectively pull changes from someone else's GitHub branch into my own. If you already have a local branch with the changes, you only need to do steps 2 and 5-7.
Create (if not created) a local branch with the changes you want to bring in.
$ git branch mybranch <base branch>
Switch into it.
$ git checkout mybranch
Pull down the changes you want from the other person's account. If you haven't already, you'll want to add them as a remote.
$ git remote add repos-w-changes <git url>
Pull down everything from their branch.
$ git pull repos-w-changes branch-i-want
View the commit logs to see which changes you want:
$ git log
Switch back to the branch you want to pull the changes into.
$ git checkout originalbranch
Cherry pick your commits, one by one, with the hashes.
$ git cherry-pick -x hash-of-commit
Hat tip: http://www.sourcemage.org/Git_Guide (archived copy)
以下是如何将
master
分支中的Myclass.java
文件替换为feature1
分支中的Myclass.java
文件。 即使Myclass.java
在master
上不存在,它也会工作。请注意,这将覆盖(而不是合并)并忽略主分支中的本地更改。
Here is how you can replace
Myclass.java
file inmaster
branch withMyclass.java
infeature1
branch. It will work even ifMyclass.java
doesn't exist onmaster
.Note this will overwrite - not merge - and ignore local changes in the master branch rather.
简单的方法是实际合并两个分支中的特定文件,而不仅仅是用另一个分支中的文件替换特定文件。
第一步:比较分支
创建当前分支和
branch_b
之间差异的补丁文件。第二步:在与模式匹配的文件上应用补丁
有关选项的有用注释
您可以在包含模式中使用
*
作为通配符。斜杠不需要转义。
另外,您可以使用
--exclude
代替,并将其应用于除与模式匹配的文件之外的所有内容,或者使用-R
反转补丁。-p1
选项是 *Unixpatch
命令的延续,补丁文件的内容在每个文件名前面加上a/
或b/
(或更多,取决于补丁文件的生成方式),您需要将其剥离,以便它可以找出真正的文件到需要应用补丁的文件的路径。查看
git-apply
的man
页面了解更多选项。第三步:没有第三步
显然您想要提交更改,但是谁敢说您在提交之前不需要做一些其他相关的调整。
The simple way, to actually merge specific files from two branches, not just replace specific files with ones from another branch.
Step one: Diff the branches
Creates a patch file of the difference between the current branch and
branch_b
.Step two: Apply the patch on files matching a pattern
Useful notes on the options
You can use
*
as a wildcard in the include pattern.Slashes don't need to be escaped.
Also, you could use
--exclude
instead, and apply it to everything except the files matching the pattern, or reverse the patch with-R
.The
-p1
option is a holdover from the *Unixpatch
command and the fact that the patch file's contents prepend each file name witha/
orb/
(or more, depending on how the patch file was generated), which you need to strip so that it can figure out the real file to the path to the file the patch needs to be applied to.Check out the
man
page forgit-apply
for more options.Step three: There is no step three
Obviously you'd want to commit your changes, but who's to say you don't have some other related tweaks you want to do before making your commit.
以下是如何让历史记录以最少的麻烦跟踪来自另一个分支的几个文件,即使更“简单”的合并会带来更多您不想要的更改。
首先,您将采取不寻常的步骤,提前声明您将要提交的是合并,而 Git 不会对工作目录中的文件执行任何操作:
...其中“branchname”是您声明的任何内容合并自。 如果您立即提交,它将不会进行任何更改,但它仍然会显示来自另一个分支的血统。 如果需要,您还可以向命令行添加更多分支、标签等。 但此时,没有要提交的更改,因此接下来从其他修订版中获取文件。
如果您要从多个其他分支合并,请根据需要重复。
现在,来自另一个分支的文件位于索引中,准备提交并具有历史记录。
您将在该提交消息中进行大量解释。
但请注意,如果不清楚的话,这是一件混乱的事情。 这不符合“分支”的精神,而樱桃挑选是一种更诚实的方式来完成您在这里要做的事情。 如果您想对上次未引入的同一分支上的其他文件进行另一次“合并”,它将阻止您并显示“已经是最新的”消息。 这是我们应该有分支时却没有分支的一种症状,因为“来自”分支应该是多个不同的分支。
Here's how you can get history to follow just a couple of files from another branch with a minimum of fuss, even if a more "simple" merge would have brought over a lot more changes that you don't want.
First, you'll take the unusual step of declaring in advance that what you're about to commit is a merge, without Git doing anything at all to the files in your working directory:
... where "branchname" is whatever you claim to be merging from. If you were to commit right away, it would make no changes, but it would still show ancestry from the other branch. You can add more branches, tags, etc. to the command line if you need to, as well. At this point though, there are no changes to commit, so get the files from the other revisions, next.
If you were merging from more than one other branch, repeat as needed.
Now the files from the other branch are in the index, ready to be committed, with history.
And you'll have a lot of explaining to do in that commit message.
Please note though, in case it wasn't clear, that this is a messed up thing to do. It is not in the spirit of what a "branch" is for, and cherry-pick is a more honest way to do what you'd be doing, here. If you wanted to do another "merge" for other files on the same branch that you didn't bring over last time, it will stop you with an "already up to date" message. It's a symptom of not branching when we should have, in that the "from" branch should be more than one different branch.
最简单的方法是将存储库设置为要合并的分支,然后运行
如果运行,
您将看到文件已经暂存...
然后运行
Simple。
The easiest way is to set your repository to the branch you want to merge with, and then run
If you run
you will see the file already staged...
Then run
Simple.
这是我合并选择性文件的工作流程。
This is my workflow for merging selective files.
我发现 这篇文章包含最简单的答案。 只需执行以下操作:
示例
将 .gitignore 文件从branchB 拉入当前分支:
有关更多信息,请参阅帖子。
I found this post to contain the simplest answer. Merely do:
Example
Pulling .gitignore file from branchB into current branch:
See the post for more information.
这并不完全是您正在寻找的内容,但它对我很有用:
它是一些答案的混合。
It is not exactly what you were looking for, but it was useful to me:
It is a mix of some answers.
我遇到了与您上面提到的完全相同的问题。 但我发现 这个 Git 博客 更清楚地解释了答案。
来自上面链接的命令:
I had the exact same problem as mentioned by you above. But I found this Git blog clearer in explaining the answer.
Command from the above link:
对我来说, git reset --softbranch 是有选择地从另一个分支中选择更改的最简单方法,因为该命令将所有差异更改放入我的工作树中,并且我可以轻松地选择或恢复我需要的那个。
这样,我就可以完全控制提交的文件。
For me,
git reset --soft branch
is the easiest way to selectively pick the changes from another branch, since, this command puts in my working tree, all the diff changes, and I can easily pick or revert which one I need.In this way, I have full control over the committed files.
我会做一个
通过这种方式,您可以限制分支中文件模式的提交范围。
它是从 Re:如何仅拉取从一个分支到另一个分支的文件很少?
I would do a
This way you can limit the range of commits for a filepattern from a branch.
It is stolen from Re: How to pull only a few files from one branch to another?
您可以使用
read-tree
读取给定的远程树或将其合并到当前索引中,例如:要执行合并,请改用
-m
。另请参阅:如何在 Git 中合并子目录?
You can use
read-tree
to read or merge a given remote tree into the current index, for example:To perform the merge, use
-m
instead.See also: How do I merge a sub directory in Git?
我喜欢上一个“git-interactive-merge”答案,但还有一个更简单的答案。 让 Git 使用 Interactive 和 Onto 的变基组合为您完成此操作:
因此,您需要来自“feature”分支(分支点“A”)的 C1 和 C2,但目前不需要其他分支。
正如前面的答案,您将进入交互式编辑器,在其中选择 C1 和 C2 的“选择”行(如上所述)。 保存并退出,然后它将继续进行变基并为您提供分支“temp”以及 master + C1 + C2 处的 HEAD:
然后您可以将 master 更新为 HEAD 并删除临时分支,然后就可以了:
I like the previous 'git-interactive-merge' answer, but there's one easier. Let Git do this for you using a rebase combination of interactive and onto:
So the case is you want C1 and C2 from the 'feature' branch (branch point 'A'), but none of the rest for now.
Which, as in the previous answer, drops you in to the interactive editor where you select the 'pick' lines for C1 and C2 (as above). Save and quit, and then it will proceed with the rebase and give you branch 'temp' and also HEAD at master + C1 + C2:
Then you can just update master to HEAD and delete the temp branch and you're good to go:
我编写了自己的名为“pmerge”的脚本来部分合并目录。 这是一项正在进行的工作,我仍在学习 Git 和 Bash 脚本。
此命令使用 git merge --no-commit ,然后取消应用与提供的路径不匹配的更改。
用法:
git pmerge 分支路径
示例:
git mergedevelop src/
我还没有对其进行广泛的测试。 工作目录应该没有任何未提交的更改和未跟踪的文件。
I wrote my own script called 'pmerge' to partially merge directories. It's a work in progress and I'm still learning both Git and Bash scripting.
This command uses
git merge --no-commit
and then unapplies changes that don't match the path provided.Usage:
git pmerge branch path
Example:
git merge develop src/
I haven't tested it extensively. The working directory should be free of any uncommitted changes and untracked files.
按文件选择性合并/提交的简单方法:
A simple approach for selective merging/committing by file:
如果您没有太多已更改的文件,那么您将无需进行额外的提交。
1. 暂时复制分支
$ git checkout -b temp_branch
2. 重置为最后想要的提交
所需的提交次数
$ git reset --hard HEAD~n
,其中n
是返回3 。 从原始分支检出每个文件$ git checkout origin/original_branch filename.ext
现在,如果需要,您可以提交并强制推送(以覆盖远程)。
If you don't have too many files that have changed, this will leave you with no extra commits.
1. Duplicate branch temporarily
$ git checkout -b temp_branch
2. Reset to last wanted commit
$ git reset --hard HEAD~n
, wheren
is the number of commits you need to go back3. Checkout each file from original branch
$ git checkout origin/original_branch filename.ext
Now you can commit and force push (to overwrite remote), if needed.
如果您只需要合并特定目录并保持其他所有内容不变并保留历史记录,您可以尝试此操作...在
master
上创建一个新的target-branch
> 在进行实验之前。以下步骤假设您有两个分支
target-branch
和source-branch
,以及要合并的目录dir-to-merge
位于源分支
中。 另外,假设您不想更改目标中的其他目录并保留历史记录,例如 dir-to-retain 。 另外,假设dir-to-merge
中存在合并冲突。If you only need to merge a particular directory and leave everything else intact and yet preserve history, you could possibly try this... create a new
target-branch
off of themaster
before you experiment.The steps below assume you have two branches
target-branch
andsource-branch
, and the directorydir-to-merge
that you want to merge is in thesource-branch
. Also assume you have other directories likedir-to-retain
in the target that you don't want to change and retain history. Also, assumes there are merge conflicts in thedir-to-merge
.当两个分支的当前提交之间只有几个文件发生更改时,我通过遍历不同的文件来手动合并更改。
git difftool..
另请参阅
https://sites.google.com/site/icusite/setup/git-差异工具
When only a few files have changed between the current commits of the two branches, I manually merge the changes by going through the different files.
git difftool <branch-1>..<branch-2>
see also
https://sites.google.com/site/icusite/setup/git-difftool
我找到了这个问题的解决方案,它非常漂亮并且可以解决这个问题。 简单化。 所以我只是把它留在这里给我自己& 其他想要使用此解决方案的人。
回答
假设我位于 branch1 中,其中包含单个文件 file1.txt
现在,我想要将
file1.txt
与 branch2 中的另一个文件file2.txt
一起使用。所以命令应该是,
它会提示控制台提示您需要输入特定字符以反映当前分支(branch1)中的更改。 有时我用a来接受所有的帅哥。
我希望这个答案有帮助。
谢谢
I found a solution to this question which is really beautiful & simplistic. So I'm just keeping it here for myself & others who want to use this solution.
ANSWER
Say I am in branch1 which contains a single file, file1.txt
Now, I want to the
file1.txt
with another filefile2.txt
which is in branch2.So the command should be,
which prompts a console saying you need to input specific character to reflect the changes in your current branch which is branch1. Sometimes I use a to accept all the hunks.
I hope this answer is helpful.
Thanks
这会将 @masukomi 的
diff
/apply
answer 改编为一个 - liner:您位于
my_cool_branch
分支上。您想要从
other_branch
获取某些内容。你们都修改了
path/to/file
。您想要这些更改,但又不想抹掉自己的更改。
这会比较
path/to/file
的更改方式(通过diff
),然后暂存这些更改(通过apply
),没有承诺。====
存在一个更简单的场景。
您需要来自
other_branch
的path/to/file
文件。您的分支没有修改
path/to/file
。在这种情况下,您只需获取该分支的文件快照即可:
这将进行一项更改,修改
path/to/file
以匹配other_branch
中的内容。没有创建提交。 您拥有的任何其他暂存更改仍将保持暂存状态。
您不切换分支(即使使用了
checkout
< /a>)。通常,这会删除您自己对文件所做的更改,因此只有在我们知道不会丢失任何更改时才应该这样做。
This adapts @masukomi's
diff
/apply
answer into a one-liner:You are on a branch
my_cool_branch
.You want something from
other_branch
.You both modified
path/to/file
.You want those changes, but you don't want to obliterate your own changes.
This compares how
path/to/file
has changed (viadiff
), and then stages those changes (viaapply
), without committing.====
A simpler scenario exists.
You want
path/to/file
file fromother_branch
.Your branch did not modify
path/to/file
.In this situation, you can just grab that branch's snapshot of the file:
This stages a change that modifies
path/to/file
to match what's inother_branch
.No commit is created. Any other staged changes that you have, remain staged.
You do not switch branch (even though
checkout
was used).Ordinarily this would obliterate your own changes to the file, so we should only do this if we know we have no changes to lose.
我将集中精力解决我感兴趣的这个问题的子集:我有两个分支,我想将一个文件从一个分支伪合并到另一个分支。
(我说“伪合并”是因为我不需要或想要合并提交;我只想以我认为合适的方式组合文件两个版本的贡献。)
我的方法基于https://stackoverflow.com/a/39916536/341994 中采用的方法。 不幸的是,这个问题被作为重复项关闭(在我看来,这是错误的:它不是这个问题的重复项,并且回答并关闭为重复项是错误的,这就是回答者在那里所做的)。 但这个答案有一些问题,所以我对这个方法进行了现代化和清理。 我使用
restore
,而不是checkout
和reset
,而且我也懒得提交任何不需要的内容。好吧,假设我有三个文件:
但我只想从
otherbranch
伪合并其中一个,a
。 让我们看一下它们,看看情况会是什么样子。 这是我的版本:这是其他分支的版本:
现在这里的技巧是我们将使用索引作为便笺簿(毕竟,这就是它的用途)。 因此,我们首先(第 1 步)确保我们的版本已复制到索引中:
现在(第 2 步)我们可以使用
restore
从otherbranch
获取版本(现在,restore
比checkout
更好,因为它让我们可以更清楚地交谈):乍一看,这看起来很糟糕。 我们现在已经用
otherbranch
的版本完全覆盖了 a,如您所见:但不用担心! 之前版本的 a 仍在索引中,如您所见:
很好,现在我们已准备好进行关键操作(步骤 3)。 我们对文件从工作树到索引进行交互式补丁
添加
。我们可以说 git add -p a 来启动交互式补丁过程,在这种情况下,我们一次会得到一个块。 但在这种情况下,只有一个大块,无论如何我都想编辑它,所以我说:
结果是我们在编辑器中打开了一个差异补丁文件! 它看起来像这样:
通过仔细编辑,我们现在可以决定我们想要接受哪些部分以及我们不接受哪些部分。 让我们接受“第六行”,但不接受“第二行已编辑”。 因此,我们进行编辑,如下所示:
我们关闭编辑器,并将补丁应用于 a 的索引版本。 但我们还没有完全完成! a 的
otherbranch
版本仍然位于工作树中:我们喜欢的版本在索引中,还记得吗? 为了得到它,(第 4 步)我们只需简单明了地调用
git Restore
(同样,这是现代方式;restore
比reset
更好)并且可以应用于单个文件):现在我们的a是正确的,我们都完成了:
我们可以在这一点上提交,但我们不必这样做; 我们已经完成了我们计划完成的任务。
I'm going to concentrate on the subset of this problem that was of interest to me: I have two branches and I want to pseudo-merge one file from one into the other.
(I say "pseudo-merge" because I don't need or want a merge commit; I just want to combine the contributions of both versions of the file, in the way that I see fit.)
My approach is based on the approach taken in https://stackoverflow.com/a/39916536/341994. Unfortunately that question is closed as a duplicate (wrongly, in my opinion: it's not a duplicate of this question, and it is wrong to answer-and-close-as-duplicate which is what the answerer did there). But there are some things wrong with that answer, so I've modernized and cleaned up the approach. Instead of
checkout
andreset
, I userestore
, and I don't bother to commit anything I don't have to.Okay, so imagine I have three files:
But I only want to pseudo-merge one of them,
a
, fromotherbranch
. Let's peek at them to see what the situation will look like. Here's my version:Here's otherbranch's version:
Now the trick here is that we're going to use the index as a scratch pad (which is, after all, what it is for). So we start (STEP 1) by making sure that our version is copied into the index:
Now (STEP 2) we can use
restore
to fetch the version fromotherbranch
(nowadays,restore
is better thancheckout
as it lets us talk more clearly):At first blush, this looks bad. We have now completely overwritten our a with the version from
otherbranch
, as you can see:But not to worry! The previous version of a is still in the index, as you can see:
Very well, now we're ready for the key move (STEP 3). We do an interactive patch
add
of our file from the working tree to the index.We could say
git add -p a
to start the interactive patch process, in which case we are fed hunks one at a time. But in this case there is just one hunk, and I want to edit it anyway, so I say:The result is that we open a patch file of diffs in our editor! It looks like this:
By careful editing we can now decide what parts we want to accept and what parts we don't. Let's accept "line six" but not "line two edited". So we edit to look like this:
We close the editor and the patch is applied to the index version of a. But we are not quite finished! The
otherbranch
version of a is still sitting in the working tree:The version we like is in the index, remember? To get it, (STEP 4) we just call
git restore
plain and simple (again, this the modern way;restore
is nicer thanreset
and can apply to a single file):Now our a is correct, and we're all finished:
We could at this point commit, but we don't have to; we've accomplished what we set out to accomplish.
我想要的:以交互方式从分支(有几个混乱的提交)中挑选大块到新分支中的干净提交中。
如果该 diff 中有任何二进制文件,则
git diff
+git apply
将不起作用。我的做法:
What I want: Interactively pick hunks from a branch (which had several messy commits) into a clean commit in a new branch.
git diff
+git apply
won't work if you had any binary files in that diff.My approach:
如果您是 Gitkraken 用户这里有一个小指南
总之:
If you are a Gitkraken User here you have a small guide
In summary: