【发布时间】:2011-06-05 04:37:09
【问题描述】:
我有两个分支,email 和 staging。 staging 是最新的,我不再需要 email 分支中的旧更改,但我不想删除它们。
所以我只想将staging 的所有内容转储到email,以便它们都指向同一个提交。这可能吗?
【问题讨论】:
标签: git
我有两个分支,email 和 staging。 staging 是最新的,我不再需要 email 分支中的旧更改,但我不想删除它们。
所以我只想将staging 的所有内容转储到email,以便它们都指向同一个提交。这可能吗?
【问题讨论】:
标签: git
这将合并两个分支 old 和 new 并在每次合并冲突时选择 new 版本:
git checkout old
git merge new
git checkout --theirs .
git add .
git commit
【讨论】:
您可以使用'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
我们最终得到了两个分支内容的 merge(示例 repo 中的分支“strategy-option”)。将其与使用合并策略(在执行后续步骤之前重新初始化您的存储库或重置分支)进行比较:
$ git merge -s ours A
$ cat file*
original
B
original
结果完全不同(示例 repo 中的分支“merge-strategy”)。使用策略选项,我们得到两个分支的合并结果,使用策略我们丢弃另一个分支中发生的任何更改。
您还会注意到,merge-strategy 创建的提交实际上与“我们的”分支的最新提交指向完全相同的树,而 strategy-option 创建了一个新的、以前看不见的树:
$ 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)。
【讨论】:
; 在每个命令的末尾?我没有;,它似乎工作正常。这个答案也不完整,第三步是检查旧分支(电子邮件),然后再次与 staging 合并。
git rebase -s theirs <oldbranc> <newbranch> 也可以(无论您是哪个分支)。请注意,在 rebase 中,“他们的”实际上是新分支,因为“我们的”是我们当前应用提交的头部。
警告:这将删除电子邮件分支上的所有提交。这就像删除电子邮件分支并在暂存分支的头部重新创建它。
最简单的方法:
//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 分支的头部重新创建它。
我尝试了@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
【讨论】:
你想要的是这个(实际上与当前接受的答案完全相反):
git checkout email
git merge --strategy-option=theirs staging
这是做什么的:
email 分支文件现在将与staging 分支完全相同相同email 分支的历史将被维护staging 分支的历史记录将添加到email 历史记录作为附加值,如果您不想要 staging 分支的所有历史记录,可以使用 squash 将其汇总为单个提交消息。
git checkout email
git merge --squash --strategy-option=theirs staging
git commit -m "Single commit message for squash branch's history here'
总之,第二个版本的作用是:
email 分支文件现在将与staging 分支完全相同相同email 分支的历史将被维护email 分支的历史记录之上添加一个提交。此提交将代表 staging 分支中发生的所有更改【讨论】:
--strategy-option=theirs
这不会改变原来的新分支,并让您有机会在最终提交之前进行进一步的修改。
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)
【讨论】:
其他答案看起来不完整。
我已经在下面进行了完整的尝试,并且效果很好。
注意:
1. 为安全起见,在您尝试以下操作之前复制您的存储库。
详情:
1. 所有开发都发生在 dev 分支中
2. qa 分支只是 dev 的同一个副本
3. 有时,开发代码需要移动/覆盖到 qa 分支
所以我们需要从 dev 分支覆盖 qa 分支
第 1 部分:
使用以下命令,旧的 qa 已更新为较新的 dev:
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 现在被新的开发分支代码覆盖
2.本地干净(远程源/开发未触及)
【讨论】:
我想合并两个分支,以便old_branch 中的所有内容都可以使用new_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
【讨论】:
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 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。
如果你只是想让'email'和'staging'两个分支相同,你可以标记'email'分支,然后将'email'分支重置为'staging'分支:
$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging
您还可以在“电子邮件”分支上重新设置“暂存”分支。但是结果会包含两个分支的修改。
【讨论】:
git checkout,据我所知git check不存在
email 分支的头部应该只指向 staging 的同一个头部,并且它们都将具有相同的提交、相同的历史记录。
怎么样:
git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease
【讨论】:
我已经看到了几个答案,这是唯一能让我在没有任何冲突的情况下解决这个问题的程序。
如果您想要从 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 reset --hard staging
git push origin email --force
注意:这仅适用于您真的不想再在电子邮件中看到这些内容。
【讨论】:
git tag old-email-branch。然后,您将能够通过标记版本保留以前的内容。