我有两个分支,email
和 staging
。 staging
是最新的,我不再需要 email
分支中的旧更改,但我不想删除它们。
所以我只想将 staging
的所有内容转储到 email
中,以便它们都指向同一个提交。那可能吗?
您可以使用 'ours' merge strategy:
$ git checkout staging
$ git merge -s ours email # Merge branches, but use our (=staging) branch head
$ git checkout email
$ git merge staging
编辑 2020-07-30:
我对这个问题和可能的解决方案进行了更多思考。如果您绝对需要以正确的顺序合并父级,需要通过单个命令行调用执行此操作,并且不介意运行管道命令,您可以执行以下操作:
$ git checkout A
$ git merge --ff-only $(git commit-tree -m "Throw away branch 'A'" -p A -p B B^{tree})
这基本上类似于(不存在的)merge -s theirs
策略。您可以在 plumbing
branch of the demo repository 中找到生成的历史记录
与 -s ours
开关相比,它的可读性和记忆力都不是很好,但它确实可以完成工作。结果树再次与分支 B 相同:
$ git rev-parse A^{tree} B^{tree} HEAD^{tree}
3859ea064e85b2291d189e798bfa1bff87f51f3e
0389f8f2a3e560b639d82597a7bc5489a4c96d44
0389f8f2a3e560b639d82597a7bc5489a4c96d44
编辑 2020-07-29:
关于 -s ours
和 -X ours
(后者等同于 -s recursive --strategy-option ours
)之间的区别似乎存在很多混淆。这里有一个小例子来展示使用这两种方法的两个结果。我还建议阅读(Git Merging) When to use 'ours' strategy, 'ours' option and 'theirs' option?的问答
首先,设置一个包含 2 个分支和 3 个提交(1 个基本提交,每个分支 1 个提交)的存储库。您可以找到示例存储库 on GitHub
$ git init
$ echo 'original' | tee file1 file2 file3
$ git commit -m 'initial commit'
$ git branch A
$ git branch B
$ git checkout A
$ echo 'A' > file1
$ git commit -m 'change on branch A' file1
$ git checkout B
$ echo 'B' > file2
$ git commit -m 'change on branch B' file2
现在,让我们尝试一下策略选项(我们使用他们的还是我们的并不重要):
$ git merge -X ours A
$ cat file*
A
B
original
我们最终合并了两个分支的内容(示例 repo 中的分支“strategy-option”)。将其与使用合并策略(在执行后续步骤之前重新初始化存储库或重置分支)进行比较:
$ git merge -s ours A
$ cat file*
original
B
original
结果完全不同(示例回购中的分支“合并策略”)。使用策略选项,我们得到两个分支的合并结果,使用策略我们丢弃另一个分支中发生的任何更改。
您还会注意到,由合并策略创建的提交实际上指向与“我们的”分支的最新提交完全相同的树,而策略选项创建了一个新的、以前看不见的树:
$ git rev-parse A^{tree} B^{tree} merge-strategy^{tree} strategy-option^{tree}
3859ea064e85b2291d189e798bfa1bff87f51f3e
0389f8f2a3e560b639d82597a7bc5489a4c96d44
0389f8f2a3e560b639d82597a7bc5489a4c96d44
5b09d34a37a183723b409d25268c8cb4d073206e
OP 确实要求“我不再需要 [...] 分支中的旧更改”和“所以我只想将 [A] 的所有内容转储到 [B]”,这与策略选项无关。使用“我们的”合并策略是许多可能性中的一种,但可能是最简单的(其他可能性包括使用 Git 的低级命令,例如 write-tree
和 commit-tree
)。
如果您只是希望“电子邮件”和“暂存”两个分支相同,则可以标记“电子邮件”分支,然后将“电子邮件”分支重置为“暂存”分支:
$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging
您还可以在“电子邮件”分支上重新设置“暂存”分支。但结果将包含两个分支的修改。
git checkout
,据我所知 git check
不存在
email
分支的头应该只指向 staging
的同一个头,并且它们都将具有相同的提交,相同的历史记录。
我已经看到了几个答案,这是唯一可以让我在没有任何冲突的情况下解决这个问题的程序。
如果您想要从 branch_old 中的 branch_new 进行所有更改,则:
git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new
一旦应用了这四个命令,您就可以毫无问题地推送 branch_old
其他答案给了我正确的线索,但它们并没有完全帮助。
这对我有用:
$ git checkout email
$ git tag old-email-branch # This is optional
$ git reset --hard staging
$
$ # Using a custom commit message for the merge below
$ git merge -m 'Merge -s our where _ours_ is the branch staging' -s ours origin/email
$ git push origin email
如果没有与 ours 策略合并的第四步,则推送被视为非快进更新,将被拒绝(被 GitHub 拒绝)。
merge -m 'This is not my beautiful house.' -s ours origin/email
。
如果你和我一样不想处理合并,你可以执行上述步骤,除了使用强制而不是合并,因为它会创建一个分散注意力的日志文件痕迹:
git checkout email
git reset --hard staging
git push origin email --force
注意:仅当您真的不想再在电子邮件中看到这些内容时。
git tag old-email-branch
。然后,您将能够通过标记版本保留以前的内容。
警告:这会删除电子邮件分支上的所有提交。这就像删除电子邮件分支并在暂存分支的头部重新创建它。
最简单的方法:
//the branch you want to overwrite
git checkout email
//reset to the new branch
git reset --hard origin/staging
// push to remote
git push -f
现在电子邮件分支和暂存是相同的。
email
分支上的所有提交。这就像删除 email
分支并在 staging
分支的头部重新创建它。
我想合并两个分支,以便用 new_branch
中的内容更新 old_branch
中的所有内容
对我来说,这就像一个魅力:
$ git checkout new_branch
$ git merge -m 'merge message' -s ours origin/old_branch
$ git checkout old_branch
$ git merge new_branch
$ git push origin old_branch
其他答案看起来不完整。我已经在下面进行了完整的尝试,并且效果很好。
注意:1. 为了安全起见,在您尝试以下操作之前,请先复制您的存储库。
详细信息: 1. 所有开发都发生在 dev 分支 2. qa 分支只是 dev 的同一个副本 3. 有时,需要将 dev 代码移动/覆盖到 qa 分支
所以我们需要从 dev 分支覆盖 qa 分支
第 1 部分:使用以下命令,旧 qa 已更新为较新的开发:
git checkout dev
git merge -s ours qa
git checkout qa
git merge dev
git push
最后推送的自动评论如下:
// Output:
// *<MYNAME> Merge branch 'qa' into dev,*
这个评论看起来是相反的,因为上面的序列也看起来是相反的
第2部分:
下面是 dev 中意想不到的新本地提交,不必要的,所以我们需要扔掉,让 dev 保持不变。
git checkout dev
// Output:
// Switched to branch 'dev'
// Your branch is ahead of 'origin/dev' by 15 commits.
// (use "git push" to publish your local commits)
git reset --hard origin/dev
// Now we threw away the unexpected commits
第 3 部分:验证一切是否符合预期:
git status
// Output:
// *On branch dev
// Your branch is up-to-date with 'origin/dev'.
// nothing to commit, working tree clean*
就这样。 1. 旧的 qa 现在被新的 dev 分支代码覆盖 2. 本地是干净的(远程源/开发未触及)
怎么样:
git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease
你想要的是这个(实际上与当前接受的答案完全相反):
git checkout email
git merge --strategy-option=theirs staging
这是做什么的:
电子邮件分支文件现在将与暂存分支完全相同
电子邮件分支的历史将被维护
暂存分支的历史记录将添加到电子邮件历史记录中
作为附加值,如果您不想要 staging
分支的所有历史记录,您可以使用 squash
将其汇总为单个提交消息。
git checkout email
git merge --squash --strategy-option=theirs staging
git commit -m "Single commit message for squash branch's history here'
总而言之,第二个版本的作用是:
电子邮件分支文件现在将与暂存分支完全相同
电子邮件分支的历史将被维护
单个提交将添加到电子邮件分支的历史记录之上。此提交将代表暂存分支中发生的所有更改
--strategy-option=theirs
git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging
这不会改变原来的较新分支,并让您有机会在最终提交之前进行进一步修改。
git checkout new -b tmp
git merge -s ours old -m 'irrelevant'
git checkout old
git merge --squash tmp
git branch -D tmp
#do any other stuff you want
git add -A; git commit -m 'foo' #commit (or however you like)
我尝试了@knittl 的 write-tree/commit-tree
方法。
branch-a:保留的分支
branch-b:废弃的分支
// goto branch-a branch
$ git checkout branch-a
$ git write-tree
6fa6989240d2fc6490f8215682a20c63dac5560a // echo tree id? I guess
$ git commit-tree -p branch-a -p branch-b 6fa6989240d2fc6490f8215682a20c63dac5560a
<type some commit message end with Ctrl-d>
20bc36a2b0f2537ed11328d1aedd9c3cff2e87e9 // echo new commit id
$ git reset --hard 20bc36a2b0f2537ed11328d1aedd9c3cff2e87e9
这将合并两个分支 old
和 new
并在每次合并冲突时选择 new
版本:
git checkout old
git merge new
git checkout --theirs .
git add .
git commit
不定期副业成功案例分享
;
?我没有;
,它似乎工作。这个答案也不完整,第三步是检查旧分支(电子邮件),然后再次与登台合并。git rebase -s theirs <oldbranc> <newbranch>
也可以(无论您是哪个分支)。请注意,在 rebase 中,“他们的”实际上是新分支,因为“我们的”是我们当前应用提交的头部。