# git-merge-base
> 原文: [https://git-scm.com/docs/git-merge-base](https://git-scm.com/docs/git-merge-base)
## 名稱
git-merge-base - 為合并找到盡可能好的共同祖先
## 概要
```
git merge-base [-a|--all] <commit> <commit>…?
git merge-base [-a|--all] --octopus <commit>…?
git merge-base --is-ancestor <commit> <commit>
git merge-base --independent <commit>…?
git merge-base --fork-point <ref> [<commit>]
```
## 描述
_git merge-base_ 找到兩個提交之間最好的共同祖先,用于三向合并。如果后者是前者的祖先,一個共同的祖先_比另一個共同的祖先更好_。沒有任何更好的共同祖先的共同祖先是_最佳共同祖先_,即_合并基_。請注意,一對提交可以有多個合并基礎。
## 操作模式
作為最常見的特殊情況,在命令行上僅指定兩個提交意味著計算給定兩個提交之間的合并基礎。
更一般地,在計算合并基數的兩個提交中,一個由命令行上的第一個提交參數指定;另一個提交是(可能是假設的)提交,它是命令行上所有剩余提交的合并。
因此,如果指定了兩個以上的提交,則_合并庫_不一定包含在每個提交參數中。當與`--merge-base`選項一起使用時,這與 [git-show-branch [1]](https://git-scm.com/docs/git-show-branch) 不同。
```
--octopus
```
計算所有提供的提交的最佳共同祖先,為n路合并做準備。這模仿了 _git show-branch --merge-base_ 的行為。
```
--independent
```
不是打印合并庫,而是使用相同的祖先打印提供的提交的最小子集。換句話說,在給出的提交中,列出那些不能從任何其他提交的提交。這模仿了 _git show-branch --independent_ 的行為。
```
--is-ancestor
```
檢查第一個< commit>是第二個< commit>的祖先,如果為true則退出,狀態為0,否則退出狀態為1。錯誤由非零狀態發出信號,該狀態不為1。
```
--fork-point
```
找到分支(或任何導致< commit>的歷史記錄)從另一個分支(或任何引用)< ref>分叉的點。這不只是尋找兩個提交的共同祖先,而且還考慮了< ref>的reflog。查看導致< commit>的歷史記錄分支早期的分支< ref>分叉(見下面關于這種模式的討論)。
## OPTIONS
```
-a
```
```
--all
```
輸出提交的所有合并基礎,而不是僅輸出一個。
## 討論
給定兩個提交 _A_ 和 _B_ ,`git merge-base A B`將通過父關系輸出可從 _A_ 和 _B_ 到達的提交。
例如,使用此拓撲:
```
o---o---o---B
/
---o---1---o---o---o---A
```
_A_ 和 _B_ 之間的合并堿基是 _1_ 。
給定三次提交 _A_ , _B_ 和 _C_ ,`git merge-base A B C`將計算 _A_ 和假設提交_之間的合并基數M_ ,是 _B_ 和 _C_ 之間的合并。例如,使用此拓撲:
```
o---o---o---o---C
/
/ o---o---o---B
/ /
---2---1---o---o---o---A
```
`git merge-base A B C`的結果是 _1_ 。這是因為 _B_ 和 _C_ 之間具有合并提交 _M_ 的等效拓撲是:
```
o---o---o---o---o
/ \
/ o---o---o---o---M
/ /
---2---1---o---o---o---A
```
`git merge-base A M`的結果是 _1_ 。提交 _2_ 也是 _A_ 和 _M_ 之間的共同祖先,但 _1_ 是更好的共同祖先,因為 _2_ 是 _1_ 的祖先。因此, _2_ 不是合并基礎。
`git merge-base --octopus A B C`的結果是 _2_ ,因為 _2_ 是所有提交的最佳共同祖先。
當歷史涉及縱橫交錯時,兩個提交可以有不止一個_最佳_共同祖先。例如,使用此拓撲:
```
---1---o---A
\ /
X
/ \
---2---o---o---B
```
_1_ 和 _2_ 都是A和B的合并堿基。兩者都不比另一個好(兩者都是_最佳_合并堿基)。如果未給出`--all`選項,則未指定輸出哪一個最佳選項。
在兩個提交A和B之間檢查“快進”的常用習慣用法是(或者至少用于)計算A和B之間的合并基礎,并檢查它是否與A相同,在這種情況下,A是B的祖先。你會看到這個習慣用法經常用在較舊的腳本中。
```
A=$(git rev-parse --verify A)
if test "$A" = "$(git merge-base A B)"
then
... A is an ancestor of B ...
fi
```
在現代git中,您可以更直接地說出這一點:
```
if git merge-base --is-ancestor A B
then
... A is an ancestor of B ...
fi
```
代替。
## 關于叉點模式的討論
處理使用`git checkout -b topic origin/master`創建的`topic`分支后,遠程跟蹤分支`origin/master`的歷史記錄可能已經倒回并重建,從而導致此形狀的歷史記錄:
```
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\
B0
\
D0---D1---D (topic)
```
其中`origin/master`用于指向提交B0,B1,B2,現在它指向B,當`origin/master`位于B0時,您的`topic`分支在它上面啟動,并且您構建了三個提交,D0, D1和D,在它上面。想象一下,您現在想要在更新的origin / master之上重新設置您在該主題上所做的工作。
在這種情況下,`git merge-base origin/master topic`將在上圖中返回B0的父節點,但是B0 ^ .. D是**而不是**你想要在B之上重放的提交范圍(它包括B0) ,這不是你寫的;它是一個提交,當它從B0移動到B1時,另一方丟棄了)。
`git merge-base --fork-point origin/master topic`旨在幫助解決此類問題。它不僅需要B,還需要B0,B1和B2(即存儲庫的reflog知道的遠程跟蹤分支的舊技巧),以查看構建主題分支的提交并找到B0,允許您僅重放對你主題的提交,不包括后來丟棄的提交。
于是
```
$ fork_point=$(git merge-base --fork-point origin/master topic)
```
會找到B0,和
```
$ git rebase --onto origin/master $fork_point topic
```
將重放B頂部的D0,D1和D以創建此形狀的新歷史記錄:
```
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\ \
B0 D0'--D1'--D' (topic - updated)
\
D0---D1---D (topic - old)
```
需要注意的是,您的存儲庫中較舊的reflog條目可能會被`git gc`過期。如果遠程跟蹤分支`origin/master`的reflog中不再出現B0,則`--fork-point`模式顯然無法找到并失敗,從而避免給出隨機且無用的結果(例如B0的父級,就像同一命令一樣沒有`--fork-point`選項給出)。
此外,您使用`--fork-point`模式的遠程跟蹤分支必須是您的主題從其提示分叉的主題。如果你從一個比提示更早的提交分叉,這個模式將找不到叉點(想象在上面的示例歷史B0不存在,origin / master從B1開始,移到B2然后B,你分叉你的主題at origin / master ^當origin / master為B1時;歷史的形狀與上面相同,沒有B0,B1的父級是`git merge-base origin/master topic`正確找到的,但`--fork-point`模式不會,因為它不是曾經位于origin / master的提交之一。
## 也可以看看
[git-rev-list [1]](https://git-scm.com/docs/git-rev-list) , [git-show-branch [1]](https://git-scm.com/docs/git-show-branch) , [git-merge [1]](https://git-scm.com/docs/git-merge)
## GIT
部分 [git [1]](https://git-scm.com/docs/git) 套件
- git
- git-config
- git-help
- git-init
- git-clone
- git-add
- git-status
- git-diff
- git-commit
- git-reset
- git-rm
- git-mv
- git-branch
- git-checkout
- git-merge
- git-mergetool
- git-log
- git-stash
- git-tag
- git-worktree
- git-fetch
- git-pull
- git-push
- git-remote
- git-submodule
- git-show
- git-log
- git-shortlog
- git-describe
- git-apply
- git-cherry-pick
- git-rebase
- git-revert
- git-bisect
- git-blame
- git-grep
- gitattributes
- giteveryday
- gitglossary
- githooks
- gitignore
- gitmodules
- gitrevisions
- gittutorial
- gitworkflows
- git-am
- git-format-patch
- git-send-email
- git-request-pull
- git-svn
- git-fast-import
- git-clean
- git-gc
- git-fsck
- git-reflog
- git-filter-branch
- git-instaweb
- git-archive
- git-bundle
- git-daemon
- git-update-server-info
- git-cat-file
- git-check-ignore
- git-checkout-index
- git-commit-tree
- git-count-objects
- git-diff-index
- git-for-each-ref
- git-hash-object
- git-ls-files
- git-merge-base
- git-read-tree
- git-rev-list
- git-rev-parse
- git-show-ref
- git-symbolic-ref
- git-update-index
- git-update-ref
- git-verify-pack
- git-write-tree