Bagaimana cara mengambil hash untuk commit saat ini di Git?

1934

Saya ingin mempertahankan (untuk saat ini) kemampuan untuk menautkan Git changesets ke workitem yang disimpan di TFS.

Saya sudah menulis alat (menggunakan kait dari Git) di mana saya bisa menyuntikkan workitemidentifiers ke dalam pesan dari Git changeset.

Namun, saya juga ingin menyimpan pengidentifikasi komit Git (hash) ke dalam bidang workitem TFS khusus. Dengan cara ini saya bisa memeriksa workitem di TFS dan melihat apa yang terkait dengan perubahan Git dengan workitem.

Bagaimana saya bisa dengan mudah mengambil hash dari commit saat ini dari Git?

Sardaukar
sumber

Jawaban:

2810

Untuk mengubah referensi objek diperluas sewenang-wenang menjadi SHA-1, gunakan cukup git-rev-parse , misalnya

git rev-parse HEAD

atau

git rev-parse --verify HEAD

Sidenote: Jika Anda ingin mengubah referensi ( cabang dan tag ) menjadi SHA-1, adagit show-refdangit for-each-ref.

Jakub Narębski
sumber
81
--verifymenyiratkan bahwa:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck
648
git rev-parse --short HEADmengembalikan versi pendek dari hash, kalau-kalau ada yang bertanya-tanya.
Thane Brimhall
55
Menambahkan apa yang dikatakan Thane, Anda juga bisa menambahkan panjang tertentu --short, seperti --short=12, untuk mendapatkan jumlah digit tertentu dari hash.
Tyson Phalp
32
@TysonPhalp: --short=Nadalah tentang jumlah digit minimal ; git menggunakan jumlah digit yang lebih besar jika dipersingkat satu tidak dapat dibedakan dari komit yang disingkat. Coba misalnya git rev-parse --short=2 HEADatau git log --oneline --abbrev=2.
Jakub Narębski
36
Menambahkan apa yang dikatakan Thane, Tyson, dan Jakub, Anda dapat mencetak hash penuh, tetapi sorot heksit yang diperlukan untuk mengidentifikasi biru komit dengangit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz
424

Jika Anda hanya menginginkan hash yang disingkat:

git log --pretty=format:'%h' -n 1

Selanjutnya, menggunakan% H adalah cara lain untuk mendapatkan hash yang panjang.

outofculture
sumber
107
Atau, tampaknya, menambahkan --short ke perintah rev-parse di atas tampaknya berfungsi.
outofculture
15
Saya pikir git logporselen dan git rev-parsepipa.
Amedee Van Gasse
Salah satu manfaat dari metode ini adalah bahwa ia akan mengembalikan versi pendek dari hash dengan panjang yang tepat disesuaikan dengan benturan hash yang terjadi untuk repo yang lebih besar. Setidaknya di git versi terbaru.
Ilia Sidorenko
4
Ini adalah cara yang buruk / salah untuk melakukannya karena metode ini akan memberi Anda hash yang salah jika Anda memiliki kepala yang terpisah. Sebagai contoh jika komit saat ini adalah 12ab34 ... dan komit sebelumnya adalah 33aa44 ... maka jika saya melakukan 'git checkout 33aa44' dan kemudian saya menjalankan perintah Anda, saya masih akan mendapatkan kembali 12ab34 ... meskipun kepala saya benar-benar menunjuk ke 33aa44 ...
theQuestionMan
3
@ theQuestionMan Saya tidak mengalami perilaku yang Anda gambarkan; git checkout 33aa44; git log -n 1memberi saya 33aa44. Apa versi git yang Anda gunakan?
outofculture
150

Satu lagi, menggunakan git log:

git log -1 --format="%H"

Ini sangat mirip dengan @outofculture meskipun sedikit lebih pendek.

Paul Pladijs
sumber
Dan hasilnya tidak dikutip sendiri.
crokusek
5
Ini adalah jawaban yang benar, karena itu berfungsi bahkan jika Anda checkout komit tertentu, bukan HEAD.
Parsa
1
@Parsa: ketika memeriksa komit tertentu HEADuntuk komit ini daripada branche bernama kenal sebagai kepala terpisah .
ChristofSenn
125

Untuk mendapatkan SHA lengkap:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Untuk mendapatkan versi singkat:

$ git rev-parse --short HEAD
cbf1b9a
Alexander
sumber
Jika dua git commithash diperlukan, seperti satu dari hash yang sedang branchAnda kerjakan dan a master branch, Anda juga bisa menggunakan git rev-parse FETCH_HEADjika Anda membutuhkan hash untuk apa master commityang Anda mergemasukkan ke arus Anda branch. misalnya jika Anda memiliki branches masterdan feature/new-featureuntuk repo yang diberikan., sementara feature/new-featureAnda dapat menggunakan git fetch origin master && git merge FETCH_HEADdan kemudian git rev-parse --short FETCH_HEADjika Anda membutuhkan commithash dari masterAnda hanya merged dalam untuk setiap skrip yang mungkin Anda miliki.
EVAL
72

Untuk kelengkapan, karena belum ada yang menyarankannya. .git/refs/heads/masteradalah file yang hanya berisi satu baris: hash dari commit terbaru master. Jadi Anda bisa membacanya dari sana.

Atau, sebagai perintah:

cat .git/refs/heads/master

Memperbarui:

Perhatikan bahwa git sekarang mendukung penyimpanan beberapa head ref di file pack-ref alih-alih sebagai file di folder / refs / heads /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Deestan
sumber
10
Ini mengasumsikan cabang saat ini master, yang belum tentu benar.
gavrie
12
Memang. Itu sebabnya saya secara eksplisit mengatakan ini untuk master.
Deestan
20
.git/HEADbiasanya menunjuk ke ref, jika Anda memiliki SHA1 di sana, Anda berada dalam mode kepala terpisah.
eckes
8
Ini tidak terlalu kuat dibandingkan dengan pendekatan lain, khususnya karena mengasumsikan bahwa ada .gitsubdirektori, yang belum tentu demikian. Lihat --separate-git-dirbendera di git inithalaman manual.
jub0bs
16
+1 karena kadang-kadang Anda tidak ingin git executable diinstal (misalnya di Dockerfile Anda)
wim
50

Komit hash

git show -s --format=%H

Disingkat melakukan hash

git show -s --format=%h

Klik di sini untuk git showcontoh lebih lanjut .

ecwpz91
sumber
50

Selalu ada git describejuga. Secara default itu memberi Anda -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
John Tyree
sumber
18
Git menjelaskan mengembalikan TAG pertama yang dapat dicapai dari komit. Bagaimana ini membantu saya mendapatkan SHA?
Sardaukar
42
Saya suka git describe --long --dirty --abbrev=10 --tagsitu akan memberi saya sesuatu seperti 7.2.0.Final-447-g65bf4ef2d4447 yang dilakukan setelah tag 7.2.0.Final dan 10 intisari pertama SHA-1 global pada HEAD saat ini adalah "65bf4ef2d4". Ini sangat bagus untuk string versi. Dengan --long ia akan selalu menambahkan jumlah (-0-) dan hash, bahkan jika tag benar-benar cocok.
eckes
14
Jika tidak ada tag, maka git describe --alwaysakan "menampilkan objek komit yang disingkat unik sebagai mundur"
Ronny Andersson
Saya menggunakan git describe --tags --first-parent --abbrev=11 --long --dirty --always. The --alwayspilihan berarti memberikan hasil (hash) bahkan jika tidak ada tag. The --first-parentberarti itu tidak bingung dengan komit penggabungan dan hanya mengikuti item pada cabang saat ini. Perhatikan juga bahwa --dirtyakan menambahkan -dirtyhasil jika cabang saat ini memiliki perubahan yang tidak dikomit.
ingyhere
30

Menggunakan git rev-list --max-count=1 HEAD

Robert Munteanu
sumber
3
git-rev-list adalah tentang membuat daftar objek commit; itu adalah git-rev-parse untuk menerjemahkan nama objek (misalnya KEPALA) ke SHA-1
Jakub Narębski
21

Jika Anda perlu menyimpan hash dalam sebuah variabel selama skrip, Anda bisa menggunakannya

last_commit=$(git rev-parse HEAD)

Atau, jika Anda hanya menginginkan 10 karakter pertama (seperti yang dilakukan github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 
Henk
sumber
26
Ada juga parameter --shortatau --short=numberuntuk git rev-parse; tidak perlu menggunakan pipa dan cut.
Julian D.
15

Jika Anda ingin cara super-hacky untuk melakukannya:

cat .git/`cat .git/HEAD | cut -d \  -f 2`

Pada dasarnya, git menyimpan lokasi HEAD di .git / HEAD, dalam bentuk ref: {path from .git}. Perintah ini membacanya, memotong "ref:", dan membacakan file apa pun yang ditunjukkan.

Ini, tentu saja, akan gagal dalam mode kepala terpisah, karena KEPALA tidak akan menjadi "ref: ...", tetapi hash itu sendiri - tetapi Anda tahu, saya tidak berpikir Anda berharap bahwa banyak kecerdasan dalam bash Anda -linier. Jika Anda tidak berpikir titik koma selingkuh, ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
Fordi
sumber
1
tidak perlu menginstal git, saya menyukainya. (gambar bangunan buruh pelabuhan saya tidak memiliki git)
Helin Wang
juga berguna karena Anda dapat menjalankan ini dengan mudah dari luar git repo
samaspin
Saya memformalkan ini ke skrip untuk mesin lokal saya. Kemudian, saya berpikir, hei: implementasi yang saya buat cukup sederhana sehingga menggambarkan bagaimana memecahkan masalah yang tidak berhubungan (parsing argumen dalam skrip shell POSIX mentah tanpa program eksternal), tetapi cukup kompleks untuk memberikan sedikit variasi dan untuk mengeksploitasi sebagian besar fitur dari sh. Setengah jam komentar dokumentasi kemudian, dan ini inti
Fordi
Melihat itu, saya membuat versi yang lebih luas untuk mendeteksi Git dan SVN, dan meraih revisi hash / svn git. Bukan string bersih kali ini, tetapi baris perintah mudah diurai, dan dapat digunakan sebagai tag versi: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi
14

Cara paling ringkas yang saya tahu:

git show --pretty=%h 

Jika Anda menginginkan jumlah digit hash tertentu, Anda dapat menambahkan:

--abbrev=n
Brian Peterson
sumber
14
Sementara ini secara teknis bekerja, git showadalah apa yang dikenal sebagai perintah porselen (yaitu yang menghadap pengguna), dan karenanya tidak boleh digunakan dalam skrip karena outputnya dapat berubah. Jawaban di atas ( git rev-parse --short HEAD) harus digunakan sebagai gantinya.
jm3
4
@ jm3 itu terbalik. Perintah "Porcelain" memiliki output stabil yang dimaksudkan untuk skrip. Cari git help showuntuk porcelain.
John Tyree
2
@ JohnTyree Ini adalah subjek yang membingungkan, tetapi jm3 benar: perintah porselen tidak dimaksudkan untuk diuraikan, tetapi lebih untuk dibaca oleh manusia. Jika Anda perlu menggunakan perintah porselen dalam skrip dan Anda ingin memiliki format yang stabil, kadang-kadang (misalnya dengan status git, tekan dan salahkan) opsi yang melakukan hal itu. Sayangnya, opsi itu disebut --porcelain, itulah sebabnya ini membingungkan. Anda dapat menemukan perincian dalam jawaban hebat ini oleh VonC
Fabio berkata Reinstate Monica
1
tuhan sayang yang memutuskan untuk menyebutkan pilihan itu - porselen aku ingin menemukan mereka dan ... oh tunggu aku harus menggunakan git untuk menemukan mereka Nevermind
Britton Kerin
14

Mungkin Anda menginginkan alias sehingga Anda tidak harus mengingat semua detail yang bagus. Setelah melakukan salah satu langkah di bawah ini, Anda dapat cukup mengetik:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Menindaklanjuti jawaban yang diterima , berikut adalah dua cara untuk mengatur ini:

1) Ajarkan git dengan cara eksplisit dengan mengedit konfigurasi global (jawaban asli saya):

 # open the git config editor
 $ git config --global --edit
 # in the alias section, add
 ...
 [alias]
   lastcommit = rev-parse HEAD
 ...

2) Atau jika Anda suka jalan pintas untuk mengajar git jalan pintas, seperti yang baru-baru ini dikomentari oleh Adrien:

$ git config --global alias.lastcommit "rev-parse HEAD"

Dari sini, gunakan git lastcommituntuk menampilkan hash komit terakhir.

miraculixx
sumber
3
Adrien de Sentenac mencatat bahwa alih-alih secara manual mengedit file konfigurasi git, Anda cukup melakukan:git config --global alias.lastcommit "rev-parse HEAD"
cgmb
12

Saya membutuhkan sesuatu yang sedikit lebih berbeda: menampilkan sha1 penuh dari komit, tetapi menambahkan tanda bintang sampai akhir jika direktori kerja tidak bersih. Kecuali saya ingin menggunakan banyak perintah, tidak ada opsi di jawaban sebelumnya yang berfungsi.

Inilah satu-satunya liner yang berfungsi:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Hasil:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Penjelasan: menjelaskan (menggunakan tag beranotasi) komit saat ini, tetapi hanya dengan tag yang mengandung "BUKAN TAG". Karena tag tidak dapat memiliki spasi, ini tidak pernah cocok dengan tag dan karena kami ingin menunjukkan hasilnya --always, perintah akan kembali menampilkan penuh ( --abbrev=0) sha1 dari komit dan menambahkan tanda bintang jika direktori kerja adalah --dirty.

Jika Anda tidak ingin menambahkan tanda bintang, ini berfungsi seperti semua perintah lain di jawaban sebelumnya:
git describe --always --abbrev=0 --match "NOT A TAG"
Hasil:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

Rado
sumber
Terima kasih, hanya tersandung padanya dan itu membuat saya gema satu atau lain untuk itu :)
hakre
1
Ini bekerja untuk saya tanpa --match "NOT A TAG". Diuji dalam git 2.18.0 dan 2.7.4. Apakah ada situasi di mana argumen ini diperlukan?
Thomas
@ Thomas tidak akan berfungsi jika Anda memiliki tag beranotasi di mana saja dalam sejarah komit saat ini. Tag palsu memastikan bahwa perintah uraikan tidak menggunakan tag untuk menggambarkan komit,
Rado
8
git show-ref --head --hash head

Jika Anda ingin kecepatan, pendekatan yang disebutkan oleh Deestan

cat .git/refs/heads/<branch-name>

secara signifikan lebih cepat daripada metode lain yang terdaftar di sini sejauh ini.

Dennis
sumber
show-reftampaknya saya untuk menjadi pilihan terbaik untuk scripting, karena itu adalah perintah pipa dan dengan demikian dijamin (atau setidaknya sangat mungkin) tetap stabil dalam rilis mendatang: jawaban lainnya menggunakan rev-parse, show, describe, atau log, yang semua perintah porselen. Dan dalam kasus-kasus di mana kecepatan bukan dari esensi, catatan dari halaman show-refmanual berlaku: 'Penggunaan utilitas ini didorong untuk secara langsung mengakses file di bawah direktori .git.'
Pont
6

Berikut ini adalah satu-liner di Bash shell menggunakan membaca langsung dari file git:

(head=($(<.git/HEAD)); cat .git/${head[1]})

Anda perlu menjalankan perintah di atas di folder git root Anda.

Metode ini dapat berguna ketika Anda telah menyimpan file, tetapi gitperintah belum diinstal.

Jika tidak berhasil, periksa di .git/refs/headsfolder jenis kepala apa yang Anda miliki.

kenorb
sumber
5

di dir-home Anda di file ".gitconfig" tambahkan yang berikut ini

[alias]
sha = rev-parse HEAD

maka Anda akan memiliki perintah yang lebih mudah untuk diingat:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
jo_
sumber
3

Pada git bash, cukup jalankan $ git log -1

Anda akan melihat, baris-baris ini mengikuti perintah Anda.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
Amuk
sumber
0

Berikut ini adalah implementasi akses langsung lainnya:

head="$(cat ".git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(cat ".git/${head#ref: }")"
done

Ini juga berfungsi di http yang berguna untuk arsip paket lokal (saya tahu: untuk situs web publik, tidak disarankan untuk membuat direktori .git dapat diakses):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done
Daniel Alder
sumber
0

Ini cara lain melakukannya dengan :)

git log | grep -o '\w\{8,\}' | head -n 1
Marcelo Lazaroni
sumber
0
cat .git/HEAD

Contoh output:

ref: refs/heads/master

Parsing:

cat .git/HEAD | sed "s/^.\+ \(.\+\)$/\1/g"

Jika Anda memiliki windows maka Anda dapat mempertimbangkan untuk menggunakan wsl.exe:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g"

Keluaran:

refs/heads/master

Nilai ini dapat digunakan untuk mendapatkan checkout nanti tetapi menjadi menunjuk ke SHA-nya. Untuk membuatnya menunjuk ke cabang aktual saat ini dengan namanya lakukan:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g" | wsl sed "s/^refs\///g" | wsl sed "s/^heads\///g"

Output:

master

Sergei
sumber