如何“覆盖”而不是“合并”Git 中另一个分支上的一个分支?
我有两个分支,email
和 staging
。 staging
是最新的,我不再需要 email
分支中的旧更改,但我不想删除它们。
所以我只想将 staging
的所有内容转储到 email
中,以便它们都指向相同的提交。这可能吗?
I have two branches, email
and staging
. staging
is the latest one and I no longer need the old changes in email
branch, yet I don't want to delete them.
So I just want to dump all the contents of staging
into email
so that they both point to the same commit. Is that possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
您可以使用“我们的”合并策略 :
该问题需要保留
email
分支的提交。它们不能被设置为不可访问,这排除了任何基于重置的方法或删除并重新创建分支。为了保持两个分支的提交均可访问,必须存在一个或多个指向这些提交的引用。您始终可以保留两个引用(
staging
和email
),但问题要求删除其中一个引用。因此,需要以某种方式合并分支。编辑2020-07-30:
我对这个问题和可能的解决方案进行了更多思考。如果您绝对需要以正确的顺序合并父项,需要使用单个命令行调用来执行此操作,并且不介意运行管道命令,您可以执行以下操作:
这基本上就像(不存在的)< code>merge -s 他们的 策略。
您可以在演示存储库的
plumbing
分支中找到生成的历史记录与
-s ours
开关相比,可读性较差,也不太容易记住,但它可以完成任务。生成的树再次与分支 B 相同:编辑 2020-07-29:
对于
-s ours
和-X ours
(后者相当于-s recursive --strategy-option ours
)。这是一个小示例,显示使用这两种方法的两个结果。我还建议阅读 (Git 合并)何时使用“我们的”策略、“我们的”选项和“他们的”选项?首先,设置一个具有 2 个分支和 3 个提交的存储库(1 个基本提交,每个分支 1 个提交)。您可以在 GitHub 上找到示例存储库。
现在,让我们尝试一下策略选项 (如果我们使用他们的或我们的来解释并不重要):
我们最终会合并两个分支的内容(示例存储库中的分支“strategy-option”)。与使用合并策略(在执行后续步骤之前重新初始化存储库或重置分支)进行比较:
结果完全不同(示例存储库中的分支“合并策略”)。通过策略选项,我们得到两个分支的合并结果,通过策略我们丢弃另一个分支中发生的任何更改。
您还会注意到,合并策略创建的提交实际上指向与“我们的”分支的最新提交完全相同的树,而策略选项创建了一个新的、以前未见过的树:
OP确实要求“我不再需要 […] 分支中的旧更改”和“因此我只想将 [A] 的所有内容转储到 [B] 中”,这是不可能使用策略选项来实现的 >。使用“我们的”合并策略是多种可能性中的一种,但可能是最简单的(其他可能性包括使用 Git 的低级命令,例如
write-tree
和commit-tree
)。You can use the 'ours' merge strategy:
The question requires the commits of the
email
branch to be kept. They must not be made unreachable, which rules out anyreset
-based approaches or deleting and recreating the branch.To keep commits of both branches reachable, one or more references must exist that point to those commits. You can always keep two references (
staging
andemail
), but the question asks to get rid of one of the refs. Therefore, the branches need to be merged somehow.EDIT 2020-07-30:
I thought a bit more about this question and possible solutions. If you absolutely require the merge parents in the correct order, need to perform this action with a single command line invocation, and don't mind running plumbing commands, you can do the following:
This basically acts like the (non-existent)
merge -s theirs
strategy.You can find the resulting history in the
plumbing
branch of the demo repositoryNot very readable and not as easy to remember compared to the
-s ours
switch, but it does the job. The resulting tree is again the same as branch B:EDIT 2020-07-29:
There seems to be a lot of confusion as to what the difference between
-s ours
and-X ours
(the latter being equivalent to-s recursive --strategy-option ours
) is. Here's a small example to show the two results from using these two methods. I also recommend reading the question and answers of (Git Merging) When to use 'ours' strategy, 'ours' option and 'theirs' option?First, setup a repository with 2 branches and 3 commits (1 base commit, and 1 commit per branch). You can find the sample repository on GitHub
Now, let's try the strategy option (doesn't really matter if we use theirs or ours for this explanation):
We end up with a merge of both branches' contents (branch "strategy-option" in the sample repo). Compare that to using the merge strategy (re-init your repository or reset branch, before executing the next steps):
The result is quite different (branch "merge-strategy" in the sample repo). With the strategy option, we get a merge result of both branches, with the strategy we throw away any changes which happened in the other branch.
You will also notice that the commit created by the merge-strategy in fact points to the exact same tree as the latest commit of "our" branch, while the strategy-option created a new, previously-unseen tree:
OP indeed asked for "I no longer need the old changes in […] branch" and "So I just want to dump all the contents of [A] into [B]", which is not possible to do with a strategy option. Using the 'ours' merge strategy is one possibility of many, but likely the easiest (other possibilities include using low level commands of Git such as
write-tree
andcommit-tree
).如果您只是希望“email”和“staging”这两个分支相同,则可以标记“email”分支,然后将“email”分支重置为“staging”分支:
您还可以重新设置“staging”分支“电子邮件”分支上的分支。但结果将包含两个分支的修改。
If you just want the two branches 'email' and 'staging' to be the same, you can tag the 'email' branch, then reset the 'email' branch to the 'staging' one:
You can also rebase the 'staging' branch on the 'email' branch. But the result will contains the modification of the two branches.
我已经看到了几个答案,这是唯一可以让我在没有任何冲突的情况下解决该问题的程序。
如果您想要从branch_new到branch_old的所有更改,那么:
一旦应用了这四个命令,您就可以毫无问题地推送branch_old
I've seen several answers and that's the only procedure that let me fix that without any conflicts.
If you want all changes from branch_new in branch_old, then:
once applied those four commands you can push the branch_old without any problem
其他答案给了我正确的线索,但并没有完全帮助。
这对我有用:
如果没有与我们的策略合并的第四步,推送将被视为非快进更新,并将被拒绝(被 GitHub 拒绝)。
The other answers gave me the right clues, but they didn't completely help.
Here's what worked for me:
Without the fourth step of merging with the ours strategy, the push is considered a non-fast-forward update and will be rejected (by GitHub).
如果您像我一样并且不想处理合并,则可以执行上述步骤,但使用强制而不是合并,因为它会创建分散注意力的日志文件记录:
注意:只有当您真的从不这样做时,才可以这样做想再次查看电子邮件中的内容。
If you're like me and you don't want to deal with merging, you can do the above steps, except use force instead of merge, because it will create a distracting log paper trail:
Note: This is only if you REALLY never want to see the stuff in email again.
最简单的方法:
现在电子邮件分支和暂存是相同的。
The easiest way to do it:
Now the email branch and the staging are the same.
我想合并两个分支,以便用
new_branch
中的内容更新old_branch
中的所有内容对我来说这就像一个魅力:
I wanted to merge two branches so that all the contents in
old_branch
to be updated with the contents fromnew_branch
For me this worked like a charm:
其他答案看起来不完整。
我已经在下面进行了完整的尝试,效果很好。
注意:
1. 为了安全起见,在尝试以下操作之前先复制您的存储库。
详情:
1. 所有开发都发生在 dev 分支
2. qa 分支只是 dev 的同一个副本
3. 有时,开发代码需要移动/覆盖到 qa 分支,
因此我们需要从 dev 分支覆盖 qa 分支
第 1 部分:
使用以下命令,旧的质量保证已更新为较新的开发人员:
最后推送的自动注释如下:
此注释看起来相反,因为上面的序列也看起来相反
第 2 部分:
下面是意外的新本地提交开发,不必要的
所以,我们需要扔掉,让开发保持原样。
第 3 部分:
验证一切是否符合预期:
仅此而已。
1. 旧的 qa 现在被新的 dev 分支代码覆盖
2.本地是干净的(远程origin/dev未受影响)
Other answers looked incomplete.
I have tried below in full, and it worked fine.
NOTE:
1. Make a copy of your repository before you try below, to be on safe side.
Details:
1. All development happens in dev branch
2. qa branch is just the same copy of dev
3. Time to time, dev code needs to be moved/overwrite to qa branch
so we need to overwrite qa branch, from dev branch
Part 1:
With below commands, old qa has been updated to newer dev:
Automatic comment for last push gives below:
This comment looks reverse, because above sequence also looks reverse
Part 2:
Below are unexpected, new local commits in dev, the unnecessary ones
so, we need to throw away, and make dev untouched.
Part 3:
Verify everything is as expected:
That's all.
1. old qa is now overwritten by new dev branch code
2. local is clean (remote origin/dev is untouched)
怎么样:
How about:
您想要的是这样的(实际上与当前接受的答案完全相反):
它的作用是:
email
分支文件现在将完全与staging相同
分支email
分支的历史记录将被维护staging
分支的历史记录将被添加到email
历史记录中作为附加值,如果您不这样做如果想要所有
staging
分支的历史记录,您可以使用squash
将其汇总为单个提交消息。总而言之,第二个版本的作用是:
email
分支文件现在完全与staging
分支email 分支的历史记录将被维护
email
分支的历史记录之上。此提交将代表staging
分支中发生的所有更改What you want is this (actually the exact inverse of the currently accepted answer):
What this does is:
email
branch files will now be exactly the same asstaging
branchemail
branch's history will be maintainedstaging
branch's history will be added toemail
historyAs added value, if you don't want all of
staging
branch's history, you can usesquash
to summarize it into a single commit message.So in summary, what this second version does is:
email
branch files will now be exactly the same asstaging
branchemail
branch's history will be maintainedemail
branch's history. This commit will represent ALL the changes that took place in thestaging
branch我尝试了 @knittl 的
write-tree/commit-tree
方法。branch-a:保留的分支
branch-b:废弃的分支
I tried @knittl's
write-tree/commit-tree
approach.branch-a: the kept branch
branch-b: the abandoned branch
这将合并两个分支
old
和new
并在每次合并冲突时选择new
版本:This will merge two branches
old
andnew
and choose thenew
version on every merge conflict:这不会改变原始的较新分支,并让您有机会在最终提交之前进行进一步修改。
This one doesn't alter the original newer branch, and gives you the opportunity to make further modifications before final commit.
我有一个类似的问题,但所有其他答案都使用合并,我想使用变基而不是合并。
当前状态
所需状态
因此,要获得此状态,请从交互式变基开始,
将第一项从“选择”更改为“编辑”。其余的保留为“选择”。第一次 rebase 后 git 停止后,我们将把第一次 rebase 变成覆盖,
这应该将 A1 复制到索引。仔细检查一切是否正确,然后继续,git 将处理剩下的事情
I had a similar problem, but all the other answers use merge, and I wanted to use rebase rather than merge.
current state
desired state
So to get this, start with an interactive rebase
change first item from 'pick' to 'edit'. Keep the rest as 'pick'. After git stops after the first rebase, we will turn the first rebase into an overwrite
This should copy A1 to index. Double check everything is correct and then continue and git will take care of the rest