Git日志仅获取特定分支的提交


214

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

通过以下代码,它列出了分支中的所有提交,还列出了父级(主)的所有提交

git log mybranch

我发现的另一个选择是排除master可以到达的提交,并提供我想要的内容,但是我想避免需要知道其他分支名称的需要。

git log mybranch --not master

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

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

更新:

我正在测试前一段时间找到的新选项,直到现在看来这可能正是我想要的:

git log --walk-reflogs mybranch

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

--walk-reflogs选项很好,但是我检查了reflog的有效期(默认为90天,gc.reflogExpire)。

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

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

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



也已经看到了这个问题,但不完全相同
dimirc

2
您确定那是您想要的吗?我发现最好有一个目标:“分支中的哪些不在上游”,或者“分支中的哪些不在主服务器中”。另外,尽管git的修剪速度很快,但是随着分支的增加,这将变得更加昂贵。我有一个脚本,在bzr的“ missing”命令之后,我将其称为“ git missing”。您可以在这里找到它:github.com/jszakmeister/etc/blob/master/git-addons/git-missing
John Szakmeister

1
我实际上需要一个用于接收后的钩子,因此“ master”将永远不是要排除的分支
dimirc

是的,StarPinkER提到的副本对我来说效果很好:git log $(git merge-base HEAD branch).. branch
charo 2014年

Answers:


165

从听起来应该使用cherry

git cherry -v develop mybranch

这将显示所有这些都包含在该提交的mybranch,而不是在发展。如果取消最后一个选项(mybranch),它将比较当前分支。

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


4
这正是我所需要的,但是似乎应该对此有一个更直观的命令(即使在Git的世界中也是如此)。
塞斯(Seth)2015年

12
您还git cherry -v master可以将当前分支与master分支进行比较。
Pithikos

2
使用git cherry的危险在于,只有在分支之间它们的文件差异相同时,才匹配提交。如果进行了某种合并,这会使一个分支与另一个分支之间的差异有所不同,则git cherry会将它们视为不同的提交。
2016年

这给了我fatal: Unknown commit mybranch
马特·阿诺德

1
@MattArnold,您必须将文本“ develop”和“ mybranch”更改为您的存储库中存在的分支
Smilie

40

但是我想避免知道其他分支名称的需要。

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

在此处输入图片说明

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

如“ GIT-我从哪里分支? ”中所述:

分支只是DAG中某些提交的指针

因此,即使git log master..mybranch是一个答案,它仍然会显示过多的提交(如果mybranch基于myotherbranch,其本身基于)master

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


26

我终于找到了执行OP想要的方法。就像这样简单:

git log --graph [branchname]

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

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

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
| |

正如你所看到的,只有提交8314c2ff833280bbc7102cb6d4fcf62240cd3ac4c3f45e811e4b49fe27624b57c3eb8f4721a4323b具备*作为第一个字符在提交线。这些提交来自master分支,其他四个来自其他分支。


11

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

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

注意事项

如果您已mybranch签出,则上述命令将不起作用。那是因为提交的提交mybranch也可以通过进行访问HEAD,因此Git认为提交不是唯一的mybranch。为了使它在mybranch检出时正常工作,还必须为添加一个排除项HEAD

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

但是,除非已将检出,否则您应该排除它,否则,您可能会冒出不是专有的提交的风险。HEADmybranchmybranch

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

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

而且,如果remote分支是远程存储库的默认分支(通常仅适用于origin/master),则还必须排除origin/HEAD

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

如果您已将分支签出,并且有一个远程分支,并且该远程分支是远程存储库的默认分支,那么您最终会排除很多:

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-walk顾名思义,该选项可防止git rev-list沿袭祖先链。因此,如果键入git rev-list --no-walk mybranch,它将仅打印一个SHA1标识符:mybranch分支的尖端提交的标识符。

--exclude=refs/heads/mybranch --all参数告诉git rev-list从除了每个参考启动refs/heads/mybranch

因此,当您运行时git rev-list --no-walk --exclude=refs/heads/mybranch --all,Git将打印每个引用的尖端提交的SHA1标识符(除外)refs/heads/mybranch。这些提交和他们的祖先是您在提交中,这些兴趣是你做的提交希望看到的。

其他的提交是你想看到的,所以我们收集的输出的东西git rev-list --no-walk --exclude=refs/heads/mybranch --all,并让Git显示一切,但这些提交和他们的祖先。

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

git bug?

我本来期望以下工作:

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

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


很好的解释。+1
VonC 2014年

5
我来到这里想知道如何做水星的hg log -b <branch>。我不明白为什么人们说git不友好。/ s
weberc2

我不知道为什么git log --all --not --exclude=refs/heads/mybranch --all不行,但行得通git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --all,关于排除HEAD和原点也有相同的警告。
本C

8

快速回答:

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

比方说:

  1. 你有一个分支

  2. 做几次提交

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

  4. git log -n1; 提交ID是b2和master之间的合并基础

  5. b2中做一些提交

  6. git log 将显示您的b2和master的日志历史记录

  7. 使用提交范围,如果您不熟悉该概念,我邀请您使用它进行谷歌搜索或堆栈溢出,

    对于您的实际情况,您可以例如

    git log commitID_FOO..comitID_BAR
    

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

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

  8. 看点#4,合并基础

    所以:git log COMMITID_mergeBASE..HEAD会告诉你区别

  9. Git可以像这样为您检索合并基础

    git merge-base b2 master
    
  10. 最后,您可以执行以下操作:

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

4

您可以尝试这样的事情:

#!/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用户手册》中配方中借用:

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

+1。我在回答中写道,您需要解析提交才能找到分支的起源,而您似乎已经做到了。
VonC

您是否使用过日志--walk-reflogs?我正在阅读有关此选项的信息,并为我提供了到目前为止所需的结果,(仍在测试中)
dimirc

@dimirc引用日志是完全不同的野兽。它通常记录恢复时间的分支点。我不确定您在接收后挂接中正在做什么,但是如果您对此进行了解释,那么人们可以为您的问题提供更明智的答案。
John Szakmeister

我只需要一键解析/检查所有提交消息。我要介绍的情况是,如果有人在master处推送了多个提交,并且也创建了一个具有多个提交的新分支。接收后钩子需要检查两个引用/分支的更改,例如master和newbranch,我需要知道new分支的边界,以避免两次解析提交消息,因为可以从master提交。
dimirc

1
好的。然后,我认为我概述的上述方法确实是您想要的。使用reflog,条目将在一段时间后下降,我认为这会引起您一些头痛。您可能也想看看使用git show-ref --tags
John Szakmeister

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

将列出每个分支的提示master

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

将列出master的历史记录中的所有提交,而不是其他任何分支机构的历史记录中的提交。

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


4

这将在当前分支上输出提交。如果传递了任何参数,则仅输出哈希值。

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

1
这为我产生了大约100条无关的日志消息。
艾莉·史蒂芬斯

嘿@ArlieStephens-我尝试过了,它似乎仍然对我有用?我刚刚在上面添加了帮助和更多错误消息。让我知道事情的后续!
布莱德·帕克斯

有趣。看看现在的代码,我认为它可能和原始代码一样简单,前提是我关心的分支来自master。使用当前代码,我可以明确指定父分支。(IIRC,我的dev分支来自发布分支,而不是master分支。)
Arlie Stephens

@ArlieStephens-是的,我认为我没有更改任何功能...。我又更新了一次,经过一些本地测试后使文档更加精确...并添加了以前的“详细”选项,但我没有记录下来
Brad Parks

3

我正在使用以下命令:

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

要么

git log --no-merges --graph --oneline --decorate master..<mybranch>

1

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

结帐至分行

  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是您运行第一个命令时将得到的两个字符串。将这些值不带<>放入第二个命令中。

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


如果您阅读问题的前三行,您会看到作者列出了此确切命令,并解释了为什么它不是他们想要的内容
black_fm

啊@black_fm我做了一些更改。如果您发现它现在有用,则可以对其进行投票。:)
Mustkeem K

0

就我而言,我们正在使用Git Flow和GitHub。您所需要做的就是:将功能分支与GitHub上的developer分支进行比较。

它将显示仅对功能分支所做的提交。

例如:

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


我同意当您遇到“我想看看请求请求的外观”的情况时,最好的解决方案通常是忽略git,而是使用GitHub发出请求请求或比较分支。
pkamb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.