Menggunakan Git, tunjukkan semua komit yang ada * hanya * pada satu cabang tertentu, dan bukan * satu * lainnya

87

Diberikan sebuah cabang, saya ingin melihat daftar komit yang hanya ada di cabang itu. Dalam pertanyaan ini kita membahas cara untuk melihat komit mana yang ada di satu cabang tetapi tidak di satu atau lebih cabang lain yang ditentukan.

Ini sedikit berbeda. Saya ingin melihat yang melakukan adalah pada satu cabang tetapi tidak pada setiap cabang lain.

Kasus penggunaan adalah dalam strategi percabangan di mana beberapa cabang hanya boleh digabungkan, dan tidak pernah diterapkan secara langsung. Ini akan digunakan untuk memeriksa apakah ada komit yang telah dibuat secara langsung di cabang "hanya gabungan".

EDIT: Berikut adalah langkah-langkah untuk menyiapkan repo git tiruan untuk diuji:

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

Hanya komit dengan pesan "komit buruk langsung di hanya gabungan", yang dibuat langsung di cabang khusus gabungan, yang akan muncul.

jimmyorr.dll
sumber
1
Pertanyaan ini menganggap semua cabang yang digabungkan dari saat ini tersedia di repo, tidak pernah dihapus setelah digabungkan sepenuhnya, dan mungkin tidak pernah digabungkan dengan fast-forward. Beri tahu saya jika saya melewatkan sesuatu, tetapi menurut saya ini hanya dapat diterapkan untuk sekumpulan kecil gabungan yang diizinkan dari cabang, jadi mengapa tidak menggunakan git log ^branch1 ^branch2 merge-only-branchsintaks saja?
Karl Bielefeldt
1
The git log ^branch1 ^branch2 merge-only-branchmemerlukan daftar keluar setiap cabang tunggal. Itu dapat dihindari dengan beberapa penggunaan bash / grep yang cerdik (lihat jawaban saya di bawah), tetapi saya berharap git memiliki dukungan bawaan untuk ini. Anda benar bahwa ini menganggap semua cabang merge-from adalah jarak jauh (hanya lokal dan tidak ada untuk pengembang lain). Menggunakan --no-mergesmenghilangkan setiap komit yang digabungkan dan kemudian memiliki cabang gabungan asli mereka dihapus, jadi ini mengasumsikan cabang gabungan dari disimpan sampai mereka telah digabungkan ke cabang non-gabungan-saja (yaitu master).
jimmyorr

Jawaban:

76

Kami baru saja menemukan solusi elegan ini

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

Dalam contoh Anda, tentu saja komit awal masih muncul.

jawaban ini tidak benar-benar menjawab pertanyaan, karena komit awal masih muncul. Di sisi lain, banyak orang yang datang ke sini sepertinya menemukan jawaban yang mereka cari.

wrtsprt
sumber
1
Karena komit awal pada master masih muncul, ini tidak menjawab pertanyaan.
jimmyorr
6
Ini saja tidak memenuhi kondisi "komit yang hanya ada di cabang itu" — ini menunjukkan initial valid commit, yang merupakan bagian dari cabang merge-onlydan master. Namun, jika seseorang melakukan upaya untuk memasukkan nama cabang saat ini di bagian akhir diikuti oleh ^ -nama cabang yang diawali dengan yang diketahui dari cabang saat ini, itu memecahkan setengah masalah (tidak termasuk hal-hal yang digabungkan). Contoh:git log --first-parent --no-merges merge-only ^master
Slipp D. Thompson
14
Saya tidak yakin mengapa ini banyak disukai, sepertinya tidak ada hubungannya dengan pertanyaan sama sekali. Jelas tidak memberikan informasi yang dicari oleh poster tersebut.
Chris Rasys
2
Jawaban ini mungkin tidak sempurna. Tapi itu sederhana dan pasti berhasil sampai batas tertentu. Saya merasa berguna untuk menambahkan nama cabang - yaitu memfilter semua komit milik cabang tertentu:git log --first-parent --no-merges | grep <branch_name>
artm
1
Terima kasih. Solusi terbaik imo.
Jakub Keller
29

Atas kebaikan teman saya 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)

... di mana origin/merge-onlynama cabang hanya gabungan jarak jauh Anda. Jika bekerja pada repo git khusus lokal, gantikan refs/remotes/origindengan refs/heads, dan gantikan nama cabang jarak jauh origin/merge-onlydengan nama cabang lokal merge-only, yaitu:

git log --no-merges merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/heads |
    grep -Fv refs/heads/merge-only)
jimmyorr.dll
sumber
2
Saya berharap orang lain dapat memberikan solusi tanpa grep hanya dengan menggunakan git, tetapi jika tidak, ini terasa cukup elegan.
jimmyorr
1
Ya, anggun. Gunakan git for-each-refuntuk membuat daftar setiap nama ref di asalnya, dan grep -vuntuk menghilangkan cabang hanya gabungan. git logmengambil --notopsi, yang kami berikan daftar semua referensi kami (kecuali cabang hanya-gabungan). Jika Anda memiliki jawaban yang lebih elegan untuk masalah ini, mari kita dengarkan.
jimmyorr
2
Oh, saya yakin itu jawaban yang paling elegan. Saya hanya berpendapat itu sedikit "bertele-tele / rumit" untuk keanggunan sejati. :-) Tidak bermaksud meremehkan pendekatan Anda, Pak!
Chris K
1
Perintah /*di belakangnya git for-each-refsbergantung pada tidak mencocokkan beberapa file yang ada dan tidak memiliki failglobatau nullglobmenyetel ( opsi bash , shell lain bervariasi). Anda harus mengutip / menghilangkan tanda bintang atau membiarkannya /*saja ( git for-each-refpola dapat cocok dengan "dari awal hingga garis miring"). Mungkin use grep -Fv refs/remotes/origin/foo( refs/heads/foo) untuk lebih ketat tentang ref mana yang dihilangkan.
Chris Johnsen
3
Ini dapat disederhanakan jika Anda hanya ingin melihat komit hadir di satu cabang dan tidak di cabang lain git log --no-merges B1 --not B2:, di mana B1 adalah cabang yang Anda minati, dan B2 adalah cabang yang ingin Anda bandingkan dengan B1. Baik B1 dan B2 dapat menjadi cabang lokal atau jarak jauh, sehingga Anda dapat menentukan git log --no-merges master --not origin/master, atau bahkan menentukan dua cabang jarak jauh.
mr.b
21
git log origin/dev..HEAD

Ini akan menunjukkan semua komit yang dibuat di cabang Anda.

Prakash
sumber
2
@Prakash origin/branchNameakan menunjuk ke kepala cabang jarak jauh DAN HEADakan menunjuk ke commitid dari komit lokal terakhir di cabang itu. Jadi ini tidak akan berfungsi jika Anda telah menggunakan git push.
Bharat
Anda dapat menggunakan ini untuk membandingkan cabang lokal lainnya. Flag --no-merges mungkin juga berguna untuk menjawab pertanyaan awal OP.
Paul Whipp
15

Jawaban @Prakash berhasil. Hanya untuk kejelasan ...

git checkout feature-branch
git log master..HEAD

mencantumkan komit di cabang fitur tetapi bukan cabang upstream (biasanya master Anda).

Bryan
sumber
12

Mungkin ini bisa membantu:

git show-branch

grzuy
sumber
2
Meskipun ini secara teoritis dapat menjawab pertanyaan, akan lebih baik jika menyertakan bagian penting dari jawaban di sini, dan menyediakan tautan untuk referensi.
Vladimir Panteleev
Ini sebenarnya cukup membantu. Lihat stackoverflow.com/a/7623339/874188 untuk contoh yang lebih terperinci dan beberapa jawaban terkait.
tripleee
7

Coba ini:

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

Pada dasarnya git rev-list --all ^branchmendapatkan semua revisi bukan di cabang dan kemudian Anda semua revisi di repo dan kurangi daftar sebelumnya yang hanya revisi di cabang.

Setelah komentar @ Brian:

Dari dokumentasi git rev-list:

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

Jadi perintah seperti di git rev-list Amana A adalah komit akan mencantumkan komitmen yang dapat dijangkau dari A termasuk A.

Dengan pemikiran seperti itu, sesuatu seperti

git rev-list --all ^A

akan mencantumkan komitmen yang tidak dapat dijangkau dari A

Begitu git rev-list --all ^branch akan mencantumkan semua komitmen yang tidak dapat dijangkau dari ujung cabang. Yang akan menghapus semua komit di cabang, atau dengan kata lain komit yang hanya ada di cabang lain.

Sekarang mari kita ke git rev-list --all --not $(git rev-list --all ^branch)

Ini akan menjadi seperti git rev-list --all --not {commits only in other branches}

Jadi kami ingin membuat daftar allyang tidak dapat dijangkau dariall commits only in other branches

Yang merupakan kumpulan komit yang hanya ada di cabang. Mari kita ambil contoh sederhana:

             master

             |

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

  \

   \

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

                      |

                      branch

Di sini tujuannya adalah untuk mendapatkan D dan E, komit bukan di cabang lain mana pun.

git rev-list --all ^branch berikan hanya B

Sekarang, git rev-list --all --not Binilah yang kita lihat. Yang juga git rev-list -all ^B- kami ingin semua komitmen tidak dapat dijangkau dari B. Dalam kasus kami, D dan E. Yang mana yang kami inginkan.

Semoga ini menjelaskan bagaimana perintah bekerja dengan benar.

Edit setelah komentar:

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"

Setelah langkah-langkah di atas, jika Anda melakukan, git rev-list --all --not $(git rev-list --all ^merge-only)Anda akan mendapatkan komit yang Anda cari - yang "bad commit directly on merge-only"satu.

Tetapi begitu Anda melakukan langkah terakhir dalam langkah Anda git merge master, perintah tidak akan memberikan hasil yang diharapkan. Karena saat ini tidak ada komit yang tidak ada di hanya-gabungan karena satu komit ekstra di master juga telah digabungkan menjadi hanya-gabungan. Jadi git rev-list --all ^branchmemberikan hasil kosong dan karenanya git rev-list -all --not $(git rev-list --all ^branch)akan memberikan semua komit hanya dalam bentuk gabungan.

manojlds
sumber
1
Hm ... tidak yakin kenapa, tapi ini tidak berhasil. Menyisipkan output perintah Anda untuk xargs -L 1 -t git branch -a --containsmenampilkan banyak positif palsu (komit yang sebenarnya ada di cabang lain). Saya mencoba dengan dan tanpa --no-merges. Terima kasih telah menjawabnya!
jimmyorr
Sepertinya bekerja dengan baik untuk saya sejauh yang saya bisa lihat di repo git tiruan.
manojlds
Saya telah menambahkan langkah-langkah untuk membuat repo git tiruan untuk membantu mendemonstrasikan masalah dengan jawaban Anda.
jimmyorr
Ah, ups. Upvoted ini sebelum saya memikirkannya sepenuhnya. git rev-list --all ^branchakan memberi Anda semua komitmen yang tidak ada branch. Anda kemudian menguranginya dari daftar yang ada di branch; tapi menurut definisi, semua komit yang tidak branchada tidak masuk branch, jadi Anda tidak mengurangi apa pun. Apa yang dicari jimmyorr adalah komit yang ada di dalam branchtetapi tidak ada master, atau cabang lainnya. Anda tidak ingin mengurangi komit yang tidak ada branch; Anda ingin mengurangi komit yang ada di cabang lain.
Brian Campbell
1
@manojlds "(semua revisi) - (semua revisi bukan di cabang) = revisi di cabang." Ya, itu berfungsi untuk memasukkan semua revisi branch, tetapi begitu juga git rev-list branch. Anda hanya menulis git rev-list branchdengan cara yang lebih rumit (dan lebih lambat). Tidak berfungsi untuk menjawab pertanyaan, yaitu bagaimana menemukan semua komit branch yang tidak ada di cabang lain .
Brian Campbell
2

Variasi lain dari jawaban yang diterima, untuk digunakan dengan master

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

Filter semua komit yang terjadi di cabang mana pun selain master.

JaimeJorge
sumber
1

Ini bukan jawaban yang sebenarnya, tetapi saya membutuhkan akses ke pemformatan, dan banyak ruang. Saya akan mencoba menjelaskan teori di balik apa yang saya anggap sebagai dua jawaban terbaik: jawaban yang diterima dan (setidaknya saat ini) peringkat teratas . Namun nyatanya, mereka menjawab pertanyaan yang berbeda .

Commit di Git sangat sering "di" lebih dari satu cabang pada satu waktu. Memang, sebagian besar pertanyaannya. Diberikan:

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

di mana huruf besar mewakili ID hash Git yang sebenarnya, kami sering hanyaH mencari komit atau hanya komitI-J dalam git logkeluaran kami . Komit melalui Gada di kedua cabang, jadi kami ingin mengecualikannya.

(Perhatikan bahwa dalam grafik yang digambar seperti ini, komit yang lebih baru mengarah ke kanan. Nama tersebut memilih komit paling kanan tunggal pada baris itu. Masing-masing komit tersebut memiliki komit induk, yaitu komit di sebelah kiri: induk dari His G, dan induk dari Jadalah I. Induk dari Iadalah Glagi. Induk dari Gadalah F, dan Fmemiliki induk yang tidak ditampilkan di sini: itu bagian dari ...bagian.)

Untuk kasus yang sangat sederhana ini, kita dapat menggunakan:

git log master..develop    # note: two dots

untuk melihat I-J, atau:

git log develop..master    # note: two dots

untuk melihat Hsaja. Nama sisi kanan, setelah dua titik, memberi tahu Git: ya, komit ini . Nama sisi kiri, sebelum dua titik, memberi tahu Git: tidak, bukan komit ini . Git dimulai di akhir —at komit Hatau komit J— dan bekerja mundur . Untuk (lebih) lagi tentang ini, lihat Think Like (a) Git .

Cara pertanyaan asli diutarakan, keinginannya adalah untuk menemukan komitmen yang dapat dijangkau dari satu nama tertentu, tetapi tidak dari nama lain dalam kategori umum yang sama. Artinya, jika kita memiliki grafik yang lebih kompleks:

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

kita dapat memilih salah satu dari nama ini, seperti name4atau name3, dan bertanya: komit mana yang dapat ditemukan dengan nama itu, tetapi tidak dengan nama lain? Jika kita memilih name3jawabannya adalah komit L. Jika kita memilih name4, jawabannya adalah tidak ada komit sama sekali: komit bahwa name4nama adalah komit Ntetapi komit Ndapat ditemukan dengan memulai name5dan bekerja mundur.

Jawaban yang diterima berfungsi dengan nama pelacakan jarak jauh, bukan nama cabang, dan memungkinkan Anda untuk menetapkan satu — yang dieja origin/merge-only— sebagai nama yang dipilih dan melihat semua nama lain di namespace itu. Ini juga menghindari menampilkan penggabungan: jika kita memilih name1sebagai "nama yang menarik", dan mengatakan tunjukkan komit yang dapat dijangkau dari name1tetapi bukan nama lain , kita akan melihat komit gabungan Mserta komit reguler I.

Jawaban paling populer agak berbeda. Ini semua tentang melintasi grafik komit tanpa mengikuti kedua kaki penggabungan, dan tanpa menunjukkan komitmen apa pun yang merupakan penggabungan. Jika kita mulai dengan name1, misalnya, kita tidak akan menampilkan M(ini adalah gabungan), tetapi dengan asumsi orang tua pertama dari gabungan Madalah komit I, kita bahkan tidak akan melihat komit Jdan K. Kami akan berakhir menampilkan komit I, dan juga melakukan H, G, F, dan sebagainya-tak satu pun dari ini komit merge dan semua bisa dicapai dengan mulai Mdan bekerja mundur, mengunjungi hanya pertama orang tua masing-masing gabungan komit.

Jawaban paling populer sangat cocok untuk, misalnya, melihat masterkapan masterdimaksudkan untuk menjadi cabang khusus gabungan. Jika semua "pekerjaan nyata" dilakukan pada cabang samping yang kemudian digabung master, kita akan memiliki pola seperti ini:

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

di mana semua okomit tanpa nama adalah komit biasa (bukan gabungan) dan Mdan Nmerupakan komit gabungan. Komit Iadalah komit awal: komit pertama yang pernah dibuat, dan satu-satunya yang harus ada di master yang bukan komit gabungan. Jika git log --first-parent --no-merges mastermenunjukkan komit selain I , kami memiliki situasi seperti ini:

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

di mana kami ingin melihat komit *yang dibuat secara langsung master, bukan dengan menggabungkan beberapa cabang fitur.

Singkatnya, jawaban populer sangat bagus untuk melihat masterkapan masterdimaksudkan untuk menjadi hanya gabungan, tetapi tidak terlalu bagus untuk situasi lain. Jawaban yang diterima berfungsi untuk situasi lain ini.

Apakah nama pelacak jarak jauh seperti nama origin/master cabang ?

Beberapa bagian Git mengatakan tidak:

git checkout master
...
git status

berkata on branch master, tapi:

git checkout origin/master
...
git status

kata HEAD detached at origin/master. Saya lebih suka setuju dengan git checkout/ git switch: origin/masterbukan nama cabang karena Anda tidak bisa mendapatkan "di" nya.

Jawaban yang diterima menggunakan nama pelacakan jarak jauh origin/*sebagai "nama cabang":

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

Garis tengah, yang memanggil git for-each-ref, mengulangi nama pelacak jarak jauh untuk nama jarak jauh origin.

Alasan ini adalah solusi yang baik untuk masalah asli adalah karena kami tertarik di sini pada nama cabang orang lain , daripada nama cabang kami . Tapi itu berarti kita telah mendefinisikan cabang sebagai sesuatu selain dari nama cabang kita . Tidak apa-apa: ketahuilah bahwa Anda sedang melakukan ini, saat Anda melakukannya.

git log melintasi beberapa bagian dari grafik komit

Apa yang sebenarnya kami cari di sini adalah rangkaian dari apa yang saya sebut daglets: lihat Apa sebenarnya yang kami maksud dengan "cabang"? Artinya, kami mencari fragmen dalam beberapa subset dari grafik komit keseluruhan .

Setiap kali kita melihat Git melihat nama cabang seperti master, nama tag seperti v2.1, atau nama pelacakan jarak jauh seperti origin/master, kita cenderung ingin Git memberi tahu kita tentang komit itu dan setiap komit yang bisa kita dapatkan dari komit itu: mulai dari sana , dan bekerja mundur.

Dalam matematika, ini disebut sebagai grafik berjalan . Grafik komit Git adalah Grafik Asiklik Terarah atau DAG , dan grafik semacam ini sangat cocok untuk berjalan. Saat berjalan di grafik seperti itu, seseorang akan mengunjungi setiap simpul grafik yang dapat dijangkau melalui jalur yang digunakan. Titik-titik dalam grafik Git adalah komit, dengan ujung-ujungnya menjadi busur — tautan satu arah — dari setiap turunan ke setiap induk. (Di sinilah Think Like (a) Git masuk. Sifat busur satu arah berarti Git harus bekerja mundur, dari anak ke orang tua.)

Dua perintah utama Git untuk pembuatan grafik adalah git logdan git rev-list. Perintah-perintah ini sangat mirip — sebenarnya sebagian besar dibuat dari file sumber yang sama — tetapi keluarannya berbeda: git logmenghasilkan keluaran untuk dibaca manusia, sementara git rev-listmenghasilkan keluaran yang dimaksudkan untuk dibaca oleh program Git lain. 1 Kedua perintah ini melakukan jenis grafik berjalan.

Penjelajahan grafik yang mereka lakukan secara khusus: mengingat beberapa set komit titik awal (mungkin hanya satu komit, mungkin sekumpulan ID hash, mungkin sekumpulan nama yang menyelesaikan menjadi ID hash), menjalankan grafik, mengunjungi komit . Arahan tertentu, seperti --notatau awalan ^, atau --ancestry-path, atau --first-parent, memodifikasi jalan grafik dengan cara tertentu.

Saat mereka menjalankan grafik, mereka mengunjungi setiap commit. Tetapi mereka hanya mencetak beberapa subset yang dipilih dari walking commit. Arahan seperti --no-mergesatau --before <date>beri tahu kode berjalan grafik yang berkomitmen untuk dicetak .

Untuk melakukan kunjungan ini, satu komit pada satu waktu, dua perintah ini menggunakan antrian prioritas . Anda menjalankan git logatau git rev-listdan memberinya beberapa titik awal komit. Mereka menempatkan komit tersebut ke dalam antrean prioritas. Misalnya, sederhana:

git log master

mengubah nama mastermenjadi ID hash mentah dan menempatkan ID hash tersebut ke dalam antrean. Atau:

git log master develop

mengubah kedua nama menjadi ID hash dan — dengan asumsi ini adalah dua ID hash yang berbeda — menempatkan keduanya ke dalam antrean.

Prioritas komit dalam antrian ini ditentukan oleh lebih banyak argumen. Misalnya, argumen --author-date-ordermemberi tahu git logatau git rev-listmenggunakan stempel waktu penulis , bukan stempel waktu pelaku. Standarnya adalah menggunakan stempel waktu pelaku dan memilih commit terbaru berdasarkan tanggal: yang memiliki tanggal numerik tertinggi. Jadi dengan master developasumsi ini menyelesaikan dua komit yang berbeda, Git akan menunjukkan mana yang lebih dulu datang , karena itu akan berada di depan antrian.

Bagaimanapun, revisi kode berjalan sekarang berjalan dalam satu putaran:

  • Saat ada komit dalam antrean:
    • Hapus entri antrian pertama.
    • Putuskan apakah akan mencetak komit ini atau tidak. Misalnya --no-merges,: tidak mencetak apa pun jika itu adalah komit gabungan; --before: tidak mencetak apa pun jika tanggalnya tidak datang sebelum waktu yang ditentukan. Jika pencetakan tidak ditekan, cetak komit: untuk git log, tampilkan lognya; untuk git rev-list, cetak ID hash-nya.
    • Letakkan beberapa atau semua komit induk komit ini ke dalam antrian (selama tidak ada sekarang, dan belum dikunjungi 2 ). Default normal adalah menempatkan semua orang tua. Menggunakan --first-parentmenekan semua kecuali orang tua pertama dari setiap gabungan.

(Keduanya git logdan git rev-listdapat melakukan penyederhanaan riwayat dengan atau tanpa penulisan ulang orang tua pada saat ini juga, tetapi kami akan melewatkannya di sini.)

Untuk rantai sederhana, seperti mulai HEADdan bekerja mundur saat tidak ada komit gabungan, antrean selalu memiliki satu komit di dalamnya di bagian atas perulangan. Ada satu komit, jadi kami mengeluarkannya dan mencetaknya dan meletakkan (tunggal) induknya ke dalam antrian dan berputar lagi, dan kami mengikuti rantai ke belakang sampai kami mencapai komit pertama, atau pengguna bosan dengan git logkeluaran dan keluar program. Dalam kasus ini, tidak ada opsi pengurutan yang penting: hanya ada satu komit untuk ditampilkan.

Ketika ada penggabungan dan kami mengikuti kedua orang tua — keduanya merupakan "kaki" dari penggabungan — atau saat Anda memberi git logatau git rev-listlebih dari satu komitmen awal, opsi penyortiran penting.

Terakhir, pertimbangkan efek dari --not atau ^di depan penentu komit. Ini memiliki beberapa cara untuk menulisnya:

git log master --not develop

atau:

git log ^develop master

atau:

git log develop..master

semuanya memiliki arti yang sama. Itu --notseperti awalan^ kecuali itu berlaku untuk lebih dari satu nama:

git log ^branch1 ^branch2 branch3

berarti bukan branch1, bukan branch2, yes branch3;tapi:

git log --not branch1 branch2 branch3

berarti bukan branch1, bukan branch2, bukan branch3, dan Anda harus menggunakan yang kedua--not untuk mematikannya:

git log --not branch1 branch2 --not branch3

yang agak canggung. Kedua arahan "bukan" digabungkan melalui XOR, jadi jika Anda benar-benar ingin, Anda dapat menulis:

git log --not branch1 branch2 ^branch3

berarti bukan branch1, bukan branch2, ya branch3 , jika Anda ingin mengaburkan .

Ini semua bekerja dengan mempengaruhi grafik berjalan. Saat git logatau git rev-listmenjalankan grafik, itu memastikan untuk tidak memasukkan ke dalam antrian prioritas setiap komit yang dapat dijangkau dari referensi yang dinegasikan . (Faktanya, mereka juga mempengaruhi pengaturan awal: komit yang dinegasikan tidak dapat masuk ke antrian prioritas langsung dari baris perintah, jadi git log master ^mastertidak menunjukkan apa-apa, misalnya.)

Semua sintaksis mewah yang dijelaskan dalam dokumentasi gitrevision memanfaatkan ini, dan Anda dapat mengeksposnya dengan panggilan sederhana ke git rev-parse. Misalnya:

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

Sintaks tiga titik berarti komitmen dapat dijangkau dari sisi kiri atau kanan, tetapi mengecualikan komitmen yang dapat dijangkau dari keduanya . Dalam hal ini origin/masterkomit b34789c0b,, itu sendiri dapat dijangkau dari origin/pu(fc307aa37... ) sehingga origin/masterhash muncul dua kali, sekali dengan negasi, tetapi pada kenyataannya Git mencapai sintaks tiga titik dengan memasukkan dua referensi positif — dua ID hash non-negasi — dan satu negatif, diwakili oleh ^awalan.

Demikian pula:

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

The ^@berarti sintaks semua orang tua yang diberikan komit , dan master^sendiri-induk pertama dari komit dipilih oleh cabang-nama master-adalah gabungan komit, sehingga memiliki dua orang tua. Ini adalah dua orang tua. Dan:

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

The ^!berarti akhiran komit itu sendiri, namun tidak satupun dari orang tuanya . Dalam hal ini, master^adalah 0b07eecf6.... Kami sudah melihat kedua orang tua dengan ^@sufiks; di sini mereka lagi, tapi kali ini, dinegasikan.


1 Banyak program Git benar-benar berjalan git rev-listdengan berbagai opsi, dan membaca keluarannya, untuk mengetahui komit dan / atau objek Git lain yang akan digunakan.

2 Karena grafiknya asiklik , mungkin untuk menjamin bahwa tidak ada yang sudah dikunjungi, jika kita menambahkan batasan jangan pernah tampilkan induk sebelum menampilkan semua anaknya ke prioritas. --date-order,, --author-date-orderdan --topo-ordertambahkan batasan ini. Tata urutan default — yang tidak memiliki nama — tidak. Jika stempel waktu commit tidak benar — jika misalnya beberapa commit dibuat "di masa mendatang" oleh komputer yang jamnya mati — ini dalam beberapa kasus dapat menyebabkan keluaran yang tampak aneh.


Jika Anda berhasil sejauh ini, Anda sekarang tahu banyak tentangnya git log

Ringkasan:

  • git log adalah tentang menampilkan beberapa komit yang dipilih saat menjalankan beberapa atau semua bagian grafik.
  • The --no-mergesargumen, ditemukan di kedua diterima dan jawaban saat-top-peringkat, menekan menunjukkan beberapa komit bahwa yang berjalan.
  • The --first-parentargumen, dari saat-top-peringkat-jawaban, menekan berjalan beberapa bagian dari grafik, selama grafik-berjalan sendiri.
  • The --notawalan untuk argumen baris perintah, seperti yang digunakan dalam jawaban yang diterima, menekan pernah mengunjungi beberapa bagian dari grafik sama sekali, benar dari awal.

Kami mendapatkan jawaban yang kami suka, untuk dua pertanyaan berbeda, menggunakan fitur-fitur ini.

torek
sumber