291

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

使用以下内容,它列出了来自分支的所有提交,也来自父级(主)

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 选项很好,但我检查了 reflogs 是否过期(默认为 90 天,gc.reflogExpire)。

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

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

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

4

16 回答 16

235

从听起来你应该使用的内容来看cherry

git cherry -v develop mybranch

这将显示包含在mybranch中的所有提交,但不在develop中。如果您放弃最后一个选项(mybranch),它将改为比较当前分支。

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

于 2014-07-10T04:18:00.470 回答
50

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

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

在此处输入图像描述

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

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

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

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

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

于 2013-02-13T07:34:49.913 回答
37

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

git log --graph [branchname]

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

例如,让我们看一下以下git log --graph masteron 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具有*提交行中的第一个字符。这些提交来自主分支,而其他四个来自其他一些分支。

于 2016-08-31T03:09:09.207 回答
14

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

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

注意事项

如果您已mybranch签出,则上述命令将不起作用。那mybranchHEAD因为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)

如果远程分支是远程存储库的默认分支(通常仅适用于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 会打印除refs/heads/mybranch. 这些提交及其祖先是您感兴趣的提交——这些是您不想看到的提交

其他提交是您想要查看的,因此我们收集输出并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 中的一个错误,但也许是故意的。

于 2014-09-12T05:14:33.720 回答
12

我正在使用以下命令:

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

或者

git log --no-merges --graph --oneline --decorate master..<mybranch>
于 2020-04-18T05:04:51.060 回答
11

快速回答:

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
    
于 2014-01-18T14:50:18.573 回答
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" )
于 2013-02-13T07:48:56.967 回答
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
于 2017-08-18T18:35:42.237 回答
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必须遵循提供提交 rev-list 不应该走的过滤器。

于 2018-07-22T16:29:23.957 回答
3

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

结帐到分行,然后

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

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

于 2018-07-18T10:26:11.150 回答
2

在这里,我根据 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(感谢 prefix heads/),别名也应该起作用。另请注意,如果提交是任何远程分支(包括上游,如果有)的一部分,则不会显示提交,符合ONLY的定义。

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

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

通过上面的示例,git only将显示:

  * (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 #'

最后一个版本是唯一真正满足条件 commits-that-are-lost-if-given-branch-is-deleted 的版本,因为如果分支被签出,并且没有 HEAD 或任何指向的提交,则无法删除它其他标签将丢失。然而,前两个变体更有用。

最后,别名不适用于远程分支(例如。git only origin/master)。必须修改别名,例如:

git config --global alias.remote-only '!git log --oneline --graph "$1" --not --exclude="$1" --remotes --branches #'
于 2021-01-11T16:05:46.607 回答
1

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

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

例如:

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

于 2014-07-23T04:15:24.060 回答
1

我需要为特定分支导出一行日志。

所以我可能想出了一个更简单的解决方案。
这样做时,git log --pretty=oneline --graph我们可以看到当前分支中未完成的所有提交都是以|

所以一个简单grep -v的工作:
git log --pretty=oneline --graph | grep -v "^|"

当然,如果您需要其他信息,您可以更改 pretty 参数,只要将其保留在一行中即可。

您可能也想删除合并提交。
当消息以“合并分支”开头时,管道另一个grep -v,你就完成了。

在我的具体情况下,最终命令是:
git log --pretty="%ad : %an, %s" --graph | grep -v "^|" | grep -v "Merge branch"

于 2020-10-07T07:48:53.977 回答
0

选项 1(似乎更快,但您可能会bash: /mingw64/bin/git: Argument list too long在 Git Bash 中遇到错误(尽管它在 Linux 中有效),具体取决于您的项目有多少分支)

git log <your_branch> --not $(git branch -a | grep -v <your_branch> | grep -ve '->' | sed "s/\s//g")

选项 2

git rev-list <your_branch> | git name-rev --stdin | sed -E 's/~[0-9]+//g; s/\^[0-9]+//g' | grep " <your_branch>" | awk -F " " '{print $1}'

于 2021-05-10T03:25:55.920 回答
0

这仍然在 2021 年讨论过,这个问题是 8 年前提出的。我很困惑为什么没有人建议使用 git --first-parent。这不是现在的解决方案吗?我目前有同样的问题,这对我来说看起来很好。我结合了这些选项:

git --first-parent --cherry  first-commit-on-branch..

我什至将来自 master 的进一步提交合并到我的功能分支中,但是由于cherry 是--cherry-pick、--right-only 和--no-merges 的组合,这些提交被过滤掉了。您需要手动查找分支上的第一个提交或从那时起您想要查找所有后续提交的提交。

于 2022-01-11T15:09:49.797 回答
0

我设法通过使用 原始文档来做到这一点:git log <branch> git -log--not <branch-name>

格式示例:

git log branch-name  --date-order --format='%ai %an <%ae> %h %f'--format='%ai , %an ,<%ae> ,%h ,%f' >> c:\log.csv
于 2021-12-21T15:00:36.690 回答