2013-04-30 8 views
19

Trong một câu hỏi trước khi một người nào đó cung cấp một câu trả lời cho việc tìm kiếm các chi nhánh có chứa một CHÍNH XÁC cam kết:Làm thế nào để liệt kê các chi nhánh có chứa tương đương cam

How to list branches that contain a given commit

Câu trả lời được chấp nhận nhấn mạnh rằng điều này chỉ làm việc cho một CHÍNH XÁC cam kết id, và không cho một cam kết giống hệt nhau. Nó đã được nói thêm rằng Git Cherry có thể được sử dụng để giải quyết vấn đề này.

GEM cherry SEEMS được thiết kế để đảo ngược; việc tìm kiếm cam kết KHÔNG bị đẩy ngược dòng. Điều này là vô ích nếu tôi không biết chi nhánh nào đã tạo ra nó và điều gì là thượng nguồn của cái gì. Vì vậy, tôi không thấy nó sẽ giúp giải quyết vấn đề này như thế nào.

Ai đó có thể giải thích/cung cấp ví dụ về cách sử dụng git cherry để tìm tất cả các nhánh có chứa 'tương đương' của một cam kết cụ thể không?

+2

Tôi khuyên bạn nên viết một tập lệnh sử dụng 'git rev-list' và' git patch-id' để xác định điều đó. Bạn cũng có thể muốn phân tích cú pháp các chú thích mà 'git cherry-pick' để lại trong các thư cam kết, vì bản vá-id (cũng là cơ sở của' git cherry') không hoàn hảo và sẽ phá vỡ nếu bạn giải quyết bất kỳ xung đột nào. – Chronial

+0

Không có nghĩa là +1 nhận xét đó: Tôi không biết bạn nói gì hay nó giúp tôi như thế nào. Tôi sử dụng chúng để tạo danh sách? Cho phép giả định xung đột được giải quyết của một ai đó và đồng đội của tôi không đủ thông minh để sử dụng cherrypick -x vì tôi phải chỉ ra cho họ. – UpAndAdam

+1

Vâng, sau đó bạn bị say. Nếu bạn muốn biết chính xác nhánh nào chứa cam kết nào, chỉ sử dụng các kết hợp và không bao giờ chọn cherry.Bạn có thể giả định rằng các cam kết với cùng một thông điệp cam kết có lẽ là giống nhau và làm một số chẩn đoán sôi nổi về sự khác biệt của chúng để xác nhận giả định đó. Nhưng quá trình đó sẽ dễ bị lỗi và bạn sẽ phải tự viết mã đó. – Chronial

Trả lời

13

Trước khi bạn có thể trả lời câu hỏi về chi nhánh nào chứa cam kết tương đương, bạn phải xác định "cam kết tương đương". Một khi bạn có điều đó, bạn chỉ cần sử dụng git branch --contains trên mỗi cam kết.

Thật không may, không có cách nào đáng tin cậy 100% để xác định các cam kết tương đương.

Phương pháp đáng tin cậy nhất là kiểm tra id bản vá của changeset được giới thiệu bởi cam kết. Đây là những gì git cherry, git log --cherrygit log --cherry-mark dựa vào. Trong nội bộ, tất cả họ gọi git patch-id. Id bản vá chỉ là SHA1 của các thay đổi được chuẩn hóa. Bất kỳ cam kết nào giới thiệu các thay đổi giống hệt nhau sẽ có cùng một id bản vá. Ngoài ra, bất kỳ cam kết nào giới thiệu chủ yếu là các thay đổi giống nhau chỉ khác nhau về khoảng trắng hoặc số dòng mà chúng áp dụng trong tệp sẽ có cùng một id bản vá. Nếu hai cam kết có cùng một ID bản vá, nó gần như được đảm bảo rằng chúng tương đương - bạn sẽ hầu như không bao giờ nhận được kết quả dương tính giả thông qua id bản vá. Sai âm tính xảy ra thường xuyên mặc dù. Bất cứ lúc nào bạn làm git cherry-pick và phải tự giải quyết xung đột hợp nhất bạn có thể đã giới thiệu sự khác biệt trong changeset. Ngay cả một thay đổi 1 ký tự sẽ gây ra một bản vá lỗi khác nhau được tạo ra.

Kiểm tra ID bản vá yêu cầu phải có kịch bản như lời khuyên của Chronial. Đầu tiên tính id vá của gốc Cam kết với cái gì đó như

(lưu ý - các kịch bản chưa được thử nghiệm, nên được hợp lý gần làm việc mặc dù)

origCommitPatchId=$(git diff ORIG_COMMIT^! | git patch-id | awk '{print $1}') 

Bây giờ bạn sẽ phải tìm kiếm thông qua tất cả các khác cam kết trong lịch sử của bạn và tính toán ID bản vá cho chúng và xem có bất kỳ ID nào giống nhau hay không.

for rev in $(git rev-list --all) 
do 
    testPatchId=$(git diff ${rev}^1..${rev} | git patch-id | awk '{print $1}') 
    if [ "${origCommitPatchId}" = "${testPatchId}" ]; then 
     echo "${rev}" 
    fi 
done 

Bây giờ bạn có danh sách các Shas, và bạn có thể vượt qua những để git branch -a --contains

gì nếu ở trên không làm việc cho bạn mặc dù, vì xung đột nhập?

Vâng, có một vài điều khác bạn có thể thử. Thông thường khi bạn chọn cherry, hãy chọn cam kết tên của tác giả, email và ngày tháng ban đầu trong cam kết được giữ nguyên. Vì vậy, bạn sẽ nhận được một cam kết mới, nhưng thông tin tác giả sẽ giống nhau.

Vì vậy, bạn có thể nhận được thông tin này từ ban đầu của bạn cam kết với

git log -1 --pretty="%an %ae %ad" ORIG_COMMIT 

Sau đó, như trước đây bạn sẽ phải đi qua tất cả các cam kết trong lịch sử của mình, in thông tin cùng ra và so sánh. Điều đó có thể cung cấp cho bạn một số kết quả trùng khớp bổ sung.

Bạn cũng có thể sử dụng git log --grep=ORIG_COMMIT để tìm bất kỳ cam kết nào tham khảo ORIG_COMMIT trong thông báo cam kết.

Nếu không có tác phẩm nào trong số đó hoạt động, bạn có thể tìm kiếm một dòng cụ thể đã được giới thiệu với cuốc, hoặc có thể git log --grep cho một thứ khác có thể là duy nhất trong thư cam kết.

Nếu tất cả điều này nghe có vẻ phức tạp, đúng vậy. Đó là lý do tại sao tôi bảo mọi người tránh sử dụng lựa chọn anh đào bất cứ khi nào có thể. git branch --contains cực kỳ có giá trị và dễ sử dụng và đáng tin cậy 100%. Không ai trong số các giải pháp khác thậm chí đến gần.

+0

Cảm ơn đây chính là loại điều tôi mong đợi và đang tìm kiếm – UpAndAdam

5

Phần sau có vẻ như hoạt động (nhưng chưa được kiểm tra nhiều). Nó chạy git cherryfor each local git branch và in tên chi nhánh nếu git cherry không liệt kê cam kết bị thiếu trong nhánh.

# USAGE: git-cherry-contains <commit> [refs] 
# Prints each local branch containing an equivalent commit. 
git-cherry-contains() { 
    local sha; sha=$(git rev-parse --verify "$1") || return 1 
    local refs; refs=${2:-refs/heads/} 
    local branch 
    while IFS= read -r branch; do 
     if ! git cherry "$branch" "$sha" "$sha^" | grep -qE "^\+ $sha"; then 
      echo "$branch" 
     fi 
    done < <(git for-each-ref --format='%(refname:short)' $refs) 
} 

Xem Andrew C's post cho một lời giải thích về cách thức git cherry thực sự hoạt động (sử dụng git patch-id).

+0

Sẽ kiểm tra điều này. Tò mò nếu nó sẽ làm việc – UpAndAdam

+1

Cảm ơn!Kịch bản hoạt động tốt, cập nhật nó cũng cho phép chỉ định thư mục ref để tìm kiếm (vì vậy chúng ta có thể tìm kiếm thông qua các tham chiếu ngược dòng): 'git-cherry-contains 0adbcd refs/remotes/origin /'. –

0
$ for i in `git rev-list --all --grep="something unique in the commit message"`; do git branch --all --contains $i; done | sort | uniq 
1

lệnh

Sử dụng lệnh Bash sau (thay thế <COMMIT HASH> với cam kết băm bạn đang tìm kiếm):

PATCH_ID=$(git show <COMMIT HASH> | git patch-id | cut -d' ' -f1) \ 
&& ALL_MATCHING_COMMIT_HASHES=$(git log --all -p | git patch-id | grep $PATCH_ID | cut -d' ' -f2) \ 
&& for HASH in $ALL_MATCHING_COMMIT_HASHES; do echo "$(git branch -a --contains $HASH) (commit $HASH)"; done 

đầu ra Ví dụ

[email protected] test_cherry_picking $ PATCH_ID=$(git show 59faabb91cfc8e449737f93be8c7df3825491674 | git patch-id | cut -d' ' -f1) \ 
&& ALL_MATCHING_COMMIT_HASHES=$(git log --all -p | git patch-id | grep $PATCH_ID | cut -d' ' -f2) \ 
&& for HASH in $ALL_MATCHING_COMMIT_HASHES; do echo "$(git branch -a --contains $HASH) (commit $HASH)"; done 

* hotfix (commit 59faabb91cfc8e449737f93be8c7df3825491674) 
master (commit bb5fa0d16931fa1d5fa9f5e9ee5c27634fad7da8) 

[email protected] test_cherry_picking $ 

Mô tả

Tính PATCH ID cho một GIT REVISION PARAMETER đã cho (ví dụ: băm của một cam kết). Sau đó, tìm tất cả các cam kết với ID PATCH được tính toán. Cuối cùng, tất cả các tên nhánh chứa các cam kết này được in ra bàn điều khiển.

Điều này tất nhiên chỉ hoạt động miễn là ID PATCH giống nhau cho tất cả các cam kết (được chọn bằng dâu tây). Bất cứ lúc nào bạn chọn anh đào và phải tự giải quyết xung đột hợp nhất bạn có thể giới thiệu sự khác biệt trong changeset. Điều này sẽ dẫn đến các ID PATCH khác nhau.