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

使用下面的代码,它列出了来自分支的所有提交,也包括来自父(master)的所有提交

git log mybranch

我发现的另一种选择是排除主可达的提交,并给我我想要的,但我想避免知道其他分支名称的需要。

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 - 13 t15:08):

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

我想我找到了我一直在寻找的答案

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

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


当前回答

在这里,我根据Richard Hansen的回答(和Ben C的建议)给出了一个别名,但我对其进行了调整,以排除标签。别名应该相当健壮。

# For Git 1.22+
git config --global alias.only '!b=${1:-$(git branch --show-current)}; git log --oneline --graph "heads/$b" --not --exclude="$b" --branches --remotes #'
# For older Git:
git config --global alias.only '!b=${1:-$(git symbolic-ref -q --short HEAD)}; b=${b##heads/}; git log --oneline --graph "heads/$b" --not --exclude="$b" --branches --remotes #'

使用示例:

git only mybranch  # Show commits that are in mybranch ONLY
git only           # Show commits that are ONLY in current branch

注意,ONLY表示如果删除给定的分支(不包括标记的影响),提交将被丢失(在垃圾收集之后)。即使有一个名为mybranch的标记(多亏了前缀heads/),别名也应该工作。还要注意,根据ONLY的定义,如果提交是任何远程分支(包括上游分支)的一部分,则不会显示提交。

别名将单行历史记录显示为所选提交的图形。

  a --- b --- c --- master
   \           \
    \           d
     \           \
      e --- f --- g --- mybranch (HEAD)
       \
        h --- origin/other

对于上面的例子,git只会显示:

  * (mybranch,HEAD)
  * g
  |\
  | * d
  * f 

为了包含标签(但仍然不包括HEAD),别名变成(针对旧Git进行如上调整):

git config --global alias.only '!b=${1:-$(git branch --show-current)};  git log --oneline --graph --all --not --exclude="refs/heads/$b" --exclude=HEAD --all #'

或者包含所有标签的变体,包括HEAD(并默认删除当前分支,因为它不会输出任何东西):

git config --global alias.only '!git log --oneline --graph --all --not --exclude=\"refs/heads/$1\" --all #'

最后一个版本是唯一真正满足commit -that-are-lost-if-given-branch-is-deleted标准的版本,因为如果签出分支就不能删除分支,HEAD或任何其他标记指出的提交都不会丢失。然而,前两个变体更有用。

最后,别名不能用于远程分支(例如。Git只有origin/master)。别名必须修改,例如:

git config --global alias.remote-only '!git log --oneline --graph "$1" --not --exclude="$1" --remotes --branches #'

其他回答

下面的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命令是一个低级(管道)命令,它遍历给定的修订并转储遇到的SHA1标识符。可以把它看作是等价于git log,除了它只显示sha1 -没有日志消息,没有作者名称,没有时间戳,没有任何“花哨”的东西。

——no-walk选项,顾名思义,防止git rev-list遍历祖先链。所以如果你输入git rev-list——no-walk mybranch,它只会打印一个SHA1标识符:mybranch分支的tip提交标识符。

——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显示除了这些提交和它们的祖先之外的所有内容。

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

去虫子?

我本希望以下几点能起作用:

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

但事实并非如此。我猜这是Git中的一个bug,但也可能是故意的。

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

会列出每个非主分支的提示。

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

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

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

从上面的评论中我看到-你只希望那些提交属于该分支,而不是它的父分支。但从技术上讲,当你从另一个分支创建一个分支时,这些提交也会复制到子分支。 但是对于你的问题,下面的命令是有用的。

git log childBranch...parentBranch

如果父分支是远程分支,可以使用以下命令。

git log yourBranch --not --remotes=origin

这是有效的:这完全符合你的要求:

for a in $(git rev-list anybranch..mybranch); do echo -n "$a "; git branch --contains $a | xargs; done

你可以使用严格的git rev-list——但如果你只关心某个分支上的提交,而不关心其他地方的提交,那么选择任何你认为自己来自的分支至少会限制实际的明显差异,而且你可以一眼看出哪些提交只属于该分支。

我做了一个别名,以便能够简单地输入“git logbranch”,并有特定于当前分支的所有提交。 这是别名:

[alias]
    logbranch = "!cd -- \"${GIT_PREFIX:-.}\" && CURRENT_BRANCH=$(git branch --show-current) && git log $CURRENT_BRANCH --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v refs/heads/$CURRENT_BRANCH) #"

注意:把它放在主目录下的.gitconfig文件的[alias]标签下。

因此,我基本上使用了最初在问题帖子中发布的内容,并使用CURRENT_BRANCH变量使其更快。 希望这将节省你一些时间!