Эмпирические правила
- Используйте
~
большую часть времени - чтобы вернуться на несколько поколений, обычно то, что вы хотите
- Используйте
^
в коммитах слияния - потому что у них два или более (непосредственных) родителя
Мнемоника:
- Тильда
~
выглядит почти линейно и хочет идти назад по прямой
- Каретка
^
предлагает интересный отрезок дерева или развилку на дороге
Тильда
Раздел «Задание редакций» документации git rev-parse
определяет ~
как
<rev>~<n>
, например, master~3
Суффикс ~<n>
к параметру ревизии означает объект фиксации, который является предком n поколения указанного объекта фиксации, следуя только первым родителям. [Например,] <rev>~3
эквивалентно <rev>^^^
, что эквивалентно <rev>^1^1^1
& hellip;
Вы можете получить к родителям любой коммит, а не только HEAD
. Вы также можете перемещаться назад через поколения: например, master~2
означает прародителя кончика главной ветви, отдавая предпочтение первому родителю при фиксации слияния.
Каре
История Git нелинейная: ориентированный ациклический граф (DAG) или дерево. Для коммита только с одним родителем rev~
и rev^
означают одно и то же. Селектор каретки становится полезным с коммитами слияния, потому что каждый из них является потомком двух или более родителей - и напрягает язык, заимствованный из биологии.
HEAD^
означает первого непосредственного родителя кончика текущей ветви. HEAD^
- это сокращение от HEAD^1
, и вы также можете указать HEAD^2
и т. Д. В зависимости от ситуации тот же раздел git rev-parse
документации определяет его как
<rev>^
, , например HEAD^
, v1.5.1^0
Суффикс ^
к параметру ревизии означает первого родителя этого объекта фиксации. ^<n>
означает n -го родителя ([ например, ] <rev>^
эквивалентно <rev>^1
). Как специальное правило, <rev>^0
означает сам коммит и используется, когда <rev>
является именем объекта тега, который ссылается на объект фиксации.
Примеры
Эти спецификаторы или селекторы могут быть произвольно соединены, например, , topic~3^2
на английском языке - это второй родительский элемент коммита слияния, который является пра-прародителем (три поколения назад) текущего наконечника филиал topic
.
В вышеупомянутом разделе git rev-parse
документации прослеживается множество путей через условную историю git. Время течет в основном вниз. Коммиты D, F, B и A являются коммитами слияния.
Вот иллюстрация Джона Лелигера. Оба узла фиксации B и C являются родителями узла фиксации A. Родительские коммиты располагаются слева направо.
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
и git lola
, поэтому вы можете просматривать историю как в
$ 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
«Указание редакций» в документации git rev-parse
содержит много полезной информации и заслуживает подробного прочтения. См. Также Git Tools - Выбор редакции из книги Pro Git .
Порядок родительских комиссий
Коммит 89e4fcb0dd из собственной истории git является коммитом слияния, как указывает git show 89e4fcb0dd
в строке заголовка Merge, которая отображает имена объектов непосредственных предков.
commit 89e4fcb0dd01b42e82b8f27f9a575111a26844df
Merge: c670b1f876 649bf3a42f b67d40adbb
Author: Junio C Hamano <gitster@pobox.com>
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>...]'
Если вы хотитеизвлеките только родителей, используйте симпатичный формат %P
для полных хешей
$ git log -1 --pretty=%P 89e4fcb0dd
c670b1f876521c9f7cd40184bf7ed05aad843433 649bf3a42f344e71b1b5a7f562576f911a1f7423 b67d40adbbaf4f5c4898001bf062a9fd67e43368
или %p
для сокращенных родителей.
$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb