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

时间:2013-02-13 07:11:46

标签: git

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

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

的提交
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 达到的提交。

14 个答案:

答案 0 :(得分:113)

听起来你应该使用cherry

git cherry -v develop mybranch

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

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

答案 1 :(得分:33)

  

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

我不认为这是可能的:Git中的分支总是基于另一个分支或至少在另一个提交上,如“git diff doesn't show enough”中所述:

enter image description here

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

如“GIT - Where did I branch from?”中所述:

  

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

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

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

答案 2 :(得分:19)

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

git log --graph [branchname]

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

例如,让我们看看下面的cakephp GitHub repo上git 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的{​​{1}}是提交行中的第一个字符。这些提交来自主分支,而其他四个来自其他分支。

答案 3 :(得分: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)

但是,除非HEAD已签出,否则您排除mybranch,否则您可能会面临显示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日志消息,没有作者姓名,没有时间戳,没有任何“花哨”的东西。

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

我原本期望以下工作:

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

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

答案 4 :(得分:9)

我正在使用以下命令:

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

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

答案 5 :(得分:6)

快速回答:

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

让我们说:

  1. 您有分支

  2. 做一些提交

  3. 您创建了一个名为 b2

  4. 的分支
  5. git log -n1; commit id是b2和master

  6. 之间的合并基础
  7. b2

  8. 中做一些提交
  9. git log将显示b2和主

  10. 的日志历史记录
  11. 使用提交范围,如果您不熟悉这个概念,我邀请您谷歌或堆栈溢出 -

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

    git log commitID_FOO..comitID_BAR
    

    &#34; ..&#34;是log命令的范围运算符。

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

  12. 请看第4点,合并基础

    所以:git log COMMITID_mergeBASE..HEAD会显示差异

  13. Git可以为您检索合并基础

    git merge-base b2 master
    
  14. 最后你可以这样做:

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

答案 6 :(得分: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)

或者,借用recipe in the Git User's Manual

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

答案 7 :(得分:2)

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

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

答案 8 :(得分:1)

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必须遵循提供commit rev的筛选器-list不应该走路。

答案 9 :(得分:1)

在这里,我根据 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 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 #'

答案 10 :(得分:0)

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

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

例如:

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

答案 11 :(得分:0)

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

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

一个简单的grep -v就可以完成这项工作:
git log --pretty=oneline --graph | grep -v "^|"

当然,如果您需要其他信息,可以将其保持在一行中,然后就可以更改漂亮参数。

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

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

答案 12 :(得分:0)

选项 1(看起来更快,但您可能会在 Git Bash 中收到错误 bash: /mingw64/bin/git: Argument list too long(尽管它在 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}'

答案 13 :(得分:-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是您在运行第一个命令时会得到的两个字符串。将这些值不带<>放入第二个命令。

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