[英]Is there a "theirs" version of "git merge -s ours"?
使用git merge
將主題分支“B”合並到“A”時,我遇到了一些沖突。 我知道所有的沖突都可以使用“B”中的版本來解決。
我知道git merge -s ours
。 但我想要的是git merge -s theirs
類的東西。
為什么不存在? 在與現有git
命令發生沖突合並后,如何獲得相同的結果? ( git checkout
來自 B 的每個未合並文件)
只是丟棄分支 A 中的任何內容(合並提交點到樹的 B 版本)的“解決方案”不是我想要的。
將-X
選項添加到theirs
. 例如:
git checkout branchA
git merge -X theirs branchB
一切都會以所需的方式合並。
我看到的唯一導致問題的是文件是否從 branchB 中刪除。 如果除 git 之外的其他東西進行了刪除,它們會顯示為沖突。
修復很容易。 只需使用已刪除文件的名稱運行git rm
:
git rm {DELETED-FILE-NAME}
之后, -X theirs
的-X theirs
應該按預期工作。
當然,使用git rm
命令進行實際刪除將首先防止沖突發生。
注意:還存在更長的形式選項。
要使用它,請替換:
-X theirs
與:
--strategy-option=theirs
將 branchB 合並到我們已檢出的 branchA 中的可能且經過測試的解決方案:
# in case branchA is not our current branch
git checkout branchA
# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB
# make temporary branch to merged commit
git branch branchTEMP
# get contents of working tree and index to the one of branchB
git reset --hard branchB
# reset to our merged commit but
# keep contents of working tree and index
git reset --soft branchTEMP
# change the contents of the merged commit
# with the contents of branchB
git commit --amend
# get rid off our temporary branch
git branch -D branchTEMP
# verify that the merge commit contains only contents of branchB
git diff HEAD branchB
要自動化它,您可以使用 branchA 和 branchB 作為參數將其包裝到腳本中。
該解決方案保留了合並提交的第一個和第二個父項,正如您對git merge -s theirs branchB
期望git merge -s theirs branchB
。
舊版本的 git 允許您使用“他們的”合並策略:
git pull --strategy=theirs remote_branch
但這已被刪除,正如Junio Hamano (Git 維護者)在此消息中所解釋的那樣。 如鏈接中所述,您可以這樣做:
git fetch origin
git reset --hard origin
但是請注意,這與實際合並不同。 您的解決方案可能是您真正正在尋找的選項。
並不完全清楚您想要的結果是什么,因此在答案和他們的評論中對“正確”的做法有些困惑。 我嘗試給出一個概述並看到以下三個選項:
嘗試合並並使用 B 解決沖突
這不是“他們的git merge -s ours
版本”而是“他們的git merge -X ours
版本”(這是git merge -s recursive -X ours
縮寫):
git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB
這就是例如Alan W. Smith 的回答所做的。
僅使用來自 B 的內容
這會為兩個分支創建一個合並提交,但會丟棄來自branchA
所有更改並僅保留來自branchB
的內容。
# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB
# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA
# Set branchA to current commit and check it out.
git checkout -B branchA
請注意,合並提交的第一個父級現在來自branchB
,只有第二個來自branchA
。 這就是例如Gandalf458 的回答所做的。
僅使用來自 B 的內容並保持正確的父順序
這是真正的“他們的git merge -s ours
版本”。 它與之前的選項具有相同的內容(即僅來自branchB
)但父母的順序是正確的,即第一個父母來自branchA
,第二個來自branchB
。
git checkout branchA
# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB
# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB
# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA
# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA
# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD
這就是Paul Pladijs 的回答所做的(不需要臨時分支)。
從現在開始,我使用了 Paul Pladijs 的答案。 我發現,您可以進行“正常”合並,但會發生沖突,因此您可以
git checkout --theirs <file>
通過使用來自另一個分支的修訂來解決沖突。 如果對每個文件都執行此操作,您將獲得與預期相同的行為
git merge <branch> -s theirs
無論如何,工作量比合並策略要多! (這是用 git 版本 1.8.0 測試的)
使用 git merge 合並“A”中的主題分支“B”時,我遇到了一些沖突。 我>知道使用“B”中的版本可以解決所有沖突。
我知道 git merge -s 我們的。 但我想要的是 git merge >-s 他們的東西。
我假設您從 master 創建了一個分支,現在想要合並回 master,覆蓋 master 中的任何舊內容。 當我看到這篇文章時,這正是我想做的。
做你想做的事情,除了先把一個分支合並到另一個分支。 我就是這樣做的,而且效果很好。
git checkout Branch
git merge master -s ours
然后,結帳 master 並將您的分支合並到其中(現在會順利進行):
git checkout master
git merge Branch
我解決了我的問題
git checkout -m old
git checkout -b new B
git merge -s ours old
如果您在分支 A 上,請執行以下操作:
git merge -s recursive -X theirs B
在 git 版本 1.7.8 上測試
要真正正確地進行合並,該合並僅從您正在合並的分支中獲取輸入,您可以這樣做
git merge --strategy=ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply --reverse --index
git commit --amend
在我所知道的任何情況下都不會有沖突,您不必創建額外的分支,它的作用就像一個正常的合並提交。
然而,這對子模塊並不友好。
為什么不存在?
雖然我在“用於使一個分支像另一個分支一樣的 git 命令”中提到如何模擬git merge -s theirs
,但請注意 Git 2.15(2017 年第 4 季度)現在更加清晰:
用於合並的 '
-X<option>
' 的文檔被誤導性地編寫,以表明存在“-s theirs
”,但事實並非如此。
請參閱Junio C gitster
( gitster
) 的commit c25d98b (2017 年 9 月 25 日) 。
(由Junio C gitster
合並-- gitster
-- in commit 4da3e23 ,2017 年 9 月 28 日)
合並策略:避免暗示“
-s theirs
”存在
-Xours
合並選項的描述有一個括號,告訴讀者它與-s ours
非常不同,這是正確的,但-Xtheirs
描述不小心說“這與ours
的相反”,給出一種錯誤的印象,讀者也需要被警告,它與-s theirs
非常不同,實際上甚至不存在。
-Xtheirs
是應用於遞歸策略的策略選項。 這意味着遞歸策略仍然會合並它可以合並的任何東西,並且只會在發生沖突時退回到“ theirs
”邏輯。
最近在 2017 年 9 月的帖子中重新討論了theirs
合並策略的相關性與否。
它確認較舊的(2008)線程
簡而言之,前面的討論可以總結為“我們不想要 '
-s theirs
',因為它鼓勵錯誤的工作流程”。
它提到了別名:
mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -
Yaroslav Halchenko 試圖再次倡導該策略,但 Junio C. Hamano 補充道:
我們的和他們的不對稱的原因是因為你是你而不是他們——我們的歷史和他們的歷史的控制和所有權是不對稱的。
一旦你決定他們的歷史是主線,你寧願把你的開發線當作一個分支並在那個方向上進行合並,即結果合並的第一個父級是他們歷史上的提交,第二個是提交父母是你歷史上最后一個壞人。 因此,您最終會使用“
checkout their-history && merge -s ours your-history
”來保持第一父母身份的合理性。那時,使用“
-s ours
”不再是缺少“-s theirs
”的解決方法。
它是所需語義的適當部分,即從幸存的規范歷史線的角度來看,您希望保留它所做的事情,使另一條歷史線所做的事情無效。
Junio 補充道,正如Mike Beaton所評論的:
git merge -s ours <their-ref>
有效地表示“將在他們的分支上由<their-ref>
組成的提交標記為永久忽略的提交”;
這很重要,因為如果您隨后從其分支的后續狀態合並,則將引入他們以后的更改,而不會引入被忽略的更改。
請參閱Junio Hamano 被廣泛引用的答案:如果您要丟棄已提交的內容,只需丟棄提交,或者無論如何將其保留在主要歷史記錄之外。 為什么將來要打擾每個人閱讀來自沒有什么可提供的提交的提交消息?
但有時有管理要求,或者可能是其他原因。 對於那些您確實必須記錄沒有任何貢獻的提交的情況,您需要:
(編輯:哇,我之前是不是弄錯了。這個有效。)
git update-ref HEAD $(
git commit-tree -m 'completely superseding with branchB content' \
-p HEAD -p branchB branchB:
)
git reset --hard
這個使用 git 管道命令 read-tree,但縮短了整體工作流程。
git checkout <base-branch>
git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit
# Check your work!
git diff <their-branch>
我認為你真正想要的是:
git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch
這看起來很笨拙,但它應該有效。 我真正不喜歡這個解決方案的唯一想法是 git 歷史記錄會令人困惑......但至少歷史記錄將被完全保留並且您不需要為已刪除的文件做一些特殊的事情。
'git merge -s theirs branchB' 的等價物(保持父級順序)
!!! 確保您處於清潔狀態!!!
進行合並:
git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command
我們做了什么? 我們創建了一個新的提交,其中有兩個父母是我們的和他們的,並且提交的內容是 branchB - 他們的
更准確地說:
git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
這個答案是由 Paul Pladijs 給出的。 我只是接受了他的命令並為方便起見做了一個 git 別名。
編輯您的 .gitconfig 並添加以下內容:
[alias]
mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"
然后你可以通過運行“git merge -s theirs A”:
git checkout B (optional, just making sure we're on branch B)
git mergetheirs A
這會將您的 newBranch 合並到現有的 baseBranch 中
git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch
重新審視這個老問題,因為我剛剛找到了一個既簡短又易於理解的解決方案——因為它只使用瓷器命令。 需要明確的是,我想回答問題標題中所述的問題(implement git merge -s theirs
),而不是問題正文。 換句話說,我想用一棵與其第二個父樹相同的樹創建一個合並提交:
# Start from the branch that is going to receive the merge.
git switch our_branch
# Create the merge commit, albeit with the wrong tree.
git merge -s ours their_branch
# Replace our working tree and our index with their tree.
git restore --source=their_branch --worktree --staged :/
# Put their tree in the merge commit.
git commit --amend
警告: git restore
是一個相當新的命令,在 git 2.23 中引入。 git help restore
警告
此命令是實驗性的。 行為可能會改變。
我確實使用 git(2.25.1、2.30.2、2.31.1、2.34.1 和 2.35.1)的多個版本測試了此方法,並且它按預期工作。
這不一定能回答原始發帖人的問題,但我是在已經嘗試合並但最終發生沖突的情況下登陸這里的。 通常我在 IDE 中管理沖突,但是當我無法訪問它時,可以使用以下 REGEX 查找差異並將其替換為“他們的”內容:
將<<<<<<< HEAD\n[^•>]+\n=======\n([^•>]+)>>>>>>>.+\n
替換為\1
(以防萬一其他人出於與我相同的原因登陸此頁面)。
我最近才需要為共享共同歷史的兩個獨立存儲庫執行此操作。 我開始於:
Org/repository1 master
Org/repository2 master
我想一切從改變repository2 master
被應用到repository1 master
,接受所有的更改repository2將使。 在 git 的術語中,這應該是一個名為-s theirs
的策略,但它不存在。 小心,因為-X theirs
的命名就像你想要的那樣,但它不一樣(它甚至在手冊頁中這樣說)。
我解決這個問題的方法是轉到repository2
並創建一個新分支repo1-merge
。 在那個分支中,我運行了git pull git@gitlab.com:Org/repository1 -s ours
並且它合並得很好,沒有任何問題。 然后我把它推到遙控器上。
然后我回到repository1
並創建一個新分支repo2-merge
。 在那個分支中,我運行git pull git@gitlab.com:Org/repository2 repo1-merge
它將完成問題。
最后,您需要在repository1
發出合並請求以使其成為新的 master,或者只是將其保留為一個分支。
一個簡單而直觀(在我看來)的兩步方法是
git checkout branchB .
git commit -m "Picked up the content from branchB"
其次是
git merge -s ours branchB
(將兩個分支標記為合並)
唯一的缺點是它不會從當前分支中刪除在 branchB 中已刪除的文件。 之后兩個分支之間的簡單差異將顯示是否有任何此類文件。
這種方法還可以在之后的修訂日志中清楚地表明做了什么 - 以及打算做什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.