Git log to get commits only for a specific branch

后端 未结 12 1634
挽巷
挽巷 2020-11-29 15:13

I want to list all commits that are only part of a specific branch.

With the following, it lists all the commits from the branch, but also from the parent (master)

相关标签:
12条回答
  • 2020-11-29 15:21

    The following shell command should do what you want:

    git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)
    

    Caveats

    If you have mybranch checked out, the above command won't work. That's because the commits on mybranch are also reachable by HEAD, so Git doesn't consider the commits to be unique to mybranch. To get it to work when mybranch is checked out, you must also add an exclude for HEAD:

    git log --all --not $(git rev-list --no-walk \
        --exclude=refs/heads/mybranch \
        --exclude=HEAD \
        --all)
    

    However, you should not exclude HEAD unless the mybranch is checked out, otherwise you risk showing commits that are not exclusive to mybranch.

    Similarly, if you have a remote branch named origin/mybranch that corresponds to the local mybranch branch, you'll have to exclude it:

    git log --all --not $(git rev-list --no-walk \
        --exclude=refs/heads/mybranch \
        --exclude=refs/remotes/origin/mybranch \
        --all)
    

    And if the remote branch is the default branch for the remote repository (usually only true for origin/master), you'll have to exclude origin/HEAD as well:

    git log --all --not $(git rev-list --no-walk \
        --exclude=refs/heads/mybranch \
        --exclude=refs/remotes/origin/mybranch \
        --exclude=refs/remotes/origin/HEAD \
        --all)
    

    If you have the branch checked out, and there's a remote branch, and the remote branch is the default for the remote repository, then you end up excluding a lot:

    git log --all --not $(git rev-list --no-walk \
        --exclude=refs/heads/mybranch \
        --exclude=HEAD
        --exclude=refs/remotes/origin/mybranch \
        --exclude=refs/remotes/origin/HEAD \
        --all)
    

    Explanation

    The git rev-list command is a low-level (plumbing) command that walks the given revisions and dumps the SHA1 identifiers encountered. Think of it as equivalent to git log except it only shows the SHA1—no log message, no author name, no timestamp, none of that "fancy" stuff.

    The --no-walk option, as the name implies, prevents git rev-list from walking the ancestry chain. So if you type git rev-list --no-walk mybranch it will only print one SHA1 identifier: the identifier of the tip commit of the mybranch branch.

    The --exclude=refs/heads/mybranch --all arguments tell git rev-list to start from each reference except for refs/heads/mybranch.

    So, when you run git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git prints the SHA1 identifier of the tip commit of each ref except for refs/heads/mybranch. These commits and their ancestors are the commits you are not interested in—these are the commits you do not want to see.

    The other commits are the ones you want to see, so we collect the output of git rev-list --no-walk --exclude=refs/heads/mybranch --all and tell Git to show everything but those commits and their ancestors.

    The --no-walk argument is necessary for large repositories (and is an optimization for small repositories): Without it, Git would have to print, and the shell would have to collect (and store in memory) many more commit identifiers than necessary. With a large repository, the number of collected commits could easily exceed the shell's command-line argument limit.

    Git bug?

    I would have expected the following to work:

    git log --all --not --exclude=refs/heads/mybranch --all
    

    but it does not. I'm guessing this is a bug in Git, but maybe it's intentional.

    0 讨论(0)
  • 2020-11-29 15:21

    Fast answer:

    git log $(git merge-base master b2)..HEAD
    

    Let's say:

    1. That you have a master branch

    2. Do a few commits

    3. You created a branch named b2

    4. Do git log -n1; the commit Id is the merge base between b2 and master

    5. Do a few commits in b2

    6. git log will show your log history of b2 and master

    7. Use commit range, if you aren't familiar with the concept, I invite you to google it or stack overflow-it,

      For your actual context, you can do for example

      git log commitID_FOO..comitID_BAR
      

      The ".." is the range operator for the log command.

      That mean, in a simple form, give me all logs more recent than commitID_FOO...

    8. Look at point #4, the merge base

      So: git log COMMITID_mergeBASE..HEAD will show you the difference

    9. Git can retrieve the merge base for you like this

      git merge-base b2 master
      
    10. Finally you can do:

      git log $(git merge-base master b2)..HEAD
      
    0 讨论(0)
  • 2020-11-29 15:31
    git rev-list --exclude=master --branches --no-walk
    

    will list the tips of every branch that isn't master.

    git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)
    

    will list every commit in master's history that's not in any other branch's history.

    Sequencing is important for the options that set up the filter pipeline for commit selection, so --branches has to follow any exclusion patterns it's supposed to apply, and --no-walk has to follow the filters supplying commits rev-list isn't supposed to walk.

    0 讨论(0)
  • 2020-11-29 15:35

    I finally found the way to do what the OP wanted. It's as simple as:

    git log --graph [branchname]
    

    The command will display all commits that are reachable from the provided branch in the format of graph. But, you can easily filter all commits on that branch by looking at the commits graph whose * is the first character in the commit line.

    For example, let's look at the excerpt of git log --graph master on cakephp GitHub repo below:

    D:\Web Folder\cakephp>git log --graph master
    *   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
    |\  Merge: c3f45e8 0459a35
    | | Author: José Lorenzo Rodríguez <lorenzo@users.noreply.github.com>
    | | Date:   Tue Aug 30 08:01:59 2016 +0200
    | |
    | |     Merge pull request #9367 from cakephp/fewer-allocations
    | |
    | |     Do fewer allocations for simple default values.
    | |
    | * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
    | | Author: Mark Story <mark@mark-story.com>
    | | Date:   Mon Aug 29 22:21:16 2016 -0400
    | |
    | |     The action should only be defaulted when there are no patterns
    | |
    | |     Only default the action name when there is no default & no pattern
    | |     defined.
    | |
    | * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
    | | Author: Mark Story <mark@mark-story.com>
    | | Date:   Sun Aug 28 22:35:20 2016 -0400
    | |
    | |     Do fewer allocations for simple default values.
    | |
    | |     Don't allocate arrays when we are only assigning a single array key
    | |     value.
    | |
    * |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
    |\ \  Merge: 10e5734 43178fd
    | |/  Author: Mark Story <mark@mark-story.com>
    |/|   Date:   Mon Aug 29 22:15:30 2016 -0400
    | |
    | |       Merge pull request #9322 from cakephp/add-email-assertions
    | |
    | |       Add email assertions trait
    | |
    | * commit 43178fd55d7ef9a42706279fa275bb783063cf34
    | | Author: Jad Bitar <jadbitar@mac.com>
    | | Date:   Mon Aug 29 17:43:29 2016 -0400
    | |
    | |     Fix `@since` in new files docblocks
    | |
    

    As you can see, only commits 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4 and c3f45e811e4b49fe27624b57c3eb8f4721a4323b have the * being the first character in the commit lines. Those commits are from the master branch while the other four are from some other branches.

    0 讨论(0)
  • 2020-11-29 15:37

    In my situation, we are using Git Flow and GitHub. All you need to do this is: Compare your feature branch with your develop branch on GitHub.

    It will show the commits only made to your feature branch.

    For example:

    https://github.com/your_repo/compare/develop...feature_branch_name

    0 讨论(0)
  • 2020-11-29 15:38

    This will output the commits on the current branch. If any argument is passed, it just outputs the hashes.

    git_show_all_commits_only_on_this_branch

    #!/bin/bash
    function show_help()
    {
      ME=$(basename $0)
      IT=$(cat <<EOF
      
      usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
      
      Compares 2 different branches, and lists the commits found only 
      in the first branch (newest branch). 
    
      e.g. 
      
      $ME         -> default. compares current branch to master
      $ME B1      -> compares branch B1 to master
      $ME B1 B2   -> compares branch B1 to B2
      $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
      
      )
      echo "$IT"
      exit
    }
    
    if [ "$1" == "help" ]
    then
      show_help
    fi
    
    # Show commit msgs if any arg passed for arg 3
    if [ "$3" ]
    then
      OPT="-v"
    fi
    
    # get branch names
    OLDER_BRANCH=${2:-"master"}
    if [ -z "$1" ]
    then
      NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
    else
      NEWER_BRANCH=$1
    fi
    
    if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
    then
      echo "  Please supply 2 different branches to compare!"
      show_help
    fi
    
    OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)
    
    if [ -z "$OUT" ]
    then
      echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
      exit;
    fi
    
    if [ "$OPT" == "-v" ]
    then
      echo "$OUT"
    else
      echo "$OUT" | awk '{print $2}'
    fi
    
    0 讨论(0)
提交回复
热议问题