2009-10-20 4 views
34

Trong môi trường tập lệnh Unix hoặc GNU (ví dụ: bản phân phối Linux, Cygwin, OSX), cách tốt nhất để xác định xem thanh toán hiện tại là thẻ Git. Nếu đó là một thẻ, làm thế nào tôi có thể xác định tên thẻ?Cách lập trình xác định xem thanh toán Git có phải là thẻ hay không và nếu có, tên thẻ là

Một lần sử dụng kỹ thuật này sẽ tự động gắn nhãn bản phát hành (như svnversion sẽ làm với Subversion).

Xem câu hỏi liên quan của tôi về programmatically detecting the Git branch.

+0

Hãy xem GIT-VERSION-GEN kịch bản (và việc sử dụng nó trong Makefile) trong kho git: http://git.kernel.org/?p=git/git.git;a=blob;f=GIT-VERSION-GEN;hb=HEAD –

+0

@jhs: Tôi đã upvoted Greg Hewgill trả lời . Tôi đã downvoted câu trả lời dựa trên 'git name-rev' bởi vì nó có thể trở lại ví dụ: 'some-tag ~ 5' và câu trả lời dựa trên sự kết hợp của 'git log' và' git tag -l' vì nó là xấu và không hiệu quả. –

Trả lời

36

Giải pháp cho câu hỏi của bạn là sử dụng

git describe --exact-match HEAD 

(mà sẽ xem xét chỉ chú thích thẻ, nhưng bạn nên sử dụng chú thích và có lẽ thậm chí ký thẻ cho gắn thẻ phát hành).

Nếu bạn muốn xem xét tất cả các thẻ, cũng nhẹ thẻ (mà thường được sử dụng để gắn thẻ địa phương), bạn có thể sử dụng --tags tùy chọn:

git describe --exact-match --tags HEAD 

Nhưng tôi nghĩ rằng bạn có " XY problem "ở đây, trong đó bạn đang đặt câu hỏi về giải pháp có thể cho vấn đề, thay vì đặt câu hỏi về một vấn đề ... có thể có giải pháp tốt hơn.

Giải pháp cho vấn đề của bạn là để có một cái nhìn như thế nào Git hiện nó trong GIT-VERSION-GEN kịch bản, và làm thế nào nó sử dụng nó trong Makefile của nó.

+2

Jakub, với tất cả sự tôn trọng, đề xuất của bạn về quy trình phát hành của tôi và suy đoán của bạn về vấn đề thực sự của tôi, đều không liên quan. Tuy nhiên, cảm ơn vì giải pháp kỹ thuật của bạn. – JasonSmith

+0

Thật không may, giải pháp của bạn không hiệu quả đối với tôi. 'git description - khớp chính xác HEAD' =>' gây tử vong: không có thẻ khớp chính xác '...'. Tôi tin rằng bạn cần thêm '--tags' vào các tham số. – JasonSmith

+0

@jhs: Wbout 'git description - khớp chính xác HEAD' so với' git describe --exact-match --tags HEAD': Tùy chọn '--tags' sẽ chỉ cần thiết nếu bạn sử dụng các thẻ nhẹ. Chúng tôi khuyên bạn nên sử dụng các thẻ đã ký (là các thẻ được chú thích, nghĩa là các đối tượng thẻ) để gắn thẻ các bản phát hành. –

-2

Đây là tập lệnh trình bao ngắn gọn (được kiểm tra trong Bash, không được xác nhận nếu nó hoạt động trên tro, v.v.). Nó sẽ đặt biến số git_tag thành tên của thẻ hiện được kiểm tra hoặc để trống nếu thanh toán không được gắn thẻ.

git_tag='' 
this_commit=`git log --pretty=format:%H%n HEAD^..` 

for tag in `git tag -l`; do 
    tag_commit=`git log --pretty=format:%H%n tags/$tag^..tags/$tag` 
    if [ "$this_commit" = "$tag_commit" ]; then 
    # This is a tagged commit, so use the tag. 
    git_tag="$tag" 
    fi 
done 

Comment by Jakub Narębski:

Giải pháp này giảm để lặp qua tất cả các thẻ, và kiểm tra nếu chúng trỏ tới corrent cam kết, ví dụ: đối tượng được trỏ bởi HEAD. Sử dụng các lệnh hệ thống ống nước, tức là các lệnh dành cho tập lệnh, điều này có thể được viết là:

this_commit=$(git rev-parse --verify HEAD) 
git for-each-ref --format="%(*objectname) %(refname:short)" refs/tags/ | 
while read tagged_object tagname 
do 
    if test "$this_commit" = "$tagged_object" 
    then 
     echo $tagname 
    fi 
done 

Điều này sẽ in tất cả các thẻ trỏ đến cam kết hiện tại.

+0

Sử dụng "git rev-parse HEAD" để nhận được SHA-1 của cam kết hiện tại, không cần giải pháp phức tạp với git-log. Sử dụng git-for-each-ref thay vì giải pháp phức tạp với "git tag -l" và "git log" (và thậm chí không "git show"). Sử dụng "git describe" để trả lời câu hỏi otiginal. Sử dụng GIT-VERSION-GEN để giải quyết vấn đề. –

2

Một giải pháp tốt hơn (từ câu trả lời Greg Hewgill trong các câu hỏi khác) sẽ là:

git name-rev --name-only --tags HEAD 

Nếu nó trả "không xác định", sau đó bạn không sử dụng thẻ. Nếu không, nó sẽ trả về tên thẻ. Vì vậy, một lớp lót để làm một cái gì đó giống như câu trả lời khác của tôi sẽ là:

git_tag=`git name-rev --name-only --tags HEAD | sed 's/^undefined$//'` 

dụ vỏ tương tác của cách hoạt động:

$ git checkout master 
Already on "master" 
$ git name-rev --name-only --tags HEAD 
undefined 
$ git checkout some-tag 
Note: moving to "some-tag" which isnt a local branch 
If you want to create a new branch from this checkout, you may do so 
(now or later) by using -b with the checkout command again. Example: 
    git checkout -b <new_branch_name> 
HEAD is now at 1234567... Some comment blah blah 
$ git name-rev --name-only --tags HEAD 
some-tag 
+2

Điều này sẽ không hoạt động chính xác nếu HEAD có thể truy cập ** từ thẻ (ví dụ: thông qua một số chi nhánh khác đến trước chi nhánh hiện đã được kiểm tra), nhưng không nằm trên chính thẻ. Bạn sẽ nhận được kết quả như: "some-tag ~ 3" –

+0

Ngoài ra, để được nitpicky, có thể có một thẻ có tên là 'undefined' ... –

5

Cách tốt nhất để làm điều này là sử dụng lệnh git describe:

git-mô tả - Hiển thị thẻ gần đây nhất mà có thể truy cập từ một cam kết

lệnh tìm thẻ gần đây nhất có thể truy cập từ cam kết. Nếu thẻ trỏ đến cam kết thì chỉ thẻ được hiển thị. Nếu không, nó sẽ gắn thẻ tên với số lượng các cam kết bổ sung trên đầu đối tượng được gắn thẻ và tên đối tượng viết tắt của lần commit gần đây nhất.

+0

Cảm ơn. git-mô tả dường như không dễ sử dụng trong một kịch bản shell cho mục tiêu cụ thể này so với git-name-rev. – JasonSmith

+0

Tôi nói rằng bởi vì, trước tiên git-mô tả lỗi khi chạy trên một chi nhánh không có đối số. Bạn có gợi ý 'git-description --tags' không? Nhưng quan trọng hơn nó không phải là tầm thường để nói cho dù bạn đang ở trên một thẻ thích hợp hay không. Bạn sẽ phải phân tích đầu ra và tìm dấu gạch nối. Nhưng điều gì sẽ xảy ra nếu tên thẻ có phần mềm trong đó? Vì lý do đó, tôi thích 'git name-ref --name-only --tags HEAD' – JasonSmith

+0

Đủ công bằng, tôi cho rằng tùy chọn tốt nhất phụ thuộc vào ứng dụng cụ thể của bạn. Tôi đã sử dụng 'git description' trong quá khứ để tự động gắn nhãn một bản phát hành. –

4

Sử dụng git-tên-rev được ưa thích cho các kịch bản, vì nó là một phần của git ống nước, trong khi git-mô tả là một phần của sứ.

Sử dụng lệnh này để in tên của thẻ nếu HEAD trỏ đến một thẻ, nếu không thì không có gì.

git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed -n 's/^\([^^~]\{1,\}\)\(\^0\)\{0,1\}$/\1/p' 

Note chuyển hướng của stderr đến/dev/null - nếu không bạn sẽ nhận được một thông báo lỗi nói:

fatal: cannot describe 'SOMESHA'" 

EDIT: Cố định regex trong sed để hỗ trợ cả hai lighweight và chú thích/thẻ đã ký.

2

Bạn không thể xác định liệu thanh toán hiện tại “là thẻ” hay không. Bạn chỉ có thể xác định xem thanh toán hiện tại có phải là cam kết có thẻ không.

Sự khác biệt là: nếu có một số thẻ trỏ đến cam kết này, git không thể cho bạn biết bạn đã sử dụng để thanh toán, cũng như nếu bạn thực sự đã sử dụng để truy cập.

Jakub’s answer here dựa trên git describe --exact-match (--tags) cung cấp cho bạn “đầu tiên” của tất cả các thẻ (chú thích).

git describe sắp xếp chúng như thế này:

  • thẻ chú thích đầu tiên
    • sắp xếp út đầu tiên
  • thẻ nhẹ đến sau
    • nhị phân được sắp xếp theo tên thẻ (mà có nghĩa là theo thứ tự bảng chữ cái nếu nó được mã hóa bằng tiếng Anh ASCII)
    • git không lưu trữ siêu dữ liệu với các thẻ nhẹ, vì vậy “út-đầu tiên” không thể thực hiện