Làm cách nào để lấy lại hàm băm cho cam kết hiện tại trong Git?


1934

Tôi muốn giữ lại (hiện tại) khả năng liên kết các thay đổi Git với các workitem được lưu trữ trong TFS.

Tôi đã viết một công cụ (sử dụng hook từ Git) trong đó tôi có thể đưa các trình xác định công việc vào thông điệp của bộ thay đổi Git.

Tuy nhiên, tôi cũng muốn lưu trữ định danh của cam kết Git (hàm băm) vào trường công việc TFS tùy chỉnh. Bằng cách này, tôi có thể kiểm tra một workitem trong TFS và xem những thay đổi Git nào được liên kết với workitem.

Làm cách nào tôi có thể dễ dàng truy xuất hàm băm từ cam kết hiện tại từ Git?

Câu trả lời:


2810

Để bật tùy ý tham chiếu đối tượng mở rộng vào SHA-1, sử dụng đơn giản git-rev-phân tích cú pháp , ví dụ

git rev-parse HEAD

hoặc là

git rev-parse --verify HEAD

Sidenote: Nếu bạn muốn biến các tham chiếu ( các nhánh thẻ ) thành SHA-1, cógit show-refgit for-each-ref.


81
--verifyngụ ý rằng:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck

648
git rev-parse --short HEADtrả về phiên bản ngắn của hàm băm, chỉ trong trường hợp có ai thắc mắc.
Thane Brimhall

55
Thêm vào những gì Thane nói, bạn cũng có thể thêm một độ dài cụ thể vào --short, chẳng hạn như --short=12, để có được một số chữ số cụ thể từ hàm băm.
Tyson Phalp

32
@TysonPhalp: --short=Nlà về số lượng chữ số tối thiểu ; git sử dụng số chữ số lớn hơn nếu rút ngắn một chữ số sẽ không thể phân biệt được với các cam kết khác được rút ngắn. Hãy thử ví dụ git rev-parse --short=2 HEADhoặc git log --oneline --abbrev=2.
Jakub Narębski

36
Thêm vào những gì Thane, Tyson và Jakub đã nói, bạn có thể in băm đầy đủ, nhưng làm nổi bật các hình lục giác cần thiết để xác định màu xanh cam kết vớigit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz

424

Nếu bạn chỉ muốn băm rút ngắn:

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

Hơn nữa, sử dụng% H là một cách khác để có được hàm băm dài.


107
Hoặc, có vẻ như, thêm --short vào lệnh rev-parse ở trên dường như hoạt động.
outofcocate

15
Tôi nghĩ git loglà sứ và git rev-parselà hệ thống ống nước.
Amedee Van Gasse

Một trong những lợi ích của phương pháp này là nó sẽ trả về phiên bản băm ngắn với độ dài phù hợp được điều chỉnh theo các va chạm băm xảy ra đối với các repos lớn hơn. Ít nhất là trong các phiên bản gần đây của git.
Ilia Sidorenko

4
Đây là một cách làm xấu / không chính xác bởi vì phương pháp này sẽ cung cấp cho bạn hàm băm sai nếu bạn có một cái đầu tách ra. Ví dụ: nếu cam kết hiện tại là 12ab34 ... và cam kết trước đó là 33aa44 ... thì nếu tôi thực hiện 'kiểm tra git 33aa44' và sau đó tôi chạy lệnh của bạn, tôi vẫn sẽ quay lại 12ab34 ... mặc dù đầu tôi thực sự chỉ đến 33aa44 ...
theQuestionMan

3
@theQuestionMan Tôi không trải nghiệm hành vi bạn mô tả; git checkout 33aa44; git log -n 1mang lại cho tôi 33aa44. Phiên bản nào của git bạn đang sử dụng?
outofcocate

150

Một số khác, sử dụng nhật ký git:

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

Nó rất giống với @outofcARM mặc dù ngắn hơn một chút.


Và kết quả không phải là trích dẫn đơn.
crokusek

5
Đây là câu trả lời đúng, vì nó hoạt động ngay cả khi bạn kiểm tra một cam kết cụ thể thay vì HEAD.
Parsa

1
@Parsa: khi kiểm tra một điểm cam kết cụ thể HEADđối với cam kết này chứ không phải là một nhánh có tên gọi là đầu tách ra .
ChristofSenn

125

Để có được SHA đầy đủ:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Để có được phiên bản rút gọn:

$ git rev-parse --short HEAD
cbf1b9a

Nếu cần hai hàm git commitbăm, chẳng hạn như một hàm băm mà bạn branchhiện đang làm việc và a master branch, bạn cũng có thể sử dụng git rev-parse FETCH_HEADnếu bạn cần hàm băm cho cái master commitmà bạn mergenhập vào hiện tại branch. ví dụ: nếu bạn có branches masterfeature/new-featurecho một repo nhất định., trong khi trên feature/new-featurebạn có thể sử dụng git fetch origin master && git merge FETCH_HEADvà sau đó git rev-parse --short FETCH_HEADnếu bạn cần commithàm băm từ masterbạn chỉ cần nhập mergevào bất kỳ tập lệnh nào bạn có thể có.
EVAL

72

Để cho đầy đủ, vì không ai đã đề nghị nó. .git/refs/heads/masterlà một tệp chỉ chứa một dòng: hàm băm của cam kết mới nhất trên master. Vì vậy, bạn chỉ có thể đọc nó từ đó.

Hoặc, như lệnh:

cat .git/refs/heads/master

Cập nhật:

Lưu ý rằng git hiện hỗ trợ lưu trữ một số refs trong tệp pack-ref thay vì như một tệp trong thư mục / refs / Heads /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html


10
Điều này giả định chi nhánh hiện tại masterlà không đúng.
gavrie

12
Thật. Đó là lý do tại sao tôi nói rõ ràng điều này là dành cho master.
Deestan

20
.git/HEADthông thường chỉ đến một ref, nếu bạn có SHA1 ở đó, bạn đang ở chế độ đầu tách rời.
eckes

8
Điều này không mạnh lắm so với các cách tiếp cận khác, đặc biệt bởi vì nó giả định rằng có một .gitthư mục con, điều này không nhất thiết phải như vậy. Xem --separate-git-dircờ trong git inittrang người đàn ông.
jub0bs

16
1 bởi vì đôi khi bạn không muốn thực thi git cài đặt (ví dụ trong Dockerfile của bạn)
wim

50

Cam kết băm

git show -s --format=%H

Chữ viết tắt cam kết băm

git show -s --format=%h

Nhấn vào đây để biết thêm git showví dụ.


50

Luôn luôn có git describenhư vậy. Theo mặc định, nó mang lại cho bạn -

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

18
Mô tả Git trả về TAG đầu tiên có thể truy cập từ một cam kết. Làm thế nào điều này giúp tôi có được SHA?
Sardaukar

42
Tôi thích git describe --long --dirty --abbrev=10 --tagsnó sẽ cung cấp cho tôi một cái gì đó giống như 7.2.0.Final-447-g65bf4ef2d4là 447 cam kết sau thẻ 7.2.0.Final và 10 thông báo đầu tiên của SHA-1 toàn cầu tại HEAD hiện tại là "65bf4ef2d4". Điều này là rất tốt cho chuỗi phiên bản. Với --long, nó sẽ luôn thêm số đếm (-0-) và hàm băm, ngay cả khi thẻ xảy ra khớp chính xác.
eckes

14
Nếu không có thẻ nào tồn tại thì git describe --alwayssẽ "hiển thị đối tượng cam kết được viết tắt duy nhất là dự phòng"
Ronny Andersson

Tôi sử dụng git describe --tags --first-parent --abbrev=11 --long --dirty --always. Các --alwaystùy chọn có nghĩa là nó cung cấp một kết quả (băm) ngay cả khi không có thẻ. Điều --first-parentđó có nghĩa là nó không bị lẫn lộn bởi các cam kết hợp nhất và chỉ theo sau các mục trên nhánh hiện tại. Cũng lưu ý rằng --dirtysẽ thêm -dirtyvào kết quả nếu chi nhánh hiện tại có những thay đổi không được cam kết.
ingyhere

30

Sử dụng git rev-list --max-count=1 HEAD


3
git-rev-list là về việc tạo danh sách các đối tượng cam kết; đó là git-rev-parse để dịch tên đối tượng (ví dụ: ĐẦU) sang SHA-1
Jakub Narębski

21

Nếu bạn cần lưu trữ hàm băm trong một biến trong tập lệnh, bạn có thể sử dụng

last_commit=$(git rev-parse HEAD)

Hoặc, nếu bạn chỉ muốn 10 ký tự đầu tiên (như github.com)

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

26
Ngoài ra còn có --shorthoặc --short=numbertham số để git rev-parse; không cần phải sử dụng một đường ống và cut.
Julian D.

15

Nếu bạn muốn cách siêu hacky để làm điều đó:

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

Về cơ bản, git lưu trữ vị trí của CHÍNH trong .git / HEAD, dưới dạng ref: {path from .git}. Lệnh này đọc nó ra, cắt bỏ "ref:" và đọc bất kỳ tập tin nào nó trỏ đến.

Tất nhiên, điều này sẽ thất bại ở chế độ tách rời, vì ĐẦU sẽ không phải là "ref: ...", nhưng bản thân hàm băm - nhưng bạn biết đấy, tôi không nghĩ rằng bạn mong đợi nhiều thông tin trong bash của bạn -liners. Nếu bạn không nghĩ dấu chấm phẩy là gian lận, mặc dù ...

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

1
Không cần cài đặt git, tôi thích nó. (hình ảnh bản dựng docker của tôi không có git)
Helin Wang

cũng hữu ích vì bạn có thể chạy nó dễ dàng từ bên ngoài repo git
samaspin

Tôi chính thức hóa nó thành một kịch bản cho máy cục bộ của tôi. Sau đó, tôi nghĩ, này: cách triển khai tôi thực hiện đủ đơn giản để minh họa cách giải quyết vấn đề không liên quan (phân tích đối số trong tập lệnh shell POSIX thô mà không có chương trình bên ngoài), nhưng đủ phức tạp để cung cấp một chút biến thể và khai thác hầu hết tính năng của sh. Nửa giờ của ý kiến tài liệu sau, và đây là một Gist của nó: gist.github.com/Fordi/29b8d6d1ef1662b306bfc2bd99151b07
Fordi

Nhìn vào nó, tôi đã tạo ra một phiên bản mở rộng hơn để phát hiện Git và SVN, và lấy bản sửa đổi git hash / svn. Không phải là một chuỗi sạch thời gian này, nhưng dễ dàng dòng lệnh phân tích cú pháp, và có thể sử dụng như một thẻ phiên bản: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi

14

Cách cô đọng nhất mà tôi biết:

git show --pretty=%h 

Nếu bạn muốn một số chữ số cụ thể của hàm băm, bạn có thể thêm:

--abbrev=n

14
Trong khi kỹ thuật này hoạt động, git showlà những gì được gọi là lệnh sứ (tức là hướng tới người dùng), và do đó không nên được sử dụng trong các tập lệnh vì đầu ra của nó có thể thay đổi. Câu trả lời ở trên ( git rev-parse --short HEAD) nên được sử dụng thay thế.
jm3

4
@ jm3 đó là ngược. Các lệnh "Sứ" có đầu ra ổn định dành cho các tập lệnh. Tìm kiếm git help showcho porcelain.
John Tyree

2
@JohnTyree Đây là một chủ đề khó hiểu, nhưng jm3 đã đúng: các lệnh sứ không có nghĩa là được phân tích cú pháp, mà là có thể đọc được. Trong trường hợp bạn cần sử dụng lệnh sứ trong tập lệnh và bạn muốn có định dạng ổn định, đôi khi (ví dụ với trạng thái git, đẩy và đổ lỗi) một tùy chọn thực hiện điều đó. Thật không may, tùy chọn đó được gọi --porcelain, đó là lý do tại sao điều này gây nhầm lẫn. Bạn có thể tìm thấy các chi tiết trong câu trả lời tuyệt vời này của VonC
Fabio nói Phục hồi lại

1
Chúa ơi, người quyết định đặt tên cho tùy chọn đó - công ty tôi muốn tìm chúng và ... oh chờ tôi cần sử dụng git để tìm thấy chúng không bao giờ
Britton Kerin

14

Có lẽ bạn muốn có một bí danh để bạn không phải nhớ tất cả các chi tiết tiện lợi. Sau khi thực hiện một trong các bước dưới đây, bạn sẽ có thể chỉ cần gõ:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Theo dõi câu trả lời được chấp nhận , đây là hai cách để thiết lập câu trả lời này:

1) Dạy git cách rõ ràng bằng cách chỉnh sửa cấu hình chung (câu trả lời ban đầu của tôi):

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

2) Hoặc nếu bạn thích một phím tắt để dạy git một phím tắt, như nhận xét gần đây của Adrien:

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

Từ đây về sau, sử dụng git lastcommitđể hiển thị hàm băm cuối cùng.


3
Adrien de Sentenac ghi chú rằng thay vì bằng tay chỉnh sửa các tập tin git config, bạn có thể chỉ cần làm:git config --global alias.lastcommit "rev-parse HEAD"
cgmb

12

Tôi cần một cái gì đó khác hơn một chút: hiển thị đầy đủ sha1 của cam kết, nhưng nối một dấu sao vào cuối nếu thư mục làm việc không sạch. Trừ khi tôi muốn sử dụng nhiều lệnh, không có tùy chọn nào trong các câu trả lời trước hoạt động.

Đây là một lớp lót:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Kết quả:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Giải thích: mô tả (sử dụng các thẻ chú thích) cam kết hiện tại, nhưng chỉ với các thẻ có chứa "KHÔNG PHẢI". Vì các thẻ không thể có khoảng trắng, nên điều này không bao giờ khớp với thẻ và vì chúng tôi muốn hiển thị kết quả --always, lệnh sẽ quay lại hiển thị đầy đủ ( --abbrev=0) sha1 của cam kết và nó sẽ thêm dấu hoa thị nếu thư mục làm việc là --dirty.

Nếu bạn không muốn nối dấu hoa thị, thì lệnh này hoạt động giống như tất cả các lệnh khác trong các câu trả lời trước:
git describe --always --abbrev=0 --match "NOT A TAG"
Kết quả:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe


Cảm ơn, chỉ cần vấp phải nó và nó cho tôi một tiếng vang khác cho điều đó :)
hakre

1
Nó làm việc cho tôi mà không có --match "NOT A TAG". Đã thử nghiệm trong git 2.18.0 cũng như 2.7.4. Có bất kỳ tình huống mà tranh luận này là cần thiết?
Thomas

@Thomas nó sẽ không hoạt động nếu bạn có một thẻ chú thích ở bất cứ đâu trong lịch sử của cam kết hiện tại. Thẻ giả đảm bảo rằng lệnh mô tả không sử dụng thẻ để mô tả cam kết,
Rado

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

Nếu bạn đang đi cho tốc độ, cách tiếp cận được đề cập bởi Deestan

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

là nhanh hơn đáng kể so với bất kỳ phương pháp khác được liệt kê ở đây cho đến nay.


show-refDường như với tôi là lựa chọn tốt nhất cho kịch bản, vì nó là một lệnh hệ thống ống nước và do đó đảm bảo (hoặc ít nhất là rất có khả năng) để duy trì ổn định trong phiên bản tương lai: câu trả lời khác sử dụng rev-parse, show, describe, hoặc log, đó là tất cả các lệnh sứ. Và trong trường hợp tốc độ không phải là điều cốt yếu, lưu ý từ show-reftrang này được áp dụng: 'Sử dụng tiện ích này được khuyến khích ủng hộ truy cập trực tiếp vào các tệp trong thư mục .git.'
Pont

6

Đây là một lớp trong vỏ Bash sử dụng đọc trực tiếp từ các tệp git:

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

Bạn cần chạy lệnh trên trong thư mục gốc git của bạn.

Phương pháp này có thể hữu ích khi bạn lưu trữ tệp, nhưng gitlệnh chưa được cài đặt.

Nếu không hoạt động, hãy kiểm tra trong .git/refs/headsthư mục những loại đầu bạn có mặt.


5

trong thư mục nhà của bạn trong tệp ".gitconfig" thêm vào như sau

[alias]
sha = rev-parse HEAD

sau đó bạn sẽ có một lệnh dễ nhớ hơn:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600

3

Trên git bash, chỉ cần chạy $ git log -1

bạn sẽ thấy, những dòng này theo lệnh của bạn.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.

0

Đây là một thực hiện truy cập trực tiếp khác:

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

Điều này cũng hoạt động trên http rất hữu ích cho việc lưu trữ gói cục bộ (tôi biết: đối với các trang web công cộng, không nên truy cập thư mục .git):

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

0

Đây là một cách khác để làm điều đó với :)

git log | grep -o '\w\{8,\}' | head -n 1

0
cat .git/HEAD

Ví dụ đầu ra:

ref: refs/heads/master

Phân tích nó:

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

Nếu bạn có windows thì bạn có thể cân nhắc sử dụng wsl.exe:

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

Đầu ra:

refs/heads/master

Giá trị này có thể được sử dụng để kiểm tra git sau nhưng nó trở thành trỏ đến SHA của nó. Để làm cho nó trỏ đến nhánh hiện tại bằng tên của nó, hãy làm:

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

Đầu ra:

master

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.