จะเรียกแฮชสำหรับการคอมมิทปัจจุบันได้อย่างไรใน Git?


1931

ฉันต้องการที่จะรักษาความสามารถในการเชื่อมโยงการเปลี่ยนแปลง Git กับงานที่เก็บไว้ใน TFS

ฉันได้เขียนเครื่องมือ (โดยใช้ hook จาก Git) ซึ่งฉันสามารถฉีดเจ้าหน้าที่ทำงานในข้อความของเซ็ตการแก้ไข Git

อย่างไรก็ตามฉันต้องการเก็บตัวบ่งชี้ของ Git commit (the hash) ในฟิลด์ TFS workitem ที่กำหนดเอง วิธีนี้ฉันสามารถตรวจสอบ workitem ใน TFS และดูว่าการเปลี่ยนแปลง Git เกี่ยวข้องกับ workitem อย่างไร

ฉันจะดึงแฮชจากการคอมมิทปัจจุบันจาก Git ได้อย่างไร?

คำตอบ:


2809

ที่จะเปิดโดยพลการอ้างอิงวัตถุขยายเข้าไปใน SHA-1 ใช้เพียงGit-REV-แจงยกตัวอย่างเช่น

git rev-parse HEAD

หรือ

git rev-parse --verify HEAD

Sidenote:ถ้าคุณต้องการที่จะเปิดการอ้างอิง (สาขาและแท็ก ) ลง SHA-1 มีและgit show-refgit for-each-ref


81
--verifyหมายความว่า:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck

648
git rev-parse --short HEADส่งคืนแฮชเวอร์ชันสั้นในกรณีที่มีใครสงสัย
Thane Brimhall

54
การเพิ่มสิ่งที่ Thane กล่าวไว้คุณสามารถเพิ่มความยาวเฉพาะ--shortเช่น--short=12เพื่อรับตัวเลขจำนวนหนึ่งจากแฮช
Tyson Phalp

32
@TysonPhalp: --short=Nเป็นจำนวนหลักที่น้อยที่สุด git ใช้จำนวนหลักที่มากขึ้นหากมีการย่อให้สั้นลงจะไม่สามารถแยกแยะได้จากการกระทำอื่นที่สั้นลง ลองเช่นหรือgit rev-parse --short=2 HEAD git log --oneline --abbrev=2
Jakub Narębski

36
เพิ่มในสิ่งที่ Thane, Tyson และ Jakub กล่าวว่าคุณสามารถพิมพ์แฮชเต็มรูปแบบ แต่เน้นจุดที่จำเป็นเพื่อระบุสีน้ำเงินคอมมิชชันด้วยgit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz

423

หากคุณต้องการแฮชที่สั้นลง:

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

นอกจากนี้การใช้% H เป็นอีกวิธีหนึ่งในการรับแฮชที่ยาว


107
หรือดูเหมือนว่าการเพิ่ม --short ไปที่คำสั่ง rev-parse ด้านบนดูเหมือนว่าจะใช้งานได้
outofculture

15
ฉันคิดว่าgit logเป็นเครื่องเคลือบและgit rev-parseเป็นประปา
Amedee Van Gasse

ข้อดีอย่างหนึ่งของวิธีนี้คือมันจะคืนค่าแฮชแบบสั้นโดยปรับความยาวให้เหมาะสมกับการชนของแฮชที่เกิดขึ้นสำหรับ repos ขนาดใหญ่ อย่างน้อยใน git รุ่นล่าสุด
Ilia Sidorenko

4
นี่เป็นวิธีที่ไม่ดี / ไม่ถูกต้องในการทำเช่นนี้เพราะวิธีนี้จะทำให้คุณแฮชผิดถ้าคุณมีหัวที่แยกออก ตัวอย่างเช่นหากกระทำปัจจุบันคือ 12ab34 ... และกระทำก่อนหน้านี้คือ 33aa44 ... แล้วถ้าฉันทำ 'git checkout 33aa44' แล้วฉันเรียกใช้คำสั่งของคุณฉันจะยังคงได้รับกลับ 12ab34 ... แม้หัวของฉันชี้จริง ๆ เพื่อ 33aa44 ...
theQuestionMan

3
@TheQuestionMan ฉันไม่ได้สัมผัสกับพฤติกรรมที่คุณอธิบาย ให้ฉันgit checkout 33aa44; git log -n 1 33aa44คุณใช้คอมไพล์รุ่นใด
outofculture

150

อีกอันหนึ่งโดยใช้บันทึก git:

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

มันคล้ายกับของ @outofculture มากกว่าเล็กน้อย


และผลลัพธ์ไม่ได้อ้างถึงแบบเดี่ยว
crokusek

5
HEADนี่คือคำตอบที่ถูกต้องเนื่องจากมันทำงานแม้ว่าคุณจะชำระเงินเฉพาะกระทำการแทน
Parsa

1
@Parsa: เมื่อตรวจสอบจากที่เฉพาะเจาะจงกระทำHEADจุดนี้กระทำมากกว่า branche รู้ชื่อเป็นหัวเดี่ยว
ChristofSenn

124

ในการรับ SHA แบบเต็ม:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

วิธีรับเวอร์ชันย่อ:

$ git rev-parse --short HEAD
cbf1b9a

หากทั้งสองgit commithashes มีความจำเป็นดังกล่าวเป็นหนึ่งจากbranchที่คุณกำลังทำงานร่วมกับและmaster branchคุณยังสามารถใช้git rev-parse FETCH_HEADถ้าคุณต้องการกัญชาสำหรับmaster commitที่คุณวันที่ลงในปัจจุบันของคุณmerge branchเช่นถ้าคุณมีbranches masterและfeature/new-featurerepo ที่กำหนดในขณะที่feature/new-featureคุณสามารถใช้git fetch origin master && git merge FETCH_HEADแล้วgit rev-parse --short FETCH_HEADถ้าคุณต้องการcommitแฮชจากmasterคุณเพียงแค่mergeสคริปต์ที่คุณอาจมี
EVAL

72

เพื่อความสมบูรณ์เนื่องจากยังไม่มีใครแนะนำเลย .git/refs/heads/masterคือไฟล์ที่มีเพียงหนึ่งบรรทัด: masterกัญชาล่าสุดกระทำใน คุณสามารถอ่านมันได้จากตรงนั้น

หรือตามคำสั่ง:

cat .git/refs/heads/master

ปรับปรุง:

โปรดทราบว่าตอนนี้ git รองรับการจัดเก็บส่วนอ้างอิงบางส่วนในไฟล์ pack-ref แทนที่จะเป็นไฟล์ใน / refs / heads / โฟลเดอร์ https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html


10
นี่ถือว่าสาขาปัจจุบันคือmasterซึ่งไม่จำเป็นต้องเป็นจริง
gavrie

12
จริง masterนั่นเป็นเหตุผลที่ผมอย่างชัดเจนกล่าวนี้เหมาะสำหรับ
Deestan

20
.git/HEADโดยทั่วไปแล้วจะชี้ไปที่การอ้างอิงถ้าคุณมี SHA1 อยู่ในนั้นคุณจะอยู่ในโหมดเฮดเดอร์เดี่ยว
eckes

8
สิ่งนี้ไม่แข็งแกร่งมากเมื่อเทียบกับวิธีการอื่น ๆ โดยเฉพาะอย่างยิ่งเพราะถือว่ามี.gitไดเรกทอรีย่อยซึ่งไม่จำเป็นต้องเป็นกรณีนี้ ดู--separate-git-dirธงในgit initหน้าคน
jub0bs

16
1 เพราะบางครั้งคุณไม่ต้องการที่ปฏิบัติการคอมไพล์ที่ติดตั้ง (เช่นใน Dockerfile ของคุณ)
Wim


50

ก็มีgit describeเช่นกัน โดยค่าเริ่มต้นจะช่วยให้คุณ -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75

18
Git อธิบายจะส่งคืนแท็กแรกที่เข้าถึงได้จากการส่ง สิ่งนี้จะช่วยให้ฉันได้รับ SHA อย่างไร
Sardaukar

42
ฉันชอบgit describe --long --dirty --abbrev=10 --tagsมันจะให้สิ่งที่ฉันชอบ7.2.0.Final-447-g65bf4ef2d4ซึ่งก็คือ 447 คอมมิชชันหลังจากแท็ก 7.2.0 สุดท้ายและ 10 สรุปแรกของ SHA-1 ทั่วโลกที่ HEAD ปัจจุบันคือ "65bf4ef2d4" สิ่งนี้ดีมากสำหรับสตริงรุ่น ด้วย - ยาวมันจะเพิ่มจำนวน (-0-) และแฮชเสมอแม้ว่าแท็กจะเกิดขึ้นตรงกันทุกประการ
eckes

14
หากไม่มีแท็กอยู่แล้วgit describe --alwaysจะ "แสดงตัวย่อการกระทำที่ไม่ซ้ำแบบพิเศษเป็นทางเลือก"
Ronny Andersson

git describe --tags --first-parent --abbrev=11 --long --dirty --alwaysฉันใช้ --alwaysตัวเลือกหมายความว่ามันมีผล (กัญชา) แม้ว่าจะมีไม่มีแท็ก --first-parentหมายความว่ามันไม่ได้รับการสับสนโดยกระทำการผสานและมีเพียงดังนี้รายการในสาขาปัจจุบัน โปรดทราบด้วยว่า--dirtyจะผนวก-dirtyผลลัพธ์ไว้ด้วยหากสาขาปัจจุบันมีการเปลี่ยนแปลงที่ไม่มีข้อผูกมัด
ingyhere

30

ใช้ git rev-list --max-count=1 HEAD


3
git-rev-list เป็นเรื่องเกี่ยวกับการสร้างรายชื่อของวัตถุที่กระทำ; มันเป็นคอมไพล์-REV-แจงการแปลชื่อวัตถุ (เช่น HEAD) ลง SHA-1
ยาคุบบNarębski

21

หากคุณต้องการเก็บแฮชในตัวแปรระหว่างสคริปต์คุณสามารถใช้

last_commit=$(git rev-parse HEAD)

หรือถ้าคุณต้องการ 10 ตัวอักษรแรกเท่านั้น (เช่น github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 

26
นอกจากนี้ยังมีพารามิเตอร์--shortหรือ--short=numberเพื่อgit rev-parse; cutไม่จำเป็นต้องใช้ท่อและ
Julian D.

15

หากคุณต้องการวิธีแฮ็คสุด ๆ :

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

โดยทั่วไปร้านค้าคอมไพล์สถานที่ตั้งของ HEAD ใน .git / HEAD ref: {path from .git}ในรูปแบบ คำสั่งนี้จะอ่านค่านั้นแบ่งส่วน "ref:" และอ่านไฟล์ที่ชี้ไป

แน่นอนว่านี่จะล้มเหลวในโหมดเดี่ยวเฮดเนื่องจาก HEAD จะไม่เป็น "ref: ... " แต่แฮชตัวเอง - แต่คุณรู้ไหมฉันไม่คิดว่าคุณจะคาดหวังว่าสมาร์ทมากในการทุบตีของคุณ -liners หากคุณไม่คิดว่าเครื่องหมายอัฒภาคกำลังนอกใจ ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH

1
ไม่จำเป็นต้องติดตั้งคอมไพล์ฉันชอบมัน (ภาพนักสร้างนักเทียบท่าของฉันไม่มีคอมไพล์)
Helin Wang

ยังมีประโยชน์เพราะคุณสามารถเรียกใช้สิ่งนี้ได้อย่างง่ายดายจากนอก git repo
samaspin

ฉันทำสิ่งนี้ให้เป็นสคริปต์สำหรับเครื่องท้องถิ่นของฉัน จากนั้นฉันคิดว่าเฮ้: การใช้งานที่ฉันทำนั้นง่ายพอที่จะอธิบายวิธีการแก้ปัญหาที่ไม่เกี่ยวข้อง (การแยกวิเคราะห์อาร์กิวเมนต์ในสคริปต์ POSIX เชลล์สคริปต์โดยไม่มีโปรแกรมภายนอก) แต่ซับซ้อนพอที่จะให้การเปลี่ยนแปลงเล็กน้อยและใช้ประโยชน์จาก shคุณสมบัติของ ครึ่งชั่วโมงของความคิดเห็นเอกสารในภายหลังและนี่เป็นส่วนสำคัญของมัน: gist.github.com/Fordi/29b8d6d1ef1662b306bfc2bd99151b07
Fordi

เมื่อมองดูแล้วฉันสร้างเวอร์ชันที่ครอบคลุมมากขึ้นสำหรับการตรวจจับ Git และ SVN และคว้าการแก้ไข hash / svn git ไม่ใช่สายอักขระที่สะอาด แต่คราวนี้แยกวิเคราะห์บรรทัดคำสั่งได้ง่ายและใช้เป็นแท็กเวอร์ชัน: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi

14

วิธีรวบรัดที่สุดที่ฉันรู้:

git show --pretty=%h 

หากคุณต้องการแฮชจำนวนหนึ่งคุณสามารถเพิ่ม:

--abbrev=n

14
ในขณะที่เทคนิคนี้ทำงานgit showได้สิ่งที่เรียกว่าคำสั่งเครื่องเคลือบ (เช่นผู้ใช้หันหน้าไปทาง) และไม่ควรใช้ในสคริปต์เพราะเอาท์พุทอาจมีการเปลี่ยนแปลง git rev-parse --short HEADควรใช้คำตอบข้างต้น ( ) แทน
jm3

4
@ jm3 ที่ล้าหลัง คำสั่ง "Porcelain" มีเอาต์พุตที่เสถียรซึ่งมีไว้สำหรับสคริปต์ ค้นหาสำหรับgit help show porcelain
John Tyree

2
@JohnTyree นี่เป็นเรื่องที่สับสน แต่ jm3 ถูกต้อง: คำสั่งเครื่องเคลือบไม่ได้มีการแยกวิเคราะห์ แต่จะอ่านได้ง่าย ในกรณีที่คุณจำเป็นต้องใช้คำสั่งเครื่องเคลือบในสคริปต์และคุณต้องการรูปแบบที่มั่นคงบางครั้งก็มี (ตัวอย่างเช่นสถานะ git, push และตำหนิ) ซึ่งเป็นตัวเลือกที่ทำเช่นนั้น น่าเสียดายที่ตัวเลือกนั้นถูกเรียก--porcelainซึ่งเป็นสาเหตุที่ทำให้เกิดความสับสน คุณสามารถค้นหารายละเอียดในคำตอบที่ยอดเยี่ยมนี้โดย VonC
Fabio พูดว่า Reinstate Monica

1
ที่รักของพระเจ้าที่ตัดสินใจตั้งชื่อตัวเลือกนั้น - พอร์ซเลนฉันต้องการค้นหาพวกเขาและ ... โอ้รอฉันจะต้องใช้คอมไพล์เพื่อค้นหาพวกเขาไม่เป็นไร
Britton Kerin

14

บางทีคุณต้องการนามแฝงดังนั้นคุณไม่จำเป็นต้องจำรายละเอียดที่ดีทั้งหมด หลังจากทำตามหนึ่งในขั้นตอนด้านล่างคุณจะสามารถพิมพ์:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

การติดตามคำตอบที่ยอมรับมีสองวิธีในการตั้งค่านี้:

1) สอน git อย่างชัดเจนโดยแก้ไข global config (คำตอบดั้งเดิมของฉัน):

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

2) หรือถ้าคุณชอบทางลัดในการสอนทางลัดคอมไพล์ตามที่เอเดรียได้แสดงความคิดเห็นไว้:

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

จากที่นี่เป็นต้นgit lastcommitไปใช้เพื่อแสดงแฮชการกระทำล่าสุด


3
Adrien de Sentenacตั้งข้อสังเกตว่าแทนที่จะแก้ไขไฟล์ git config ด้วยตนเองคุณสามารถทำได้:git config --global alias.lastcommit "rev-parse HEAD"
cgmb

12

ฉันต้องการบางสิ่งที่แตกต่างออกไปเล็กน้อย: แสดง sha1 แบบเต็มของการคอมมิต แต่ผนวกเครื่องหมายดอกจันต่อท้ายถ้าไดเร็กทอรีการทำงานไม่สะอาด ถ้าฉันไม่ต้องการใช้หลายคำสั่งก็ไม่มีตัวเลือกในคำตอบก่อนหน้านี้ทำงาน

นี่คือหนึ่งซับที่:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
ผลลัพธ์:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

คำอธิบาย: อธิบาย (ใช้แท็กที่มีคำอธิบายประกอบ) การคอมมิทปัจจุบัน แต่ใช้แท็กที่มี "NOT A TAG" เท่านั้น ตั้งแต่แท็กไม่สามารถมีช่องว่างตรงนี้ไม่เคยแท็กและเนื่องจากเราต้องการที่จะแสดงผลให้--alwaysคำสั่งอยู่กลับแสดงเต็มรูปแบบ ( --abbrev=0) sha1 --dirtyของการกระทำและมันผนวกดอกจันถ้าไดเรกทอรีการทำงานคือ

หากคุณไม่ต้องการผนวกเครื่องหมายดอกจันคำสั่งนี้จะทำงานเหมือนกับคำสั่งอื่นทั้งหมดในคำตอบก่อนหน้านี้:
git describe --always --abbrev=0 --match "NOT A TAG"
ผลลัพธ์:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe


ขอบคุณเพียงแค่สะดุดมากกว่านั้นและมันอะไหล่ฉันหนึ่งหรืออื่น ๆ สำหรับเสียงสะท้อนที่ :)
hakre

1
--match "NOT A TAG"การทำงานสำหรับฉันโดยไม่ต้อง ทดสอบในคอมไพล์ 2.18.0 เช่นเดียวกับ 2.7.4 มีสถานการณ์ใดบ้างที่จำเป็นต้องมีการโต้แย้งนี้?
โทมัส

@Thomas มันจะไม่ทำงานหากคุณมีแท็กที่มีคำอธิบายประกอบที่ใดก็ได้ในประวัติศาสตร์ของการกระทำในปัจจุบัน แท็กปลอมทำให้แน่ใจว่าคำสั่งอธิบายไม่ได้ใช้แท็กเพื่ออธิบายการกระทำ
Rado

8
git show-ref --head --hash head

หากคุณต้องการความรวดเร็ววิธีการที่ Deestan พูดถึง

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

เร็วกว่าวิธีอื่นใดที่แสดงไว้ ณ ที่นี้


show-refดูเหมือนว่าฉันจะเป็นตัวเลือกที่ดีที่สุดสำหรับการเขียนสคริปต์เพราะมันเป็นคำสั่งประปาและจึงรับประกัน (หรืออย่างน้อยมีโอกาสมาก) ยังคงมีเสถียรภาพในอนาคต: คำตอบอื่น ๆ ใช้rev-parse, show, describeหรือlogซึ่งเป็นคำสั่งพอร์ซเลนทั้งหมด และในกรณีที่ความเร็วไม่ใช่สาระสำคัญข้อความจากshow-refmanpage จะมีผลบังคับใช้: 'สนับสนุนการใช้โปรแกรมอรรถประโยชน์นี้เพื่อสนับสนุนการเข้าถึงไฟล์โดยตรงภายใต้ไดเรกทอรี. git'
Pont

6

นี่คือซับในเชลล์ Bash โดยใช้การอ่านโดยตรงจากไฟล์ git:

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

คุณต้องเรียกใช้คำสั่งด้านบนในโฟลเดอร์รูท git ของคุณ

วิธีนี้จะมีประโยชน์เมื่อคุณมีไฟล์เก็บข้อมูล แต่gitยังไม่ได้ติดตั้งคำสั่ง

หากไม่ได้ผลให้เช็คอิน.git/refs/headsโฟลเดอร์ว่ามีหัวแบบไหนอยู่


5

ใน home-dir ของคุณในไฟล์ ".gitconfig" เพิ่มดังต่อไปนี้

[alias]
sha = rev-parse HEAD

จากนั้นคุณจะมีคำสั่งที่ง่ายต่อการจดจำ:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600

3

สำหรับ bash git เพียงแค่เรียกใช้ $ git log -1

คุณจะเห็นบรรทัดเหล่านี้ตามคำสั่งของคุณ

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.

0

นี่คืออีกหนึ่งการใช้งานการเข้าถึงโดยตรง:

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

นอกจากนี้ยังใช้งานได้ผ่าน http ซึ่งมีประโยชน์สำหรับการเก็บถาวรแพคเกจในท้องถิ่น (ฉันรู้ว่า: สำหรับเว็บไซต์สาธารณะไม่แนะนำให้ทำให้ไดเรกทอรี. git สามารถเข้าถึงได้):

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


0
cat .git/HEAD

ตัวอย่างผลลัพธ์:

ref: refs/heads/master

แยกมัน

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

หากคุณมี windows คุณอาจพิจารณาใช้ wsl.exe:

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

เอาท์พุท:

refs/heads/master

ค่านี้อาจใช้ในการคอมไพล์เช็คเอาต์ในภายหลัง แต่จะชี้ไปที่ SHA หากต้องการให้ชี้ไปที่สาขาปัจจุบันจริงโดยใช้ชื่อ:

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

ขาออก:

master

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.