Git只能获得特定分支的提交日志

我想列出只是特定分支的一部分的所有提交。

通过以下内容,它列出了来自分支的所有提交,还列出了来自父(主)

git log mybranch 

我发现的另一个select是排除主人可达的提交,并给我我想要的,但是我想避免需要知道其他分支的名字。

 git log mybranch --not master 

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

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

更新:

我正在testing一个新的选项,我刚才发现,直到现在看来,这可能是我所期待的:

 git log --walk-reflogs mybranch 

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

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

我想我find了我正在寻找的答案:

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

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

从听起来你应该使用cherry

 git cherry -v develop mybranch 

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

正如VonC所指出的那样,你总是把你的分支与另一个分支进行比较,所以知道你的分支,然后select与哪个分支进行比较。

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

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

在这里输入图像说明

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

正如“ GIT – 我从哪里分支? ”中提到的那样 :

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

所以,即使git log master..mybranch是一个答案,它仍然会显示太多的提交,如果mybranch是基于myotherbranch ,本身是基于master

为了find这个引用(你的分支的起源),你只能parsing提交,看看它们在哪个分支,如下所示:

  • “ Git:find一个提交来自哪个分支 ”。
  • “ 我怎么能看到另一个分支是从哪个分支分出来的呢?

我终于find了做OP的想法。 这很简单:

 git log --graph [branchname] 

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

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

 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*是提交行中的第一个字符。 这些提交来自主分支,而其他四个来自其他分支。

下面的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) 

但是,除非mybranch被检出,否则你应该排除HEAD ,否则你冒着显示不是mybranch专有的提交的风险。

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

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

如果远程分支是远程仓库的默认分支(通常只适用于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命令是一个低级别(pipe道)命令,用于遍历给定的修订版本并转储遇到的SHA1标识符。 把它看作等同于git log除了它只显示SHA1-没有日志消息,没有作者的名字,没有时间戳,没有那些“奇特”的东西。

顾名思义, --no-walk选项阻止了git rev-list走向血统链。 所以,如果你inputgit rev-list --no-walk mybranch ,它将只打印一个SHA1标识符: mybranch分支的提示提交的mybranch

--exclude=refs/heads/mybranch --all参数告诉git rev-list从每个引用开始,除了refs/heads/mybranch

所以,当你运行git rev-list --no-walk --exclude=refs/heads/mybranch --all ,Git将打印除refs/heads/mybranch之外的每个ref的提示提交的SHA1标识符。 这些提交和他们的祖先是你感兴趣的提交 – 这些是你不想看到的提交。

其他的提交是你想看到的,所以我们收集git rev-list --no-walk --exclude=refs/heads/mybranch --all的输出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中的一个bug,但也许是故意的。

快速回答:

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

我们说:

  1. 你有一个分支

  2. 做一些提交

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

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

  5. b2中做一些提交

  6. git log会显示你的b2和master的日志历史logging

  7. 使用提交范围,如果你不熟悉这个概念,我邀请你去谷歌它或堆栈溢出它,

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

     git log commitID_FOO..comitID_BAR 

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

    这意味着,在一个简单的forms,给我所有日志比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 

你可以尝试这样的事情:

 #!/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" ) 

在我的情况下,我们正在使用Git Flow和GitHub。 所有你需要做的是:在GitHub上比较你的function分支和开发分支。

它将显示仅提交给您的function分支的提交。

例如:

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

这将输出当前分支上的提交。 如果有任何parameter passing,它只是输出散列。

git_show_all_commits_only_on_this_branch

 BRANCH=$(git branch | grep "*" | awk '{print $2}') OUT=$(git cherry -v master $BRANCH ) if [ -z "$1" ] then echo "$OUT" else echo "$OUT" | awk '{print $2}' fi