经验法则
- Use
~
大多数时候——可以追溯到几代人之前,通常是你想要的
- Use
^
在合并提交上 - 因为它们有两个或更多(直接)父母
助记符:
- Tilde
~
外观近乎直线,想直线向后走
- Caret
^
建议树上有趣的部分或岔路口
Tilde
The 的“指定修订”部分git rev-parse文档 https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrevgtltngtemegemmaster3em定义~
as
<rev>~<n>
, e.g. master~3
A suffix ~<n>
to a revision parameter means the commit object that is the nth generation ancestor of the named commit object, following only the first parents. For example, <rev>~3
is equivalent to <rev>^^^
which is equivalent to <rev>^1^1^1
…
您可以联系任何提交的父母,而不仅仅是HEAD
。您还可以向后移动几代人:例如,master~2
表示主分支尖端的祖父母,在合并提交时支持第一个父分支。
Caret
Git 历史是非线性的:有向无环图 (DAG) 或树。对于只有一个父级的提交,rev~
and rev^
意思是一样的。插入符号选择器对于合并提交非常有用,因为每个提交都是两个或多个父母的孩子 - 并且从生物学借用了语言。
HEAD^
意思是第一个即时当前分支尖端的父级。HEAD^
是缩写HEAD^1
,您还可以解决HEAD^2
等等。这的同一部分git rev-parse文档 https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrevgtemegemHEADv1510em将其定义为
<rev>^
, e.g. HEAD^
, v1.5.1^0
A suffix ^
to a revision parameter means the first parent of that commit object. ^<n>
means the nth parent ([e.g.] <rev>^
is equivalent to <rev>^1
). As a special rule, <rev>^0
means the commit itself and is used when <rev>
is the object name of a tag object that refers to a commit object.
Examples
这些说明符或选择器可以任意链接,e.g., topic~3^2
英文是合并提交的第二个父级,它是分支当前尖端的曾祖父母(三代人之前)topic
.
The 上述部分的git rev-parse文档 https://git-scm.com/docs/git-rev-parse#_specifying_revisions追溯了名义上的 git 历史的许多路径。时间总体上向下流动。提交 D、F、B 和 A 是合并提交。
这是 Jon Loeliger 绘制的插图。提交节点 B 和 C 都是提交节点 A 的父节点。父节点提交按从左到右的顺序排列。 (注:git log --graph
命令以相反的顺序显示历史记录。)
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
运行下面的代码来创建一个 git 存储库,其历史记录与引用的插图相匹配。
#! /usr/bin/env perl
use strict;
use warnings;
use subs qw/ postorder /;
use File::Temp qw/ mkdtemp /;
my %sha1;
my %parents = (
A => [ qw/ B C / ],
B => [ qw/ D E F / ],
C => [ qw/ F / ],
D => [ qw/ G H / ],
F => [ qw/ I J / ],
);
sub postorder {
my($root,$hash) = @_;
my @parents = @{ $parents{$root} || [] };
postorder($_, $hash) for @parents;
return if $sha1{$root};
@parents = map "-p $sha1{$_}", @parents;
chomp($sha1{$root} = `git commit-tree @parents -m "$root" $hash`);
die "$0: git commit-tree failed" if $?;
system("git tag -a -m '$sha1{$root}' '$root' '$sha1{$root}'") == 0 or die "$0: git tag failed";
}
$0 =~ s!^.*/!!; # / fix Stack Overflow highlighting
my $repo = mkdtemp "repoXXXXXXXX";
chdir $repo or die "$0: chdir: $!";
system("git init") == 0 or die "$0: git init failed";
chomp(my $tree = `git write-tree`); die "$0: git write-tree failed" if $?;
postorder 'A', $tree;
system "git update-ref HEAD $sha1{A}"; die "$0: git update-ref failed" if $?;
system "git update-ref master $sha1{A}"; die "$0: git update-ref failed" if $?;
# for browsing history - http://blog.kfish.org/2010/04/git-lola.html
system "git config alias.lol 'log --graph --decorate --pretty=oneline --abbrev-commit'";
system "git config alias.lola 'log --graph --decorate --pretty=oneline --abbrev-commit --all'";
它仅在新的一次性存储库中添加别名git lol and git lola http://blog.kfish.org/2010/04/git-lola.html这样你就可以查看历史记录
$ git lol
* 29392c8 (HEAD -> master, tag: A) A
|\
| * a1ef6fd (tag: C) C
| |
| \
*-. \ 8ae20e9 (tag: B) B
|\ \ \
| | |/
| | * 03160db (tag: F) F
| | |\
| | | * 9df28cb (tag: J) J
| | * 2afd329 (tag: I) I
| * a77cb1f (tag: E) E
* cd75703 (tag: D) D
|\
| * 3043d25 (tag: H) H
* 4ab0473 (tag: G) G
请注意,在您的计算机上,SHA-1 对象名称将与上面的名称不同,但标签允许您按名称处理提交并检查您的理解。
$ git log -1 --format=%f $(git rev-parse A^)
B
$ git log -1 --format=%f $(git rev-parse A~^3~)
I
$ git log -1 --format=%f $(git rev-parse A^2~)
F
The 中的“指定修订”git rev-parse文档 https://git-scm.com/docs/git-rev-parse#_specifying_revisions充满了重要的信息,值得深入阅读。也可以看看Git 工具 - 修订选择 https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection从书中Pro Git https://git-scm.com/book/en/v2/.
父级提交的顺序
提交89e4fcb0dd https://github.com/git/git/commit/89e4fcb0dd01b42e82b8f27f9a575111a26844df从 git 自己的历史来看,是一个合并提交,如下git show 89e4fcb0dd
指示显示直接祖先对象名称的合并标题行。
commit 89e4fcb0dd01b42e82b8f27f9a575111a26844df
Merge: c670b1f876 649bf3a42f b67d40adbb
Author: Junio C Hamano <[email protected] /cdn-cgi/l/email-protection>
Date: Mon Oct 29 10:15:31 2018 +0900
Merge branches 'bp/reset-quiet' and 'js/mingw-http-ssl' into nd/config-split […]
我们可以通过询问确认订单git rev-parse
按顺序显示 89e4fcb0dd 的直接父母。
$ git rev-parse 89e4fcb0dd^1 89e4fcb0dd^2 89e4fcb0dd^3
c670b1f876521c9f7cd40184bf7ed05aad843433
649bf3a42f344e71b1b5a7f562576f911a1f7423
b67d40adbbaf4f5c4898001bf062a9fd67e43368
查询不存在的第四个父级会导致错误。
$ git rev-parse 89e4fcb0dd^4
89e4fcb0dd^4
fatal: ambiguous argument '89e4fcb0dd^4': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
如果您只想提取父母,请使用漂亮的格式 https://git-scm.com/docs/git-log#_pretty_formats %P
对于完整的哈希值
$ git log -1 --pretty=%P 89e4fcb0dd
c670b1f876521c9f7cd40184bf7ed05aad843433 649bf3a42f344e71b1b5a7f562576f911a1f7423 b67d40adbbaf4f5c4898001bf062a9fd67e43368
or %p
对于简短的父母。
$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb