Git'te HEAD ^ ve HEAD ~ arasındaki fark nedir?


756

Git'te bir üst öğe taahhüt nesnesi belirttiğimde, HEAD^ve arasında kafam karıştı HEAD~.

Her ikisi de HEAD^3ve gibi "numaralı" bir sürümü var HEAD~2.

Bana çok benzer ya da aynı görünüyorlar, ancak tilde ve şapka arasında herhangi bir fark var mı?


64
bağlantıları yapıştırmak kötü, biliyorum ama bu bulduğum en iyi açıklama ve içinde resim var. paulboxley.com/blog/2011/06/git-caret-and-tilde
igor

4
Bağlantılar koptuklarında özellikle kötüdür. Bu, bazı açıklamaları kopyalayıp yapıştırabildiğinden dolayı bunu önlemeye yardımcı olan soruyu cevaplamanın daha güvenli olmasının nedeni budur :)
Samuel

Yanıtlar:


763

Temel kurallar

  • ~Çoğu zaman kullanın - genellikle istediğinizi istediğiniz birkaç nesile geri dönmek için
  • ^Birleştirme taahhütlerinde kullanın - çünkü iki veya daha fazla (hemen) ebeveynleri var

Mnemonics:

  • Tilde ~görünüşte neredeyse doğrusaldır ve düz bir çizgide geriye gitmek ister
  • Caret ^, ilginç bir ağaç parçası veya yoldaki bir çatal önerir

Tilde

Ve “Belirleme Düzenlemeler” bölümü git rev-parse, onarım tanımlayıp ~olarak

<rev>~<n>Örneğinmaster~3
bir son ek ~<n>bir düzeltme parametresi olan nesne işlemek anlamına gelir n, inci adlı üretimi atası sadece ilk ebeveyn sonra, nesne işlemek. Örneğin, <rev>~3eşdeğerdir <rev>^^^eşdeğerdir hangi <rev>^1^1^1...

Sadece değil, herhangi bir taahhütten ebeveynlere de ulaşabilirsiniz HEAD. Nesiller arasında da geri gidebilirsiniz: örneğin, master~2ana dalın ucunun büyükanne veya büyükbaba anlamına gelir ve birleştirme taahhütlerinde ilk ebeveyni tercih eder.

Düzeltme işareti

Git geçmişi doğrusal değildir: yönlendirilmiş bir asiklik grafik (DAG) veya ağaç. Sadece bir ebeveyne bağlılık rev~ve rev^aynı şey demek. Caret seçici, birleştirme taahhütlerinde faydalı olur, çünkü her biri iki veya daha fazla ebeveynin çocuğudur - ve biyolojiden ödünç alınan dili zorlar.

HEAD^mevcut dalın ucunun ilk yakın ebeveyni anlamına gelir . HEAD^için kısadır HEAD^1ve ayrıca HEAD^2uygun şekilde adresleme vb. de yapabilirsiniz . Aynı kesiti git rev-parsebelgeleri olarak tanımlar

<rev>^, Örneğin HEAD^ ,v1.5.1^0
bir son ek ^bir düzeltme parametresine nesne işlemek bu ilk üst anlamına gelir. ^<n>anlamına gelir , n inci üst ([ örn ] <rev>^eşdeğerdir <rev>^1). Özel bir kural olarak, <rev>^0komutun kendisi <rev>anlamına gelir ve bir bitiş nesnesine başvuran bir etiket nesnesinin nesne adı olduğunda kullanılır .

Örnekler

Bu belirticilere veya seçiciler, keyfi olarak zincirleme edilebilir örneğin , topic~3^2İngiliz birleştirme ikinci üstüdür o (üç kuşak geriye) şubesi akım ucu büyük-büyükbaba olduğunu taahhüt topic.

Yukarıda bahsedilen bölüm git rev-parsebelgelerinde bir kavramsal git tarih boyunca birçok yolları izler. Zaman genellikle aşağı doğru akar. D, F, B ve A komisyonları birleştirme komisyonlarıdır.

İşte Jon Loeliger'den bir örnek. Hem B hem de C düğümleri A düğümünün A ebeveynleridir. Üst taahhütler soldan sağa doğru sıralanır.

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

Geçmişi alıntılanan çizimle eşleşen bir git deposu oluşturmak için aşağıdaki kodu çalıştırın.

#! /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'";

Yeni atılabilir depoya takma adlar ekler git lolvegit lola böylece geçmişi olduğu gibi görüntüleyebilirsiniz

$ 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

Makinenizde SHA-1 nesne adlarının yukarıdakilerden farklı olacağını, ancak etiketlerin taahhütleri ada göre ele almanızı ve anlayışınızı kontrol etmenizi sağladığını unutmayın.

$ 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

İçinde “belirtme Düzeltmeler” git rev-parsedokümantasyon büyük bilgi dolu ve değer derinlemesine bir okuma. Ayrıca bkz. Git Araçları - Pro Git kitabından Revizyon Seçimi .

Ana Taahhüt Sırası

Taahhüt 89e4fcb0dd olarak, git kendi geçmişinden bir birleştirme taahhüt olduğunu git show 89e4fcb0ddBirleştirme başlık satırından bu görüntüler hemen atalarının nesne adları ile gösterir.

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-parse89e4fcb0dd'nin anında ebeveynlerini sırayla göstermesini isteyerek siparişi onaylayabiliriz .

$ git rev-parse 89e4fcb0dd^1 89e4fcb0dd^2 89e4fcb0dd^3
c670b1f876521c9f7cd40184bf7ed05aad843433
649bf3a42f344e71b1b5a7f562576f911a1f7423
b67d40adbbaf4f5c4898001bf062a9fd67e43368

Var olmayan dördüncü üst öğeyi sorgulamak bir hatayla sonuçlanır.

$ 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>...]'

Yalnızca ebeveynleri ayıklamak istiyorsanız , tam karmalar için güzel format kullanın%P

$ git log -1 --pretty=%P 89e4fcb0dd
c670b1f876521c9f7cd40184bf7ed05aad843433 649bf3a42f344e71b1b5a7f562576f911a1f7423 b67d40adbbaf4f5c4898001bf062a9fd67e43368

veya %pkısaltılmış ebeveynler için.

$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb

^ tüm davaları halledebilir ve neden ~ ~ ilk başta ortaya çıktı merak edebilirsiniz. Neden sadece ^ nasıl çalıştığını hatırlamıyorsunuz?
Sbu

bu hala kafa karıştırıcı ... G'nin HEAD olduğunu varsayarsak, eğer bir HEAD ^ yaparsam bu D ... olur mu?
Patoshi パ ト シ

12
@duckx grafik aslında yukarıdan aşağıya doğru gidiyor, bu yüzden A en son taahhüt ve G en eskilerinden biridir. G'den D'ye giden yol, geriye doğru değil, söyleyebileceğimden ileri doğru.
goldenratio

@SimonBudin Sanırım, bunun ^^^^^^^yerine kullanmak çok uygun değil ~7, değil mi? Bu yüzden ~faydalıdır
YakovL

1
@AdityaVikasDevarapalli Bu kendi sorusu kadar iyi olurdu.
Greg Bacon

340

Http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html adresinde bulunan resim (Jon Loeliger tarafından) arasındaki fark HEAD^ve HEAD~iyi tanımlanmıştır .

Bu dokümantasyon yeni başlayanlar için biraz belirsiz olabilir, bu yüzden aşağıdaki çizimi yeniden oluşturdum:

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

12
Sadece bir soru. Bir taahhüdün ikiden fazla ebeveyne sahip olması nasıl mümkün olabilir? (Bkz. B - ebeveynler D, E ve F) Bir taahhüdün iki ebeveyne sahip olabilmesinin tek yolunun birleştirme taahhüdü olduğu ... ama aynı anda 3 taahhüdü nasıl birleştirebilirsiniz?
tsikov

Yanılmıyorsam, bu açık olabilir, ancak bence HEAD ~ 'nin mevcut dalı takip ettiği belirtilmelidir (Diego Dias gibi aşağıda belirtildiği gibi).
fibono

2
Ayrıca F = A^2^,.
Mateen Ulhaq

2
Yani, ^ == ^1 == LEFTMOST PARENT, ^2 == SECOND LEFTMOST PARENTileri böylece. Ve ~ == ~1 == LEFTMOST PARENT, ~2 == LEFTMOST PARENTS LEFTMOST PARENT == LEFTMOST GRANDPARENT. ~2^2 == LEFTMOST GRANDPARENTS SECOND LEFTMOST PARENT
Uzantıyla

1
@AlexanderTorstling bu benim için çok yararlı oldu. Ancak, sol ve sağ burada ne anlama geliyor?
polynomial_donut

287

Her ikisi de ~ve ^kendi başlarına taahhütlerin ebeveyni ( ~~ve ^^her ikisi de büyükbaba veya büyükanne taahhütleri vb. Anlamına gelir).

  • ~2bir taahhüt birden fazla ebeveyne sahipse ilk veli aracılığıyla hiyerarşide iki seviye anlamına gelir

  • ^2bir taahhüdün birden fazla ebeveyne sahip olduğu ikinci ebeveyni ifade eder (bir birleşim olduğu için)

Bunlar birleştirilebilir, yani büyükbaba veya büyükanne taahhütünün üçüncü ebeveyn taahhüdü HEAD~2^3anlamına gelir HEAD.


2
Bunu okumak ve ardından stackoverflow.com/questions/2221658/… adresinden gelen resim mükemmel bir anlam ifade etti.
kunigami

23
Bu kabul edilen cevap, diğerlerinden çok daha özlü ve yararlı olmalıdır.
Mart'ta RichVel

3
Bu cevap beni numarasız işaretle işaretle ayırmayı sağladı! Benimle ^^aynı olduğunu düşündüm ^2ama değil.
Alexander Derck

278

Benim görüşüm...

resim açıklamasını buraya girin


Nasıl H=A~2^2olmaz H=A~2^1?
Mohammad Faisal

3
Doğru anladım olsaydı, kaydedilmesini A, B, D, Gaynı dal üzerinde olup taahhüt Dbir birleştirme olduğunu Gve Hbu nedenle iki aileye sahip. Yani Hdiğer daldan gelen commit ( ) tarafından referans alınır ^2.
Mohammad Faisal

62

İşte http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde adresinden kelimesi kelimesine alınmış çok iyi bir açıklama :

ref~kısaltmasıdır ref~1ve taahhüdün ilk ebeveyni anlamına gelir. ref~2Taahhüdün ilk ebeveyninin ilk ebeveyni anlamına gelir. ref~3, söz konusu taahhüdün ilk ebeveyninin ilk ebeveyninin ilk ebeveynidir. Ve bunun gibi.

ref^kısaltmasıdır ref^1ve taahhüdün ilk ebeveyni anlamına gelir. Ancak bu ikisinin farklı olduğu durumlarda, bu ref^2, taahhüdün ikinci ebeveyni anlamına gelir (hatırlayın, birleştirme sırasında iki ebeveyne sahip olabilir).

^Ve ~operatörler birleştirilebilir.

resim açıklamasını buraya girin


5
Bir dizi örnek göndermek yerine farklılıkları açıkladığınız için teşekkür ederiz.
Kirk Broadhurst

32

^<n>Biçimi taahhüt n'inci ebeveyne (birleştirme ilgili) seçmenize olanak sağlar. ~<n>Biçimi n'inci seçmek atası her zaman ilk ebeveyn aşağıdaki işlemeye izin verir. Bkz git-rev-ayrıştırma bazı örnekler için s' belgelerine.


21

Git'in aynı zamanda "nereden geldiğini" / "şimdi geri gitmek istiyorum" u izlemek için bir sözdizimine sahip olduğunu belirtmek gerekir HEAD@{1}.

Temel olarak HEAD@{}değişkenler HEAD hareketinin geçmişini yakalar ve komutu kullanarak git reflekslerine bakarak belirli bir kafa kullanmaya karar verebilirsiniz git reflog.

Misal:

0aee51f HEAD@{0}: reset: moving to HEAD@{5}
290e035 HEAD@{1}: reset: moving to HEAD@{7}
0aee51f HEAD@{2}: reset: moving to HEAD@{3}
290e035 HEAD@{3}: reset: moving to HEAD@{3}
9e77426 HEAD@{4}: reset: moving to HEAD@{3}
290e035 HEAD@{5}: reset: moving to HEAD@{3}
0aee51f HEAD@{6}: reset: moving to HEAD@{3}
290e035 HEAD@{7}: reset: moving to HEAD@{3}
9e77426 HEAD@{8}: reset: moving to HEAD@{3}
290e035 HEAD@{9}: reset: moving to HEAD@{1}
0aee51f HEAD@{10}: reset: moving to HEAD@{4}
290e035 HEAD@{11}: reset: moving to HEAD^
9e77426 HEAD@{12}: reset: moving to HEAD^
eb48179 HEAD@{13}: reset: moving to HEAD~
f916d93 HEAD@{14}: reset: moving to HEAD~
0aee51f HEAD@{15}: reset: moving to HEAD@{5}
f19fd9b HEAD@{16}: reset: moving to HEAD~1
290e035 HEAD@{17}: reset: moving to HEAD~2
eb48179 HEAD@{18}: reset: moving to HEAD~2
0aee51f HEAD@{19}: reset: moving to HEAD@{5}
eb48179 HEAD@{20}: reset: moving to HEAD~2
0aee51f HEAD@{21}: reset: moving to HEAD@{1}
f916d93 HEAD@{22}: reset: moving to HEAD@{1}
0aee51f HEAD@{23}: reset: moving to HEAD@{1}
f916d93 HEAD@{24}: reset: moving to HEAD^
0aee51f HEAD@{25}: commit (amend): 3rd commmit
35a7332 HEAD@{26}: checkout: moving from temp2_new_br to temp2_new_br
35a7332 HEAD@{27}: commit (amend): 3rd commmit
72c0be8 HEAD@{28}: commit (amend): 3rd commmit

Bir örnek yerel aits> a-> b-> c-> d yaptım ve sonra kodumu kontrol etmek için 2 komisyon atarak geri döndüm git reset HEAD~2- ve daha sonra KAFA d geri taşımak istiyorum git reset HEAD@{1}.


17

Basitçe :

  • ~ ataları belirtir
  • ^ ebeveynleri belirtir

Birleştirirken bir veya daha fazla dal belirleyebilirsiniz. Daha sonra bir taahhüt iki veya daha fazla ebeveyne sahiptir ve daha sonra ^ebeveyni belirtmek için faydalıdır.

Eğer dal üzerinde olduğunu varsayalım A : ve iki tane daha şubeleri var B ve C .

Her dalda son üç taahhüt:

  • A : A1 , A2 , A3
  • B : B1 , B2 , B3
  • C : C1 , C3 , C3

Şimdi A dalındaysanız şu komutu uygularsınız :

git merge B C

o zaman üç dalı birleştiriyorsunuz (burada birleştirme taahhüdünüzün üç ebeveyni var)

ve

~ ilk daldaki n. atayı belirtir, yani

  • HEAD~A3'ü gösterir
  • HEAD~2A2'yi gösterir
  • HEAD~3A1'i gösterir

^ n'inci ebeveyni belirtir.

  • HEAD^A3'ü gösterir
  • HEAD^2B3'ü gösterir
  • HEAD^3C3'ü belirtir

Bir sonraki ~ya da ^yan yana bir sonraki kullanım, önceki karakterlerin belirlediği taahhüt bağlamındadır.

Bildirim 1 :

  • HEAD~3her zaman eşittir: HEAD~~~ve: HEAD^^^(her biri A1'i gösterir ),

        ve genellikle :

  • HEAD~nher zaman eşittir: HEAD~...~( n kez ~) ve: HEAD^...^( n kez ^).

Bildirim 2 :

  • HEAD^3ile aynı değildirHEAD^^^ (ilki C3'ü , ikincisi A1'i gösterir ),

        ve genellikle :

  • HEAD^1ile aynı HEAD^,
  • ancak n > 1 için: HEAD^nher zaman ( n kez ) ile aynı değildir .HEAD^...^~

15

TLDR

~ çoğu zaman istediğiniz şeydir, geçmiş taahhütleri mevcut şubeye yönlendirir

^ ebeveynlere referanslar (git-merge 2. veya daha fazla ebeveyn oluşturur)

A ~ her zaman A ^
A ~~ ile aynıdır ve her zaman A ^^ ile aynıdır ve bu nedenle
A ~ 2 A ^ 2 ile aynı değildir,
çünkü ~ 2 ~ ~ için kısaysa
^ ^ değil her şey için kısayol, 2. ebeveyn demektir


11

HEAD ^^^ HEAD ~ 3 ile aynıdır, HEAD öncesi üçüncü taahhüdü seçer

HEAD ^ 2, bir birleştirme işlemindeki ikinci başı belirtir


9
  • HEAD ~ bir "dalda" ilk üst öğeyi belirtir

  • HEAD ^, taahhüdün belirli bir üst öğesini seçmenize olanak tanır

Bir örnek:

Bir yan dalı takip etmek istiyorsanız, aşağıdaki gibi bir şey belirtmeniz gerekir

master~209^2~15


0

Basitçe, birinci ebeveynlik düzeyi için (soy, miras, soy, vb.) HEAD ^ ve HEAD ~ her ikisi de HEAD'in (taahhüt) bir ebeveyni (taahhüt) üzerinde bulunan aynı taahhüdü işaret eder.

Ayrıca, HEAD ^ = HEAD ^ 1 = HEAD ~ = HEAD ~ 1. Ancak HEAD ^^! = HEAD ^ 2! = HEAD ~ 2. Yine de HEAD ^^ = HEAD ~ 2. Okumaya devam etmek.

Birinci ebeveynlik seviyesinin ötesinde, özellikle çalışma dalı / ana dalda (diğer dallardan) birleşmeler varsa işler daha da karmaşıklaşır. Ayrıca, şapka ile sözdizimi de vardır, HEAD ^^ = HEAD ~ 2 (eşdeğerler) AMA HEAD ^^! = HEAD ^ 2 (tamamen iki farklı şeydir).

Her bir / caret, HEAD'in ilk ebeveyni anlamına gelir; bu nedenle, birlikte dizilen caretler tilde ifadelerine eşdeğerdir, çünkü ilk olarak ebeveynlerin (ilk ebeveyn) ilk ebeveynleri vb. veya yaklaşık işareti izleyen sayıda (her iki şekilde de, her ikisi de aynı anlama gelir), yani ilk ebeveynle kal ve x nesillere çık.

HEAD ~ 2 (veya HEAD ^^), hiyerarşideki mevcut taahhüdün (HEAD) iki üst düzey atalarının üstesinden geldiği anlamına gelir;

Öte yandan HEAD ^ 2, ilk ebeveynin ikinci ebeveyninin taahhüdünü değil, sadece ikinci ebeveynin taahhüdünü ifade eder. Bunun nedeni, caret işleminin üst öğesi anlamına gelmesidir ve aşağıdaki sayı, hangi üst öğenin hangi / hangi iletime atıfta bulunduğunu belirtir (ilk üst öğe, satırın bir sayı izlememesi durumunda [numara için kısayol olduğu için) 1, ilk ebeveyn anlamına gelir]). Düzeltme işaretinden farklı olarak, daha sonra gelen sayı yukarı doğru başka bir hiyerarşi düzeyi anlamına gelmez, bunun yerine hiyerarşiye doğru kaç düzey yan yana olduğunu, doğru ebeveyni (taahhüdü) bulmayı gerektirir. Bir tilde ifadesindeki sayıdan farklı olarak, düzeltme işlemini gerçekleştiren numaradan (hemen) bağımsız olarak, hiyerarşide yalnızca bir üst öğedir. Yukarı doğru yerine, düzeltme işareti '

Bu yüzden HEAD ^ 3, HEAD taahhüdünün üçüncü ebeveyne eşittir (HEAD ^ ^ ^ VE HEAD ~ 3'ün ne olacağı büyük büyükbaba veya büyükanne DEĞİLDİR ...).


-1

~ bu ebeveyn demektir.

^ Birleştirme taahhüdü gibi iki veya daha fazla ebeveynleri varsa, ebeveyn veya ikincisini seçebiliriz.

yani (HEAD ~ veya HEAD ^) gibi bir şey varsa, aynı sonuçları verir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.