How to find the nearest parent of a Git branch?

后端 未结 21 1650
野性不改
野性不改 2020-11-22 00:54

Let\'s say I have the following local repository with a commit tree like this:

master --> a
            \\
             \\
      develop c --> d
               


        
相关标签:
21条回答
  • 2020-11-22 01:11

    If you use Source Tree look at your commit details > Parents > then you'll see commit numbers underlined (links)

    0 讨论(0)
  • 2020-11-22 01:12

    git parent

    You can just run the command

    git parent

    to find the parent of the branch, if you add the @Joe Chrysler's answer as a git alias. It will simplify the usage.

    Open gitconfig file located at "~/.gitconfig" by using any text editor. ( For linux). And for Windows the ".gitconfig" path is generally located at c:\users\your-user\.gitconfig

    vim  ~/.gitconfig
    

    Add the following alias command in the file:

    [alias]
                parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"
    

    Save and exit the editor.

    Run the command git parent

    That's it!

    0 讨论(0)
  • 2020-11-22 01:14

    Since none of the answers above worked on our repository, I want to share my own way, using latest merges in git log:

    #!/bin/bash
    git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10
    

    Put it in a script named git-last-merges, which also accepts a branch name as argument (instead of current branch) as well as other git log arguments

    From the output, we can manually detect the parent branch(es) based on own branching conventions and number of merges from each branch.

    EDIT: If you use git rebase on child branches often (and merges are fast-forwarded often so there aren't too many merge commits), this answer won't work well, so I wrote a script to count ahead commits (normal and merge), and behind commits (there shouldn't be any behind merge in parent branch) on all branches comparing to the current branch. Just run this script and let me know if works for you or not

    #!/bin/bash
    HEAD="`git rev-parse --abbrev-ref HEAD`"
    echo "Comparing to $HEAD"
    printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
    git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
        ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
        if [[ $ahead_merge_count != 0 ]] ; then
            continue
        fi
        ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
        behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
        behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
        behind="-$behind_count"
        behind_merge="-M$behind_merge_count"
        ahead="+$ahead_count"
        printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
    done | sort -n
    
    0 讨论(0)
  • 2020-11-22 01:15

    JoeChrysler's command-line magic can be simplified. Here's Joe's logic - for brevity I've introduced a parameter named cur_branch in place of the command substitution `git rev-parse --abbrev-ref HEAD` into both versions; that can be initialized like so:

    cur_branch=$(git rev-parse --abbrev-ref HEAD)
    

    Then, here's Joe's pipeline:

    git show-branch -a           |
      grep '\*'                  | # we want only lines that contain an asterisk
      grep -v "$cur_branch"      | # but also don't contain the current branch
      head -n1                   | # and only the first such line
      sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
      sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed
    

    We can accomplish the same thing as all five of those individual command filters in a relatively simple awk command:

    git show-branch -a |
      awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  
    

    That breaks down like this:

    -F'[]^~[]' 
    

    split the line into fields at ], ^, ~, and [ characters.

    /\*/                      
    

    Find lines that contain an asterisk

    && !/'"$cur_branch"'/
    

    ...but not the current branch name

    { print $2;               
    

    When you find such a line, print its second field (that is, the part between the first and second occurrences of our field separator characters). For simple branch names, that will be just what's between the brackets; for refs with relative jumps, it will be just the name without the modifier. So our set of field separators handles the intent of both sed commands.

      exit }
    

    Then exit immediately. This means it only ever processes the first matching line, so we don't need to pipe the output through head -n 1.

    0 讨论(0)
  • 2020-11-22 01:15
    vbc=$(git rev-parse --abbrev-ref HEAD)
    vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
    swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
    git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
    

    Achieves the same ends as Mark Reed's answer, but uses a much safer approach that doesn't misbehave in a number of scenarios:

    1. Parent branch's last commit is a merge, making the column show - not *
    2. Commit message contains branch name
    3. Commit message contains *
    0 讨论(0)
  • 2020-11-22 01:17

    Anyone wanting to do this these days - Atlassian's SourceTree application shows you a great visual representation of how your branches relate to one another, i.e. Where they began and where they currently sit in the commit order (e.g. HEAD or 4 commits behind, etc.).

    0 讨论(0)
提交回复
热议问题