Finding a branch point with Git?

前端 未结 22 1353
小鲜肉
小鲜肉 2020-11-22 10:11

I have a repository with branches master and A and lots of merge activity between the two. How can I find the commit in my repository when branch A was created based on mast

22条回答
  •  遇见更好的自我
    2020-11-22 10:35

    Given that so many of the answers in this thread do not give the answer the question was asking for, here is a summary of the results of each solution, along with the script I used to replicate the repository given in the question.

    The log

    Creating a repository with the structure given, we get the git log of:

    $ git --no-pager log --graph --oneline --all --decorate
    * b80b645 (HEAD, branch_A) J - Work in branch_A branch
    | *   3bd4054 (master) F - Merge branch_A into branch master
    | |\  
    | |/  
    |/|   
    * |   a06711b I - Merge master into branch_A
    |\ \  
    * | | bcad6a3 H - Work in branch_A
    | | * b46632a D - Work in branch master
    | |/  
    | *   413851d C - Merge branch_A into branch master
    | |\  
    | |/  
    |/|   
    * | 6e343aa G - Work in branch_A
    | * 89655bb B - Work in branch master
    |/  
    * 74c6405 (tag: branch_A_tag) A - Work in branch master
    * 7a1c939 X - Work in branch master
    

    My only addition, is the tag which makes it explicit about the point at which we created the branch and thus the commit we wish to find.

    The solution which works

    The only solution which works is the one provided by lindes correctly returns A:

    $ diff -u <(git rev-list --first-parent branch_A) \
              <(git rev-list --first-parent master) | \
          sed -ne 's/^ //p' | head -1
    74c6405d17e319bd0c07c690ed876d65d89618d5
    

    As Charles Bailey points out though, this solution is very brittle.

    If you branch_A into master and then merge master into branch_A without intervening commits then lindes' solution only gives you the most recent first divergance.

    That means that for my workflow, I think I'm going to have to stick with tagging the branch point of long running branches, since I can't guarantee that they can be reliably be found later.

    This really all boils down to gits lack of what hg calls named branches. The blogger jhw calls these lineages vs. families in his article Why I Like Mercurial More Than Git and his follow-up article More On Mercurial vs. Git (with Graphs!). I would recommend people read them to see why some mercurial converts miss not having named branches in git.

    The solutions which don't work

    The solution provided by mipadi returns two answers, I and C:

    $ git rev-list --boundary branch_A...master | grep ^- | cut -c2-
    a06711b55cf7275e8c3c843748daaa0aa75aef54
    413851dfecab2718a3692a4bba13b50b81e36afc
    

    The solution provided by Greg Hewgill return I

    $ git merge-base master branch_A
    a06711b55cf7275e8c3c843748daaa0aa75aef54
    $ git merge-base --all master branch_A
    a06711b55cf7275e8c3c843748daaa0aa75aef54
    

    The solution provided by Karl returns X:

    $ diff -u <(git log --pretty=oneline branch_A) \
              <(git log --pretty=oneline master) | \
           tail -1 | cut -c 2-42
    7a1c939ec325515acfccb79040b2e4e1c3e7bbe5
    

    The script

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

    I doubt the git version makes much difference to this, but:

    $ git --version
    git version 1.7.1
    

    Thanks to Charles Bailey for showing me a more compact way to script the example repository.

提交回复
热议问题