Git log只能获取特定分支的提交


Git log to get commits only for a specific branch

我想列出仅属于特定分支的所有提交。

通过以下内容,它列出了分支中的所有提交,但也列出了父(主)的提交

1
git log mybranch

我找到的另一个选项是排除master可以访问的提交并给我我想要的东西,但我想避免需要知道其他分支名称。

1
git log mybranch --not master

我试图使用git for-each-ref,但它也列出mybranch所以实际上它排除了所有:

1
git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

更新:

我正在测试我刚才发现的一个新选项,直到现在看来这可能是我想要的:

1
git log --walk-reflogs mybranch

更新(2013-02-13T15:08):

--walk-reflogs选项很好,但我检查了reflogs的到期时间(默认为90天,gc.reflogExpire)。

我想我找到了我想要的答案:

1
git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v"refs/heads/mybranch")

我只是从可用分支列表中删除当前分支,并使用该列表从日志中排除。这样我只能获得mybranch才能达到的提交。


听起来你应该使用cherry

1
git cherry -v develop mybranch

这将显示mybranch中包含的所有提交,但不会显示。如果你不使用最后一个选项(mybranch),它将比较当前分支。

正如VonC指出的那样,您总是将您的分支与另一个分支进行比较,因此请了解您的分支,然后选择要与哪个分支进行比较。


BUT I would like to avoid the need of knowing the other branches names.

我不认为这是可能的:Git中的分支总是基于另一个或至少在另一个提交上,如"git diff中显示的不够":

enter image description here

您需要一个日志参考点来显示正确的提交。

如"GIT - 我从何处分支?"中所述:

branches are simply pointers to certain commits in a DAG

因此,即使git log master..mybranch是一个答案,如果mybranch基于myotherbranch,它仍将显示太多提交,其本身基于master

为了找到该引用(分支的来源),您只能解析提交并查看它们所在的分支,如下所示:

  • "Git:找出提交来自哪个分支"。
  • "我怎样才能看到另一个分支从哪个分支分叉?"


我终于找到了做OP想要的方法。它很简单:

1
git log --graph [branchname]

该命令将以图形格式显示可从提供的分支访问的所有提交。但是,您可以通过查看提交图表轻松过滤该分支上的所有提交,其中*是提交行中的第一个字符。

例如,让我们看看下面的cakephp GitHub repo上的git log --graph master的摘录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | 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 <[email protected]>
| | 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 <[email protected]>
| | 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 <[email protected]>
|/|   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 <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

如您所见,只有提交8314c2ff833280bbc7102cb6d4fcf62240cd3ac4c3f45e811e4b49fe27624b57c3eb8f4721a4323b*是提交行中的第一个字符。这些提交来自主分支,而其他四个来自其他一些分支。


以下shell命令应该执行您想要的操作:

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

注意事项

如果mybranch已签出,则上述命令将不起作用。这是因为mybranch上的提交也可以通过HEAD到达,因此Git不认为提交对于mybranch是唯一的。要在mybranch签出时使其工作,您还必须为HEAD添加排除:

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

但是,除非mybranch已签出,否则不应排除HEAD,否则可能会显示不属于mybranch的提交。

同样,如果您有一个名为origin/mybranch的远程分支对应于本地mybranch分支,则必须将其排除:

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

如果远程分支是远程存储库的默认分支(通常仅对origin/master为true),则还必须排除origin/HEAD

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

如果您已检出分支,并且有远程分支,并且远程分支是远程存储库的默认分支,那么您最终排除了很多:

1
2
3
4
5
6
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)

说明

git rev-list命令是一个低级(管道)命令,它处理给定的修订并转储遇到的SHA1标识符。可以认为它等同于git log,除了它只显示SHA1-no日志消息,没有作者姓名,没有时间戳,没有任何"花哨"的东西。

顾名思义,--no-walk选项可防止git rev-list走向祖先链。因此,如果键入git rev-list --no-walk mybranch,它将只打印一个SHA1标识符:mybranch分支的提示提交的标识符。

--exclude=refs/heads/mybranch --all参数告诉git rev-listrefs/heads/mybranch以外的每个引用开始。

因此,当您运行git rev-list --no-walk --exclude=refs/heads/mybranch --all时,Git会打印除refs/heads/mybranch之外的每个引用的提示提交的SHA1标识符。这些提交及其祖先是您不感兴趣的提交 - 这些是您不希望看到的提交。

其他提交是你想要看到的,所以我们收集git rev-list --no-walk --exclude=refs/heads/mybranch --all的输出并告诉Git显示除了那些提交和他们的祖先之外的所有内容。

--no-walk参数对于大型存储库是必需的(并且是对小型存储库的优化):如果没有它,Git将不得不打印,并且shell必须收集(并存储在内存中)多于必要的提交标识符。对于大型存储库,收集的提交数量很容易超过shell的命令行参数限制。

Git bug?

我希望以下工作:

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

但事实并非如此。我猜这是Git中的一个错误,但也许是故意的。


快速回答:

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

让我们说:

  • 你有一个主分支

  • 做一些提交

  • 您创建了一个名为b2的分支

  • git log -n1; commit id是b2和master之间的合并基础

  • 在b2做一些提交

  • git log将显示b2和master的日志历史记录

  • 使用提交范围,如果您不熟悉这个概念,我邀请您谷歌或堆栈溢出 - 它,

    对于您的实际情况,您可以这样做

    1
    git log commitID_FOO..comitID_BAR

    ".."是log命令的范围运算符。

    这意味着,以简单的形式,给我所有日志比commitID_FOO更新...

  • 看看第4点,合并基础

    所以:git log COMMITID_mergeBASE..HEAD会告诉你差异

  • Git可以为你检索合并基础

    1
    git merge-base b2 master
  • 最后你可以这样做:

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

  • 这将输出当前分支上的提交。如果传递任何参数,它只输出哈希值。

    git_show_all_commits_only_on_this_branch

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #!/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


    你可以尝试这样的事情:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/bin/bash

    all_but()
    {
        target="$(git rev-parse $1)"
        echo"$target --not"
        git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
        while read entry
        do
            eval"$entry"

            test"$ref" !="$target" && echo"$ref"
        done
    }

    git log $(all_but $1)

    或者,借用Git用户手册中的配方:

    1
    2
    #!/bin/bash
    git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v"^$1" )


    1
    git rev-list --exclude=master --branches --no-walk

    将列出每个不是master的分支的提示。

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

    将列出master历史记录中不在任何其他分支历史记录中的每个提交。

    排序对于为提交选择设置过滤器管道的选项很重要,因此--branches必须遵循它应该应用的任何排除模式,并且--no-walk必须遵循过滤器提供提交rev-list不应该 步行。


    在我的情况下,我们正在使用Git Flow和GitHub。您需要做的就是:将您的功能分支与GitHub上的开发分支进行比较。

    它将显示仅对您的功能分支进行的提交。

    例如:

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


    我发现这种方法相对容易。

    结账到分行而不是

  • 1
    git rev-list --simplify-by-decoration -2 HEAD
  • 这将只提供两个SHA:

    1)分支的最后提交[C1]

    2)并将父级提交给分支的第一次提交[C2]

  • 现在跑

    1
    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
  • 这里C1和C2是你运行第一个命令时会得到的两个字符串。在第二个命令中不使用<>放置这些值。

    这将给出分支内文件更改历史列表。