我有一个带有master和a分支的存储库,在这两个分支之间有很多合并活动。当分支A基于master创建时,我如何在我的存储库中找到提交?

我的存储库基本上是这样的:

-- X -- A -- B -- C -- D -- F  (master) 
          \     /   \     /
           \   /     \   /
             G -- H -- I -- J  (branch A)

我正在寻找修订A,这不是git merge-base(——all)找到的。


当前回答

我最近也需要解决这个问题,最后写了一个Ruby脚本:https://github.com/vaneyckt/git-find-branching-point

其他回答

使用reflog似乎解决了这个问题git reflog <branchname>显示了所有的分支提交,包括创建分支。

这是来自一个分支,该分支在合并回主节点之前有2次提交。

git reflog june-browser-updates
b898b15 (origin/june-browser-updates, june-browser-updates) june-browser-updates@{0}: commit: sorted cve.csv
467ae0e june-browser-updates@{1}: commit: browser updates and cve additions
d6a37fb june-browser-updates@{2}: branch: Created from HEAD

要从分支点查找提交,可以使用这个。

git log --ancestry-path master..topicbranch

Git 2.36提出了一个更简单的命令:

(branch_A_tag)
     |
--X--A--B--C--D--F  (master) 
      \   / \   /
       \ /   \ /
        G--H--I--J  (branch A)
vonc@vclp MINGW64 ~/git/tests/branchOrigin (branch_A)
git log -1 --decorate --oneline \
  $(git rev-parse \
     $(git rev-list --exclude-first-parent-only ^main branch_A| tail -1)^ \
   )
 80e8436 (tag: branch_A_tag) A - Work in branch main

^main branch_A给出的是J—I—H—G -1得到G git rev-parse G^给你它的第一个父:A或branch_A_tag

使用测试脚本:

mkdir branchOrigin
cd branchOrigin
git init
git commit --allow-empty -m "X - Work in branch main"
git commit --allow-empty -m "A - Work in branch main"
git tag branch_A_tag     -m "Tag branch point of branch_A"
git commit --allow-empty -m "B - Work in branch main"
git switch -c branch_A branch_A_tag
git commit --allow-empty -m "G - Work in branch_A"
git switch main
git merge branch_A       -m "C - Merge branch_A into branch main"
git switch branch_A
git commit --allow-empty -m "H - Work in branch_A"
git merge main         -m "I - Merge main into branch_A"
git switch main
git commit --allow-empty -m "D - Work in branch main"
git merge branch_A       -m "F - Merge branch_A into branch main"
git switch branch_A
git commit --allow-empty -m "J - Work in branch_A branch"

这就给了你:

vonc@vclp MINGW64 ~/git/tests/branchOrigin (branch_A)
$ git log --oneline --decorate --graph --branches --all
* a55a87e (HEAD -> branch_A) J - Work in branch_A branch
| *   3769cc8 (main) F - Merge branch_A into branch main
| |\
| |/
|/|
* |   1b29fa5 I - Merge main into branch_A
|\ \
* | | e7accbd H - Work in branch_A
| | * 87a62f4 D - Work in branch main
| |/
| *   7bc79c5 C - Merge branch_A into branch main
| |\
| |/
|/|
* | 0f28c9f G - Work in branch_A
| * e897627 B - Work in branch main
|/
* 80e8436 (tag: branch_A_tag) A - Work in branch main
* 5cad19b X - Work in branch main

这是:

(branch_A_tag)
     |
--X--A--B--C--D--F  (master) 
      \   / \   /
       \ /   \ /
        G--H--I--J  (branch A)

在Git 2.36 (Q2 2022)中,“Git log”(man)和朋友们学习了一个选项——exclude-first-parent-only只沿着第一个父链向下传播UNINTERESTING位,就像——first-parent选项只显示在第一个父链上缺乏UNINTERESTING位的提交一样。

参见Jerry Zhang (Jerry -skydio)提交的9d505b7 (11 Jan 2022)。 (由Junio C Hamano—gitster—在commit 708cbef中合并,2022年2月17日)

Git-rev-list: add——exclude-first-parent-only标志 署名:Jerry Zhang

It is useful to know when a branch first diverged in history from some integration branch in order to be able to enumerate the user's local changes. However, these local changes can include arbitrary merges, so it is necessary to ignore this merge structure when finding the divergence point. In order to do this, teach the "rev-list" family to accept "--exclude-first-parent-only", which restricts the traversal of excluded commits to only follow first parent links. -A-----E-F-G--main \ / / B-C-D--topic In this example, the goal is to return the set {B, C, D} which represents a topic branch that has been merged into main branch. git rev-list topic ^main(man) will end up returning no commits since excluding main will end up traversing the commits on topic as well. git rev-list --exclude-first-parent-only topic ^main(man) however will return {B, C, D} as desired. Add docs for the new flag, and clarify the doc for --first-parent to indicate that it applies to traversing the set of included commits only.

Rev-list-options现在包括在它的手册页:

——“首席家长 当找到要包含的提交时,只遵循第一个 父节点在看到合并提交时提交。 这个选项 能给一个更好的概述时,查看的演变 一个特定的主题分支,因为合并到一个主题中 分支倾向于只调整到更新的上游 时不时地,这个选项可以让你忽略 个人的承诺被带入你的历史 一个合并。

Rev-list-options现在包括在它的手册页:

——exclude-first-parent-only 当发现提交排除(使用'{插入符号}')时,只跟随 第一个父节点在看到合并提交时提交。 这可用于查找主题分支中的更改集 从它与远分支的分歧点开始 任意的合并可以是有效的主题分支更改。

您可以检查分支A的reflog,以找到它是从哪个提交创建的,以及该分支所指向的提交的完整历史。Reflogs在.git/logs中。

这是我之前的答案的改进版本。它依赖于来自合并的提交消息来查找分支第一次创建的位置。

它适用于这里提到的所有存储库,我甚至还处理了邮件列表中产生的一些棘手的存储库。我还为此写了测试。

find_merge ()
{
    local selection extra
    test "$2" && extra=" into $2"
    git rev-list --min-parents=2 --grep="Merge branch '$1'$extra" --topo-order ${3:---all} | tail -1
}

branch_point ()
{
    local first_merge second_merge merge
    first_merge=$(find_merge $1 "" "$1 $2")
    second_merge=$(find_merge $2 $1 $first_merge)
    merge=${second_merge:-$first_merge}

    if [ "$merge" ]; then
        git merge-base $merge^1 $merge^2
    else
        git merge-base $1 $2
    fi
}