使用 Git,显示所有*仅*存在于一个特定分支上的提交,而不是*任何*其他分支

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5720343/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 10:40:31  来源:igfitidea点击:

Using Git, show all commits that exist *only* on one specific branch, and not *any* others

git

提问by jimmyorr

Given a branch, I'd like to see a list of commits that exist onlyon that branch. In this questionwe discuss ways to see which commits are on one branch but not one or more specified other branches.

给定一个分支,我想查看仅存在于该分支上的提交列表。在这个问题中,我们讨论了查看哪些提交在一个分支上而不是一个或多个指定的其他分支上的方法。

This is slightly different. I'd like to see which commits are on one branch but not on anyother branches.

这略有不同。我想看看哪些提交是在一个分支上,而不是在任何其他分支上。

The use case is in a branching strategy where some branches should only be merged to, and never committed directly on. This would be used to check if any commits have been made directly on a "merge-only" branch.

用例是在分支策略中,其中一些分支应该只合并到,而不要直接提交。这将用于检查是否直接在“仅合并”分支上进行了任何提交。

EDIT: Below are steps to set up a dummy git repo to test:

编辑:以下是设置虚拟 git 存储库进行测试的步骤:

git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt 
git commit -am "2nd valid commit on master"
git checkout merge-only 
git merge master

Only the commit with message "bad commit directly on merge-only", which was made directly on the merge-only branch, should show up.

只有在仅合并分支上直接进行的带有消息“直接在仅合并上进行错误提交”的提交才应显示。

采纳答案by jimmyorr

Courtesy of my dear friend Redmumba:

由我亲爱的朋友Redmumba 提供

git log --no-merges origin/merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/remotes/origin |
    grep -Fv refs/remotes/origin/merge-only)

...where origin/merge-onlyis your remote merge-only branch name. If working on a local-only git repo, substitute refs/remotes/originwith refs/heads, and substitute remote branch name origin/merge-onlywith local branch name merge-only, i.e.:

...origin/merge-only您的远程仅合并分支名称在哪里。如果在仅本地的 git repo 上工作,请替换refs/remotes/originrefs/heads,并将远程分支名称origin/merge-only替换为本地分支名称merge-only,即:

git log --no-merges merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/heads |
    grep -Fv refs/heads/merge-only)

回答by wrtsprt

We just found this elegantsolution

我们刚刚找到了这个优雅的解决方案

git log --first-parent --no-merges

In your example of course the initial commit still shows up.

当然,在您的示例中,初始提交仍会显示。

this answer does not exactly answer the question, because the initial commit still shows up. On the other hand many people coming here seem to find the answer they are looking for.

这个答案并没有完全回答这个问题,因为初始提交仍然出现。另一方面,许多来到这里的人似乎找到了他们正在寻找的答案。

回答by Prakash

git log origin/dev..HEAD

This will show you all the commits made in your branch.

这将向您显示在您的分支中所做的所有提交。

回答by Bryan

@Prakash answer works. Just for clarity ...

@Prakash 答案有效。只是为了清楚...

git checkout feature-branch
git log master..HEAD

lists the commits on feature-branch but not the upstream branch (typically your master).

列出功能分支上的提交,但不列出上游分支(通常是您的主分支)。

回答by grzuy

Maybe this could help:

也许这可以帮助:

git show-branch

回答by manojlds

Try this:

尝试这个:

git rev-list --all --not $(git rev-list --all ^branch)

Basically git rev-list --all ^branchgets all revisions not in branch and then you all the revisions in the repo and subtract the previous list which is the revisions onlyin the branch.

基本上git rev-list --all ^branch获取不在分支中的所有修订,然后你在 repo 中获取所有修订,并减去前一个列表,即在分支中的修订。

After @Brian's comments:

在@Brian 发表评论后:

From git rev-list's documentation:

来自 git rev-list 的文档:

List commits that are reachable by following the parent links from the given commit(s)

List commits that are reachable by following the parent links from the given commit(s)

So a command like git rev-list Awhere A is a commit will list commits that are reachable from A inclusive of A.

因此,像git rev-list Awhere A is a commit这样的命令将列出从包含 A 的 A 可访问的提交。

With that in mind, something like

考虑到这一点,类似于

git rev-list --all ^A

git rev-list --all ^A

will list commits not reachable from A

将列出无法从 A 访问的提交

So git rev-list --all ^branchwill list all commits not reachable from the tip of branch. Which will remove all the commits in the branch, or in other words commits that are only in other branches.

所以git rev-list --all ^branch将列出所有从分支尖端无法到达的提交。这将删除分支中的所有提交,或者换句话说,仅在其他分支中的提交。

Now let's come to git rev-list --all --not $(git rev-list --all ^branch)

现在让我们来 git rev-list --all --not $(git rev-list --all ^branch)

This will be like git rev-list --all --not {commits only in other branches}

这会像 git rev-list --all --not {commits only in other branches}

So we want to list allthat are not reachable from all commits only in other branches

所以我们想列出all那些无法从all commits only in other branches

Which is the set of commits that are only inbranch. Let's take a simple example:

这是仅在分支中的提交集。我们举一个简单的例子:

             master

             |

A------------B

  \

   \

    C--------D--------E

                      |

                      branch

Here the goal is to get D and E, the commits not in any other branch.

这里的目标是获得 D 和 E,提交不在任何其他分支中。

git rev-list --all ^branchgive only B

git rev-list --all ^branch只给 B

Now, git rev-list --all --not Bis what we come down to. Which is also git rev-list -all ^B- we want all commits not reachable from B. In our case it's is D and E. Which is what we want.

现在,git rev-list --all --not B这就是我们的目标。这也是git rev-list -all ^B- 我们希望所有提交都无法从 B 到达。在我们的例子中,它是 D 和 E。这就是我们想要的。

Hope this explains how the command works correctly.

希望这能解释命令如何正确工作。

Edit after comment:

评论后编辑:

git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt 
git commit -am "2nd valid commit on master"

After the above steps, if you do a git rev-list --all --not $(git rev-list --all ^merge-only)you will get the commit you were looking for - the "bad commit directly on merge-only"one.

完成上述步骤后,如果您执行 a,git rev-list --all --not $(git rev-list --all ^merge-only)您将获得您正在寻找的提交 - 那个"bad commit directly on merge-only"

But once you do the final step in your steps git merge masterthe command will not give the expected output. Because as of now there is no commit that is not there in merge-only since the one extra commit in master also has been merged to merge-only. So git rev-list --all ^branchgives empty result and hence git rev-list -all --not $(git rev-list --all ^branch)will give allthe commits in merge-only.

但是,一旦您完成步骤中的最后一步, git merge master该命令将不会给出预期的输出。因为到目前为止,在仅合并中没有不存在的提交,因为 master 中的一个额外提交也已合并到仅合并中。所以git rev-list --all ^branch给出空结果,因此git rev-list -all --not $(git rev-list --all ^branch)将在仅合并中给出所有提交。

回答by JaimeJorge

Another variation of the accepted answers, to use with master

已接受答案的另一种变体,用于 master

git log origin/master --not $(git branch -a | grep -Fv master)

git log origin/master --not $(git branch -a | grep -Fv master)

Filter all commits that happen in any branch other than master.

过滤除 master 之外的任何分支中发生的所有提交。

回答by torek

This is not exactly a real answer, but I need access to formatting, and a lot of space. I'll try to describe the theory behind what I consider the two best answers: the accepted oneand the (at least currently) top-ranked one. But in fact, they answer different questions.

这不是一个真正的答案,但我需要访问格式和大量空间。我将尝试描述我认为的两个最佳答案背后的理论:公认的答案和(至少目前)排名最高的答案。但事实上,他们回答了不同的问题

Commits in Git are very often "on" more than one branch at a time. Indeed, that's much of what the question is about. Given:

Git 中的提交经常一次“在”多个分支上。事实上,这就是问题的大部分内容。鉴于:

...--F--G--H   <-- master
         \
          I--J   <-- develop

where the uppercase letters stand in for actual Git hash IDs, we're often looking for only commit Hor only commits I-Jin our git logoutput. Commits up through Gare on bothbranches, so we'd like to exclude them.

在大写字母代表实际 Git 哈希 ID 的情况下,我们经常在我们的输出中寻找仅提交H仅提交I-Jgit log。提交通过G两个分支上,所以我们想排除它们。

(Note that in graphs drawn like this, newer commits are towards the right. The namesselect the single right-most commit on that line. Each of those commits has a parent commit, which is the commit to their left: the parent of His G, and the parent of Jis I. The parent of Iis Gagain. The parent of Gis F, and Fhas a parent that simply isn't shown here: it's part of the ...section.)

(请注意,在这样绘制的图表中,较新的提交向右。名称选择该行最右侧的单个提交。每个提交都有一个父提交,即左侧的提交:的父提交HG和母公司JI的父,IG再一次的家长。GF,并F有简单的这里没有显示父:它的一部分的...部分)。

For this particularly simple case, we can use:

对于这种特别简单的情况,我们可以使用:

git log master..develop    # note: two dots

to view I-J, or:

查看I-J,或:

git log develop..master    # note: two dots

to view Honly. The right-side name, after the two dots, tells Git: yes, these commits. The left-side name, before the two dots, tells Git: no, not these commits. Git starts at the end—at commit Hor commit J—and works backwards. For (much) more about this, see Think Like (a) Git.

H仅查看。右侧的名称,在两个点之后,告诉 Git:是的,这些提交。两个点之前的左侧名称告诉 Git:不,不是这些提交。Git 从最后开始——在提交H或提交时J——并向后工作。有关(更多)更多信息,请参阅Think Like (a) Git

The way the original question is phrased, the desire is to find commits that are reachable fromone particular name, but not from any other namein that same general category. That is, if we have a more complex graph:

原始问题的表述方式是,希望找到可从一个特定名称访问的提交,但不能从同一一般类别中的任何其他名称访问。也就是说,如果我们有一个更复杂的图:

               O--P   <-- name5
              /
             N   <-- name4
            /
...--F--G--H--I---M   <-- name1
         \       /
          J-----K   <-- name2
           \
            L   <-- name3

we could pick out one of these names, such as name4or name3, and ask: which commits can be found by that name, but not by any of the other names?If we pick name3the answer is commit L. If we pick name4, the answer is no commits at all: the commit that name4names is commit Nbut commit Ncan be found by starting at name5and working backwards.

我们可以选择其中一个名称,例如name4or name3,然后问:可以通过该名称找到哪些提交,但不能通过任何其他名称找到?如果我们选择name3答案是 commit L。如果我们选择name4,答案是根本没有提交:name4名称为 commitN但提交的提交N可以通过从 at 开始name5并向后工作找到。

The accepted answer works with remote-tracking names, rather than branch names, and allows you to designate one—the one spelled origin/merge-only—as the selected name and look at all other names in that namespace. It also avoids showing merges: if we pick name1as the "interesting name", and say show me commits that are reachable from name1but not any other name, we'll see merge commit Mas well as regular commit I.

接受的答案适用于远程跟踪名称,而不是分支名称,并允许您指定一个(拼写的)origin/merge-only作为所选名称并查看该名称空间中的所有其他名称。它还避免显示合并:如果我们选择name1“有趣的名称”,并说向我显示可从name1但不能从任何其他名称访问的提交,我们将看到合并提交M以及常规提交I

The most popular answer is quite different. It's all about traversing the commit graph withoutfollowing both legsof a merge, and without showingany of the commits that aremerges. If we start with name1, for instance, we won't show M(it's a merge), but assuming the firstparent of merge Mis commit I, we won't even look at commits Jand K. We'll end up showing commit I, and also commits H, G, F, and so on—none of these are merge commits and all are reachable by starting at Mand working backwards, visiting only the firstparent of each merge commit.

最受欢迎的答案是完全不同的。这是所有关于穿越提交图形,而不以下双腿合并,并没有表现出任何的是,提交的合并。name1例如,如果我们从 开始,我们不会显示M(这是一个合并),但假设合并的第一个父项M是 commit I,我们甚至不会查看 commitsJK。我们最终会显示 commit I,以及 commits HGF、等等——这些都不是合并提交,所有这些都可以通过从 at 开始M并向后工作,只访问每个合并提交的第一个父级来访问。

The most-popular answer is pretty well suited to, for instance, looking at masterwhen masteris intended to be a merge-only branch. If all "real work" was done on side branches which were subsequently merged into master, we will have a pattern like this:

最受欢迎的答案非常适合,例如,查看master何时master打算成为仅合并分支。如果所有“实际工作”都在随后合并到 的侧分支上完成master,我们将有一个这样的模式:

I---------M---------N   <-- master
 \       / \       /
  o--o--o   o--o--o

where all the un-letter-named ocommits are ordinary (non-merge) commits and Mand Nare merge commits. Commit Iis the initial commit: the very first commit ever made, and the only one that shouldbe on master that isn't a merge commit. If the git log --first-parent --no-merges mastershows any commit other thanI, we have a situation like this:

其中所有未以字母命名的o提交都是普通(非合并)提交,M并且N是合并提交。CommitI是初始提交:有史以来第一次提交,也是唯一一个应该在 master 上的不是合并提交的提交。如果git log --first-parent --no-merges master显示除 之外的任何提交I,我们会遇到这样的情况:

I---------M----*----N   <-- master
 \       / \       /
  o--o--o   o--o--o

where we want to see commit *that was made directly on master, not by merging some feature branch.

我们希望看到*直接在 上进行的提交,而master不是通过合并某些功能分支。

In short, the popular answer is great for looking at masterwhen masteris meant to be merge-only, but is not as great for other situations.The accepted answer works for these other situations.

简而言之,流行的答案非常适合查看master何时master仅用于合并,但对于其他情况则没有那么好。接受的答案适用于这些其他情况。

Are remote-tracking names like origin/masterbranchnames?

远程跟踪名称是否类似于origin/master分支名称?

Some parts of Git say they're not:

Git 的某些部分说它们不是:

git checkout master
...
git status

says on branch master, but:

on branch master,但是:

git checkout origin/master
...
git status

says HEAD detached at origin/master. I prefer to agree with git checkout/ git switch: origin/masteris not a branch namebecause you cannot get "on" it.

HEAD detached at origin/master。我更愿意同意git checkout/ git switch:origin/master不是分支名称,因为您无法“使用”它。

The accepted answeruses remote-tracking names origin/*as "branch names":

接受的答案使用远程跟踪名称origin/*作为“分支名称”:

git log --no-merges origin/merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/remotes/origin |
    grep -Fv refs/remotes/origin/merge-only)

The middle line, which invokes git for-each-ref, iterates over the remote-tracking names for the remote named origin.

调用 的中间行git for-each-ref遍历名为 的远程跟踪名称origin

The reason this is a good solution to the original problem is that we're interested here in someone else'sbranch names, rather than ourbranch names. But that means we've defined branchas something other than our branch names. That's fine: just be aware that you're doing this, when you do it.

这是原始问题的一个很好的解决方案的原因是我们在这里对其他人的分支名称感兴趣,而不是我们的分支名称。但这意味着我们已经将branch定义为我们的 branch names以外东西。没关系:只要注意你在做这件事,当你做的时候。

git logtraverses some part(s) of the commit graph

git log遍历提交图的某些部分

What we're really searching for here are series of what I have called daglets:see What exactly do we mean by "branch"?That is, we're looking for fragments within some subset of the overall commit graph.

我们在这里真正要寻找的是一系列我称之为daglets 的东西:请参阅我们所说的“分支”究竟是什么意思?也就是说,我们在整个提交图的某个子集中寻找片段

Whenever we have Git look at a branch name like master, a tag name like v2.1, or a remote-tracking name like origin/master, we tend to want to have Git tell us about that commit andevery commit that we can get to from that commit: starting there, and working backwards.

每当我们让 Git 查看像 那样的分支名称、像 一样master的标记名称v2.1或像 那样的远程跟踪名称时origin/master,我们倾向于让 Git 告诉我们该提交以及我们可以从该提交获得的每个提交:从那里开始,并反向工作。

In mathematics, this is referred to as walking a graph. Git's commit graph is a Directed Acyclic Graphor DAG, and this kind of graph is particularly suited for walking. When walking such a graph, one will visit each graph vertex that is reachablevia the path being used. The vertices in the Git graph are the commits, with the edges being arcs—one-way links—going from each child to each parent. (This is where Think Like (a) Gitcomes in. The one-way nature of arcs means that Git must work backwards, from child to parent.)

在数学中,这被称为走图。Git 的提交图是有向无环图DAG,这种图特别适合行走。在遍历这样一个图时,人们将访问通过所使用的路径可到达的每个图顶点。Git 图中的顶点是提交,边是弧——单向链接——从每个子节点到每个父节点。(这就是Think Like (a) Git 的用武之地。弧的单向性质意味着 Git 必须向后工作,从子级到父级。)

The two main Git commands for graph-walking are git logand git rev-list. These commands are extremely similar—in fact they're mostly built from the same source files—but their output is different: git logproduces output for humans to read, while git rev-listproduces output meant for other Git programs to read.1Both commands do this kind of graph-walk.

用于图形遍历的两个主要 Git 命令是git loggit rev-list。这些命令极其相似——实际上它们大多是从相同的源文件构建的——但它们的输出不同:git log产生供人类阅读的git rev-list输出,而产生供其他 Git 程序阅读的输出。1这两个命令都执行这种图形遍历。

The graph walk they do is specifically: given some set of starting point commits(perhaps just one commit, perhaps a bunch of hash IDs, perhaps a bunch of names that resolve to hash IDs), walk the graph, visiting commits. Particular directives, such as --notor a prefix ^, or --ancestry-path, or --first-parent, modify the graph walkin some way.

他们所做的图遍历具体是:给定一组起始点提交(可能只是一个提交,可能是一堆散列 ID,也许是一堆解析为散列 ID 的名称),遍历图,访问 commits。特定指令,例如--notor 前缀^,或--ancestry-path,或--first-parent,以某种方式修改图游走

As they do the graph walk, they visit each commit. But they only printsome selected subsetof the walked commits. Directives such as --no-mergesor --before <date>tell the graph-walking code which commits to print.

当他们进行图走访时,他们会访问每个提交。但他们只打印一些选定的步行提交子集。诸如--no-mergesor 之类的指令--before <date>告诉提交print的图形行走代码。

In order to do this visiting, one commit at a time, these two command use a priority queue. You run git logor git rev-listand give it some starting point commits. They put those commits into the priority queue. For instance, a simple:

为了进行这种访问,一次提交一个,这两个命令使用一个优先级队列。你运行git logorgit rev-list并给它一些起点提交。他们将这些提交放入优先级队列。例如,一个简单的:

git log master

turns the name masterinto a raw hash ID and puts that one hash ID into the queue. Or:

将名称master转换为原始散列 ID 并将该散列 ID 放入队列中。或者:

git log master develop

turns both names into hash IDs and—assuming these are two different hash IDs—puts both into the queue.

将两个名称都转换为散列 ID,并且——假设它们是两个不同的散列 ID——将它们都放入队列中。

The priority of the commits in this queue is determined by still more arguments. For instance, the argument --author-date-ordertells git logor git rev-listto use the authortimestamp, rather than the committer timestamp. The default is to use the committer timestamp and pick the newest-by-date commit: the one with the highest numerical date. So with master develop, assuming these resolve to two different commits, Git will show whichever one came laterfirst, because that will be at the front of the queue.

此队列中提交的优先级由更多参数决定。例如,参数--author-date-order告诉git loggit rev-list使用作者时间戳,而不是提交者时间戳。默认是使用提交者时间戳并选择最新的按日期提交:具有最高数字日期的提交。因此master develop,假设这些解析为两个不同的提交,Git 将显示稍后出现的那个,因为它将在队列的前面。

In any case, the revision walking code now runs in a loop:

在任何情况下,修订行走代码现在都在循环中运行:

  • While there are commits in the queue:
    • Remove the first queue entry.
    • Decide whether to print this commit at all. For instance, --no-merges: print nothing if it is a merge commit; --before: print nothing if its date does not come before the designated time. If printing isn'tsuppressed, print the commit: for git log, show its log; for git rev-list, print its hash ID.
    • Put some or all of this commit's parentcommits into the queue (as long as it isn't there now, and has not been visited already2). The normal default is to put in all parents. Using --first-parentsuppresses all but the firstparent of each merge.
  • 虽然队列中有提交:
    • 删除第一个队列条目。
    • 决定是否完全打印此提交。例如--no-merges:如果是合并提交,则不打印任何内容;--before: 如果日期不早于指定时间,则不打印任何内容。如果打印未被抑制,则打印提交:for git log,显示其日志;for git rev-list,打印其哈希 ID。
    • 将此提交的部分或全部提交放入队列(只要它现在不存在,并且尚未被访问2)。正常的默认值是放入所有父级。Using--first-parent抑制除了每个合并的第一个父级之外的所有内容。

(Both git logand git rev-listcan do history simplificationwith or without parent rewritingat this point as well, but we'll skip over that here.)

(在这一点上,git loggit rev-list都可以在有或没有父重写的情况下进行历史简化,但我们将在这里跳过。)

For a simple chain, like start at HEADand work backwardswhen there are no merge commits, the queue always has one commit in it at the top of the loop. There's one commit, so we pop it off and print it and put its (single) parent into the queue and go around again, and we follow the chain backwards until we reach the very first commit, or the user gets tired of git logoutput and quits the program. In this case, none of the ordering options matter: there is only ever one commit to show.

对于一个简单的链,比如HEAD没有合并提交时开始和向后工作,队列总是在循环顶部有一个提交。有一个提交,所以我们弹出它并打印它并将其(单个)父项放入队列并再次循环,我们沿着链向后直到我们到达第一个提交,或者用户厌倦了git log输出并退出该程序。在这种情况下,排序选项都不重要:只有一个提交要显示。

When there are merges and we follow both parents—both "legs" of the merge—or when you give git logor git rev-listmore than one starting commit, the sorting options matter.

当有合并并且我们遵循合并的两个“腿”时,或者当您提供git loggit rev-list多个开始提交时,排序选项很重要。

Last, consider the effect of --notor ^in front of a commit specifier. These have several ways to write them:

最后,考虑提交说明符的--not^前面的效果。这些有几种写法:

git log master --not develop

or:

或者:

git log ^develop master

or:

或者:

git log develop..master

all mean the same thing. The --notis like the prefix ^except that it applies to more than one name:

都是一样的意思。The--not类似于前缀,^只是它适用于多个名称:

git log ^branch1 ^branch2 branch3

means not branch1, not branch2, yes branch3;but:

表示不是 branch1,不是 branch2,是 branch3;但:

git log --not branch1 branch2 branch3

means not branch1, not branch2, not branch3,and you have to use a second --notto turn it off:

意味着不是 branch1,不是 branch2,不是 branch3,你必须用一秒钟--not把它关掉:

git log --not branch1 branch2 --not branch3

which is a bit awkward. The two "not" directives are combined via XOR, so if you really want, you can write:

这有点尴尬。这两个“not”指令通过 XOR 组合在一起,所以如果你真的想要,你可以写:

git log --not branch1 branch2 ^branch3

to mean not branch1, not branch2, yes branch3, if you want to obfuscate.

表示不是 branch1,不是 branch2,是 branch3,如果你想混淆

These all work by affecting the graph walk. As git logor git rev-listwalks the graph, it makes sure notto put into the priority queue any commit that is reachable from any of the negatedreferences. (In fact, they affect the starting setup too: negated commits can't go into the priority queue right from the command line, so git log master ^mastershows nothing, for instance.)

这些都是通过影响图行走来工作的。当git loggit rev-list走图时,它确保不会将任何可从任何否定引用访问的提交放入优先级队列。(实际上,它们也会影响启动设置:例如,否定提交不能直接从命令行进入优先级队列,因此不git log master ^master显示任何内容。)

Allof the fancy syntax described in the gitrevisions documentationmakes use of this, and you can expose this with a simple call to git rev-parse. For instance:

gitrevisions 文档中描述的所有花哨语法都使用了它,您可以通过简单地调用git rev-parse. 例如:

$ git rev-parse origin/pu...origin/master     # note: three dots
b34789c0b0d3b137f0bb516b417bd8d75e0cb306
fc307aa3771ece59e174157510c6db6f0d4b40ec
^b34789c0b0d3b137f0bb516b417bd8d75e0cb306

The three-dot syntax means commits reachable from either left or right side, but excluding commits reachable from both. In this case the origin/mastercommit, b34789c0b, is itself reachable from origin/pu(fc307aa37...) so the origin/masterhash appears twice, once with a negation, but in fact Git achieves the three-dot syntax by putting in two positive references—the two non-negated hash IDs—and one negative one, represented by the ^prefix.

三点语法表示可从左侧或右侧访问的提交,但不包括可从两者访问的提交。在这种情况下,origin/master提交 , b34789c0b本身可以从origin/pu( fc307aa37...)访问,因此origin/master散列出现两次,一次带有否定,但实际上 Git 通过放入两个正引用(两个非否定的散列 ID)来实现三点语法一负一,由^前缀表示。

Simiarly:

同样:

$ git rev-parse master^^@
2c42fb76531f4565b5434e46102e6d85a0861738
2f0a093dd640e0dad0b261dae2427f2541b5426c

The ^@syntax means all the parents of the given commit, and master^itself—the first parent of the commit selected by branch-name master—is a merge commit, so it has two parents. These are the two parents. And:

^@语法意味着所有给定的父母承诺,以及master^本身-在此提交的分支名称选定的第一个父master-is合并提交,所以它有两个家长。这是两位家长。和:

$ git rev-parse master^^!
0b07eecf6ed9334f09d6624732a4af2da03e38eb
^2c42fb76531f4565b5434e46102e6d85a0861738
^2f0a093dd640e0dad0b261dae2427f2541b5426c

The ^!suffix means the commit itself, but none of its parents. In this case, master^is 0b07eecf6.... We already saw both parents with the ^@suffix; here they are again, but this time, negated.

^!后缀手段的承诺本身,但没有其父母。在这种情况下,master^0b07eecf6...。我们已经看到带有^@后缀的父母双方;他们又来了,但这一次,被否定了。



1Many Git programs literally run git rev-listwith various options, and read its output, to know what commits and/or other Git objects to use.

1许多 Git 程序实际上git rev-list使用各种选项运行,并读取其输出,以了解要使用的提交和/或其他 Git 对象。

2Because the graph is acyclic, it's possible to guarantee that none have been visited already, if we add the constraint never show a parent before showing all of its childrento the priority. --date-order, --author-date-order, and --topo-orderadd this constraint. The default sort order—which has no name—doesn't. If the commit timestamps are screwy—if for instance some commits were made "in the future" by a computer whose clock was off—this could in some cases lead to odd looking output.

2因为图是非循环的,所以可以保证没有人已经访问过,如果我们添加约束,在将其所有子项显示为优先级之前从不显示父项--date-order, --author-date-order, 并--topo-order添加此约束。默认排序顺序(没有名称)没有。如果提交时间戳很乱——例如,如果某些提交是由时钟关闭的计算机“在未来”进行的——这在某些情况下可能会导致看起来很奇怪的输出。



If you made it this far, you now know a lot about git log

如果你做到了这一步,你现在知道很多关于 git log

Summary:

概括:

  • git logis about showing some selected commits while walking some or all of some part of the graph.
  • The --no-mergesargument, found in both the accepted and the currently-top-ranked answers, suppresses showing some commits that arewalked.
  • The --first-parentargument, from the currently-top-ranked-answer, suppresses walkingsome parts of the graph, during the graph-walk itself.
  • The --notprefix to command line arguments, as used in the accepted answer, suppresses ever visitingsome parts of the graph at all, right from the start.
  • git log是关于在遍历图形的某些部分或全部部分时显示一些选定的提交。
  • --no-merges在已接受的和当前排名最高的答案中都找到了这个论点,它抑制了显示一些走过的提交。
  • --first-parent说法,从当前排名第一的回答,压制行走图形的某些部分,在图形的走本身。
  • --not在接受的答案中使用的命令行参数的前缀从一开始就完全禁止访问图形的某些部分。

We get the answers we like, to two different questions, using these features.

使用这些功能,我们可以得到我们喜欢的两个不同问题的答案。