Apa perbedaan antara HEAD ^ dan HEAD ~ di Git?

756

Ketika saya menentukan objek commit leluhur di Git, saya bingung antara HEAD^dan HEAD~.

Keduanya memiliki versi "bernomor" seperti HEAD^3dan HEAD~2.

Mereka tampak sangat mirip atau sama dengan saya, tetapi apakah ada perbedaan antara tilde dan caret?

TK.
sumber
64
itu buruk untuk menyisipkan tautan, saya tahu tetapi ini adalah penjelasan terbaik yang saya temukan dan ada gambar di dalamnya. paulboxley.com/blog/2011/06/git-caret-and-tilde
igor
4
Tautan sangat buruk saat rusak. Itulah alasan mengapa lebih aman untuk menjawab pertanyaan yang membantu mencegah hal ini karena kemampuan untuk menyalin menempel beberapa penjelasan :)
Samuel

Jawaban:

763

Aturan praktis

  • Gunakan ~sebagian besar waktu - untuk kembali ke beberapa generasi, biasanya apa yang Anda inginkan
  • Gunakan ^komitmen gabungan - karena mereka memiliki dua orang tua (langsung) atau lebih

Ilmu tentang cara menghafal:

  • Tilde ~hampir linear dalam penampilan dan ingin mundur dalam garis lurus
  • Caret ^menyarankan segmen yang menarik dari pohon atau garpu di jalan

Tilde

Bagian “Menentukan Revisi” dari git rev-parsedokumentasi ini didefinisikan ~sebagai

<rev>~<n>, Misalnyamaster~3
A akhiran ~<n>ke parameter revisi berarti komit objek yang adalah n th nenek moyang generasi bernama komit objek, berikut hanya orang tua pertama. Misalnya, <rev>~3setara dengan <rev>^^^yang setara dengan <rev>^1^1^1...

Anda dapat menjangkau orang tua dari komitmen apa pun, bukan hanya HEAD. Anda juga dapat bergerak turun-temurun: misalnya, master~2berarti kakek dari ujung cabang master, lebih menyukai orangtua pertama yang menggabungkan komitmen.

Tanda sisipan

Sejarah Git adalah nonlinier: grafik asiklik terarah (DAG) atau pohon. Untuk komit dengan hanya satu orangtua, rev~dan rev^berarti hal yang sama. Selektor tanda kuret menjadi berguna dengan menggabungkan komitmen karena masing-masing adalah anak dari dua atau lebih orang tua - dan bahasa yang dipinjam dari biologi.

HEAD^berarti induk langsung pertama dari ujung cabang saat ini. HEAD^kependekan dari HEAD^1, dan Anda juga bisa mengatasinya HEAD^2dan seterusnya sesuai kebutuhan. Bagian yang sama dari git rev-parsedokumentasi mendefinisikannya sebagai

<rev>^, misalnya HEAD^ ,v1.5.1^0
sufiks ^ke parameter revisi berarti induk pertama dari objek komit tersebut. ^<n>berarti orang tua ke- n ([ misalnya ] setara dengan ). Sebagai aturan khusus, berarti komit itu sendiri dan digunakan ketika adalah nama objek dari objek tag yang merujuk ke objek komit.<rev>^<rev>^1<rev>^0<rev>

Contohnya

Penentu atau penyeleksi ini dapat dirantai secara sewenang-wenang, misalnya , topic~3^2dalam bahasa Inggris adalah induk kedua dari komit gabungan yang merupakan kakek-nenek buyut (tiga generasi ke belakang) dari ujung cabang saat ini topic.

Bagian git rev-parsedokumentasi yang disebutkan di atas melacak banyak jalur melalui sejarah git nosional. Waktu mengalir secara umum ke bawah. Komit D, F, B, dan A adalah gabungan komit.

Ini sebuah ilustrasi, karya Jon Loeliger. Kedua node komit B dan C adalah orang tua dari node komit A. Komit induk diperintahkan dari kiri ke kanan.

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

Jalankan kode di bawah ini untuk membuat repositori git yang sejarahnya cocok dengan ilustrasi yang dikutip.

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

Itu menambahkan alias di repo sekali pakai baru hanya untuk git loldangit lola sehingga Anda dapat melihat riwayat seperti di

$ 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

Perhatikan bahwa pada mesin Anda, nama objek SHA-1 akan berbeda dari yang di atas, tetapi tag memungkinkan Anda untuk mengatasi komit dengan nama dan memeriksa pemahaman Anda.

$ 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 “Menentukan Revisi” di git rev-parsedokumentasi penuh dengan informasi yang besar dan bernilai dibaca mendalam. Lihat juga Alat Git - Pilihan Revisi dari buku Pro Git .

Perintah Orangtua Berkomitmen

Komit 89e4fcb0dd dari sejarah git sendiri adalah gabungan komit, seperti yang git show 89e4fcb0ddditunjukkan dengan baris header Gabung yang menampilkan nama objek leluhur langsung.

commit 89e4fcb0dd01b42e82b8f27f9a575111a26844df
Merge: c670b1f876 649bf3a42f b67d40adbb
Author: Junio C Hamano <[email protected]>
Date:   Mon Oct 29 10:15:31 2018 +0900

    Merge branches 'bp/reset-quiet' and 'js/mingw-http-ssl' into nd/config-split […]

Kami dapat mengonfirmasi pemesanan dengan meminta git rev-parsemenunjukkan orang tua langsung 89e4fcb0dd secara berurutan.

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

Meminta orang tua keempat yang tidak ada menghasilkan kesalahan.

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

Jika Anda ingin mengekstrak orang tua saja, gunakan format cantik %P untuk hash lengkap

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

atau %puntuk orang tua pendek.

$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb
Greg Bacon
sumber
tampaknya ^ dapat menangani semua kasus dan orang dapat bertanya-tanya mengapa ~ muncul di tempat pertama. Mengapa tidak hanya mengingat cara kerjanya?
Sbu
ini masih sangat membingungkan ... anggap G adalah HEAD, jadi jika saya melakukan HEAD ^ itu akan menjadi D ... kan?
Patoshi パ ト シ
12
@duckx grafik sebenarnya dari atas ke bawah, jadi A adalah komit terbaru, dan G adalah salah satu yang tertua. Jalan dari G ke D adalah ke depan, bukan ke belakang, dari apa yang bisa saya katakan.
goldenratio
@SimonBudin Saya kira, tidak nyaman untuk digunakan, ^^^^^^^bukan ~7? Itu sebabnya ~berguna
YakovL
1
@AdityaVikasDevarapalli Itu akan menjadi pertanyaan tersendiri.
Greg Bacon
340

Perbedaan antara HEAD^dan HEAD~dijelaskan dengan baik oleh ilustrasi (oleh Jon Loeliger) ditemukan di http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html .

Dokumentasi ini bisa sedikit tidak jelas bagi pemula jadi saya telah mereproduksi ilustrasi di bawah ini:

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
g_fred
sumber
12
Hanya satu pertanyaan. Bagaimana mungkin suatu komitmen memiliki lebih dari dua orang tua? (Lihat B - orang tuanya adalah D, E dan F) Saya membayangkan bahwa satu-satunya cara komit dapat memiliki dua orang tua adalah ketika komit gabungan ... tetapi bagaimana Anda bisa menggabungkan 3 komit pada saat yang sama?
tsikov
Jika saya tidak salah, ini mungkin jelas, tetapi saya pikir harus ditentukan bahwa HEAD ~ mengikuti cabang saat ini (seperti Diego Dias yang disebutkan di bawah).
fibono
2
Selain itu F = A^2^,.
Mateen Ulhaq
2
Jadi, ^ == ^1 == LEFTMOST PARENT, ^2 == SECOND LEFTMOST PARENTdan sebagainya. Dan ~ == ~1 == LEFTMOST PARENT, ~2 == LEFTMOST PARENTS LEFTMOST PARENT == LEFTMOST GRANDPARENT. Dengan ekstensi,~2^2 == LEFTMOST GRANDPARENTS SECOND LEFTMOST PARENT
Alexander Torstling
1
@AlexanderTorstling ini sangat membantu saya. Namun, apa artinya kiri dan kanan di sini?
polynomial_donut
287

Keduanya ~dan ^sendiri mengacu pada orang tua dari komit ( ~~dan ^^keduanya merujuk pada komit kakek-nenek, dll.) Tetapi mereka berbeda artinya ketika mereka digunakan dengan angka:

  • ~2berarti naik dua tingkat dalam hierarki , melalui induk pertama jika komit memiliki lebih dari satu orangtua

  • ^2berarti induk kedua di mana komit memiliki lebih dari satu orangtua (yaitu karena gabungan)

Ini dapat digabungkan, jadi itu HEAD~2^3berarti HEADkomit ketiga kakek nenek.

Matthew Strawbridge
sumber
2
Membaca ini diikuti oleh gambar dari stackoverflow.com/questions/2221658/… masuk akal.
kunigami
23
Ini harus menjadi jawaban yang diterima, jauh lebih ringkas dan bermanfaat daripada yang lain.
RichVel
3
Jawaban ini membuat saya membedakan antara caret / tilde tanpa angka dan dengan angka! Saya pikir ^^itu sama ^2tetapi tidak.
Alexander Derck
278

Dua sen saya ...

masukkan deskripsi gambar di sini

Alex Janzik
sumber
Dan bagaimana H=A~2^2tidak H=A~2^1?
Mohammad Faisal
3
Jika saya telah menemukan jawabannya benar, komit A, B, D, Gberada di cabang yang sama dan komit Dadalah gabungan dari Gdan H, oleh karena itu memiliki dua orang tua. Jadi komit ( H) dari cabang lain adalah referensi oleh ^2.
Mohammad Faisal
62

Berikut ini penjelasan yang sangat baik yang diambil secara verbatim dari http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde :

ref~adalah singkatan untuk ref~1dan berarti orang tua pertama dari komit. ref~2berarti orang tua pertama dari orang tua komit. ref~3berarti orang tua pertama dari orang tua pertama dari komit. Dan seterusnya.

ref^adalah singkatan untuk ref^1dan berarti orang tua pertama dari komit. Tetapi di mana keduanya berbeda adalah itu ref^2berarti orang tua kedua komit (ingat, komit dapat memiliki dua orang tua ketika mereka bergabung).

The ^dan ~operator dapat dikombinasikan.

masukkan deskripsi gambar di sini

dr_
sumber
5
Terima kasih karena telah benar-benar menjelaskan perbedaan daripada memposting sejumlah contoh.
Kirk Broadhurst
32

The ^<n>Format memungkinkan Anda untuk memilih orang tua n dari komit (relevan dalam penggabungan). The ~<n>Format memungkinkan Anda untuk memilih n nenek moyang komit, selalu mengikuti orangtua pertama. Lihat dokumentasi git-rev-parse untuk beberapa contoh.

jamessan
sumber
21

Perlu dicatat bahwa git juga memiliki sintaks untuk melacak "dari-mana-Anda-datang" / "ingin-untuk-kembali-sekarang" - misalnya, HEAD@{1} akan merujuk tempat dari mana Anda melompat ke lokasi komit baru.

Pada dasarnya HEAD@{}variabel menangkap sejarah pergerakan HEAD, dan Anda dapat memutuskan untuk menggunakan head tertentu dengan melihat reflog git menggunakan perintah git reflog.

Contoh:

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

Contohnya adalah saya melakukan local-commit a-> b-> c-> d dan kemudian saya kembali membuang 2 commit untuk memeriksa kode saya - git reset HEAD~2- dan kemudian setelah itu saya ingin memindahkan HEAD saya kembali ke d - git reset HEAD@{1}.

abu
sumber
17

Secara sederhana :

  • ~ menentukan leluhur
  • ^ menentukan orang tua

Anda dapat menentukan satu atau beberapa cabang saat penggabungan. Kemudian komit memiliki dua atau lebih orangtua dan kemudian^ berguna untuk menunjukkan orang tua.

Misalkan Anda berada di cabang A dan Anda memiliki dua cabang lagi: B dan C .

Di setiap cabang, tiga komitmen terakhir adalah:

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

Jika sekarang di cabang A Anda menjalankan perintah:

git merge B C

maka Anda menggabungkan tiga cabang bersama (di sini gabungan Anda memiliki tiga orang tua)

dan

~ menunjukkan leluhur ke-9 di cabang pertama, jadi

  • HEAD~menunjukkan A3
  • HEAD~2menunjukkan A2
  • HEAD~3menunjukkan A1

^ menunjukkan induk ke-n, jadi

  • HEAD^menunjukkan A3
  • HEAD^2menunjukkan B3
  • HEAD^3menunjukkan C3

Penggunaan selanjutnya dari ~atau^ samping satu sama lain adalah dalam konteks komit yang ditunjuk oleh karakter sebelumnya.

Perhatikan 1 :

  • HEAD~3selalu sama dengan: HEAD~~~dan untuk: HEAD^^^(setiap menunjukkan A1 ),

        dan umumnya :

  • HEAD~nselalu sama dengan: HEAD~...~( n kali ~) dan untuk: HEAD^...^( n kali ^).

Pemberitahuan 2 :

  • HEAD^3adalah tidak sama dengan HEAD^^^(yang pertama menunjukkan C3 dan yang kedua menunjukkan A1 ),

        dan umumnya :

  • HEAD^1sama dengan HEAD^,
  • tetapi untuk n > 1: HEAD^nselalu tidak sama dengan HEAD^...^( n kali ~).
simhumileco
sumber
15

TLDR

~ adalah apa yang paling Anda inginkan, itu merujuk komit masa lalu ke cabang saat ini

^ referensi orang tua (git-merge menciptakan orangtua kedua atau lebih)

A ~ selalu sama dengan A ^
A ~~ selalu sama dengan A ^^, dan seterusnya
A ~ 2 tidak sama dengan A ^ 2,
karena ~ 2 adalah singkatan untuk ~~
sedangkan ^ 2 tidak singkatan untuk apa pun, itu artinya orangtua kedua

WeakPointer
sumber
11

HEAD ^^^ sama dengan HEAD ~ 3, memilih komit ketiga sebelum HEAD

KEPALA ^ 2 menentukan kepala kedua dalam komit gabungan

rajutan
sumber
9
  • KEPALA ~ menentukan orang tua pertama pada "cabang"

  • HEAD ^ memungkinkan Anda untuk memilih induk spesifik dari komit

Sebuah contoh:

Jika Anda ingin mengikuti cabang samping, Anda harus menentukan sesuatu seperti

master~209^2~15
Diego Dias
sumber
5

contoh aktual perbedaan antara HEAD ~ dan HEAD ^

KEPALA ^ VS KEPALA ~

Anas Alpure
sumber
0

Sederhananya, untuk level pertama dari keturunan (keturunan, warisan, garis keturunan, dll.) KEPALA ^ dan KEPALA ~ keduanya menunjuk ke komit yang sama, yaitu (terletak) satu orangtua di atas KEPALA (komit).

Selanjutnya, KEPALA ^ = KEPALA ^ 1 = KEPALA ~ = KEPALA ~ 1. Tapi KEPALA ^^! = KEPALA ^ 2! = KEPALA ~ 2. Namun KEPALA ^^ = KEPALA ~ 2. Baca terus.

Di luar tingkat pertama dari keturunan, hal menjadi lebih rumit, terutama jika cabang kerja / cabang master telah memiliki penggabungan (dari cabang lain). Ada juga masalah sintaksis dengan tanda sisipan, KEPALA ^^ = KEPALA ~ 2 (mereka setara) TETAPI KEPALA ^^! = KEPALA ^ 2 (mereka dua hal yang berbeda sama sekali).

Setiap / tanda sisipan mengacu pada orang tua pertama KEPALA, oleh karena itulah tanda kurung yang dirangkai sama dengan ekspresi tilde, karena mereka mengacu pada orang tua pertama orang tua (orang tua pertama), dll., Dll. Berdasarkan ketat pada nomor pada carets yang terhubung atau pada nomor yang mengikuti tilde (keduanya, keduanya berarti hal yang sama), yaitu tetap dengan orangtua pertama dan naik x generasi.

KEPALA ~ 2 (atau KEPALA ^^) mengacu pada komit yang merupakan dua tingkat leluhur di atas / di atas komit saat ini (KEPALA) dalam hierarki, yang berarti komit kakek nenek HEAD.

KEPALA ^ 2, di sisi lain, TIDAK mengacu pada komit orang tua kedua dari orang tua pertama, tetapi hanya untuk komit orang tua kedua. Itu karena tanda sisipan berarti induk dari komit, dan angka berikut menandakan yang / apa yang dilakukan orangtua komit (orangtua pertama, dalam kasus ketika tanda sisipan tidak diikuti oleh angka [karena itu adalah singkatan untuk nomor menjadi 1, artinya orang tua pertama]). Berbeda dengan tanda sisipan, angka yang mengikutinya tidak menyiratkan tingkat hierarki lain ke atas, tetapi lebih menyiratkan berapa banyak level menyamping, ke dalam hierarki, seseorang harus mencari orang tua yang benar (komit). Berbeda dengan angka dalam ekspresi tilde, itu hanya satu induk di hierarki, terlepas dari nomor (segera) melanjutkan tanda sisipan. Alih-alih ke atas, tanda sisipan '

Jadi KEPALA ^ 3 sama dengan orang tua ketiga dari komit KEPALA (BUKAN kakek buyut, yang adalah KEPALA ^^^ DAN KEPALA ~ 3 akan menjadi ...).

Sean Tank Garvey
sumber
-1

~ ini berarti orang tua.

^ jika memiliki orang tua dari dua atau lebih, seperti menggabungkan komit, kita dapat memilih yang kedua dari orang tua atau yang lain.

jadi jika hanya satu hal seperti (HEAD ~ atau HEAD ^), ia memiliki hasil yang sama .

Margaux
sumber