2016-07-27 16 views
5

Cho một tệp ngẫu nhiên, có phương pháp kinh điển nào để xác định từ dòng lệnh cho dù tệp thuộc về một cam kết cụ thể không?Tìm git commit một tập tin nào?

Điều này tương tự như câu hỏi tràn ngăn xếp find-out-which-git-commit-a-file-was-taken-from ngoại trừ việc tôi muốn có thể sử dụng nó trong tập lệnh và cũng không tạo nhánh tạm thời.

+0

@ Vì lý do tôi hỏi là (với git) tôi luôn nghi ngờ có một số lệnh như "git ls-tree --do-something-magic thực hiện chính xác những gì tôi muốn. Giống như khi tôi phát hiện" git hash- đối tượng "phút sau khi viết một máy tính git sha-1 tiện dụng bằng Python! – Xevious

+1

Ví dụ sẽ là khi ai đó gửi tệp cấu hình (được truy xuất từ ​​phần cứng) lên các tầng hỗ trợ cho đến khi nó được gửi cho một bài đăng hoặc chẩn đoán. Trong những ngày quay lại, chúng tôi đã sử dụng mở rộng từ khóa RCS (và cuối cùng là CVS) cho mục đích này. Tôi khá chắc chắn rằng chúng ta có thể sử dụng commit và checkout hooks để thêm mở rộng từ khóa giả, nhưng nó là một kludge mà tôi – Xevious

+1

Liên kết gợi ý và rõ ràng từ nhận xét thứ 2 của bạn, rằng bạn đang nói về một tệp không phải là một phần của cây đang hoạt động của bạn - nhưng e câu hỏi chính nó không nói rằng. Có vẻ như bạn đang yêu cầu 'git log -1 - $ filename' (có thể với một số nhầm lẫn về ý nghĩa của" thuộc về "). Bạn có thể rephrase nó một chút? – trentcl

Trả lời

2

Dưới đây là đoạn trích của tập lệnh mà tôi đã sử dụng cho mục đích này. Tôi đã tấn công nó bằng cách sử dụng kiến ​​thức git giới hạn của tôi và các phần của các tập lệnh khác mà tôi đã tìm thấy trên web. Nó hoạt động đủ tốt, nhưng tôi thường thấy rằng có những cách dễ dàng hơn để làm những điều trong git hơn những gì tôi đã học được bằng cách thử và sai.

FILE=$1 

# git hash for file 
HASH=`git hash-object $FILE` 

# git revisions for file 
REVS=`git log --pretty=%H -- $FILE` 

# check each revision for checksum match 
for rev in $REVS; do 
    POSSIBLE=`git ls-tree $rev $FILE | awk '{print $3}'` 
    if [[ $HASH == $POSSIBLE ]]; then 
     echo $rev 
    fi 
done 
+2

Khác với thay đổi 'git log --pretty = ...' thành 'git rev-list --all - $ FILE' Tôi sẽ không thay đổi bất cứ điều gì về câu trả lời của bạn. –

1

Ý của bạn là, tệp có được sửa đổi trong cam kết không? Nếu vậy, một cái gì đó như git log --oneline -- filePathName nên liệt kê các cam kết từ HEAD trong trường hợp đó.

Khi đọc lần hai, tôi nghĩ bạn chỉ yêu cầu các cam kết chứa tệp đó, cho dù có thay đổi hay không. Nếu vậy, sau đó không ls-tree của bạn cần một lá cờ -r, để recurse vào cây con của nó (subdirs)? mà sẽ tìm thấy bất kỳ bản sao của một tập tin dưới bất kỳ tên nào, nếu bạn chỉ phù hợp trên sha.

+1

Điều đó dường như trả về tất cả các cam kết liên quan đến tên tệp đó - nhưng không phải là cam kết cụ thể có chứa tệp ở trạng thái chính xác mà nó đang ở tại thời điểm này. – Xevious

+0

ah, ok, vì vậy bạn đang tìm kiếm một kết hợp chính xác của tập tin đó. Vì vậy, vẫn còn, bạn không nên đệ quy (ở trên) và tìm kiếm một trận đấu của mỗi blob của shas với sha của tập tin bạn đang cố gắng để phù hợp với? – DavidN

1

Your approach có thể thất bại để làm việc trong trường hợp chênh lệch không đáng kể (ví dụ phong cách dòng kết thúc, hoặc chênh lệch do để làm sạch bộ lọc/smudge) giữa các phiên bản địa phương và kho của tập tin.

Tập lệnh sau hoạt động qua git diff thay vì dựa vào băm. Nó chấp nhận các tùy chọn khác sau tên tệp.

ví dụ sử dụng:

# list all commits that introduce the file README.md in its local state 
list_introducing_commits README.md 

# list all commits that introduce the file README.md in its local state 
# ignoring any difference in whitespace 
list_introducing_commits README.md -w 

list_introducing_commits (không thể tìm thấy một tên tốt hơn):

#!/bin/bash 

if [ $# -eq 0 ] 
then 
    echo "Usage: $(basename $0) path/to/file [<diff-options>]" 
    exit 1 
fi 

file="$1" 
shift 1 

for rev in $(git log --pretty=%H -- "$file") 
do 
    if git diff --exit-code [email protected] $rev -- $file &> /dev/null 
    then 
     echo $rev 
    fi 
done 
1

xây dựng trên DavidN 's answer, nếu tập tin là trong hiện tại worktree và worktree được đồng bộ với HEAD, điều này sẽ giúp bạn có được cam kết tương ứng với nội dung hiện tại của tệp:

git log --pretty="%H" -1 -- path/to/file 

Nhưng bạn có thể muốn kiểm tra các giả định đó trước thông qua "git diff --exit-code /path/to/file" và xem nhanh $?.

Các vấn đề liên quan