2014-11-17 13 views
31

Tôi muốn đi qua một loạt các cam kết và thực hiện lệnh shell trên mỗi lệnh. Nếu lệnh thất bại, tôi muốn đi bộ để dừng lại, nếu không tiếp tục đi. Tôi đã xem filter-branch, nhưng tôi không muốn viết lại các cam kết, chỉ cần kiểm tra chúng. for-each-ref dường như không cho phép bạn chỉ định phạm vi hoạt động.Lệnh shell chạy Git cho mỗi cam kết

Vấn đề cụ thể của tôi là tôi đã tạo ra một loạt các cam kết và tôi muốn đảm bảo rằng mỗi cam kết đều có thể xây dựng được. Tôi muốn làm điều gì đó như:

git foreach origin/master..master 'git submodule update && make clean && make' 

tôi có thể tất nhiên viết một kịch bản để làm điều này, nhưng nó có vẻ như các loại điều mà git có thể có một cách tốt đẹp để làm.

+0

Bạn đã cân nhắc sử dụng Python chưa? Có lẽ GitPython có thể là một giải pháp. Kiểm tra bài đăng này: http://stackoverflow.com/questions/1456269/python-git-module-experiences – kmundnic

+0

Bạn có biết rằng nguồn gốc/thạc sĩ là tốt và chủ là xấu (hoặc nghịch đảo), hoặc là bạn chỉ cần cố gắng để kiểm tra tất cả mọi thứ giữa chúng mà không biết rằng có tồn tại một sự thất bại tại bất kỳ địa điểm cụ thể? –

+0

@CharlesDuffy, sau này. Tôi bắt đầu từ một điểm làm việc và thực hiện một loạt các thay đổi đã hoạt động. Sau đó, tôi đã thực hiện một số cam kết chi tiết từ đống thay đổi làm việc không được cam kết, và muốn đảm bảo rằng tất cả các cam kết ở giữa đều có thể xây dựng được. – FazJaxton

Trả lời

38

Bạn có thể sử dụng rebase tương tác với một tùy chọn exec.

git rebase -i --exec <build command> <first sha you want to test>~ 

--exec Nối "exec" sau mỗi dòng tạo ra một cam kết trong lịch sử chính thức. sẽ được hiểu là một hoặc nhiều lệnh shell .

Sắp xếp lại và chỉnh sửa các cam kết thường tạo ra các bước trung gian chưa được kiểm tra . Bạn có thể muốn kiểm tra rằng chỉnh sửa lịch sử của bạn không bị ngắt bất kỳ điều gì bằng cách chạy thử nghiệm hoặc ít nhất biên dịch lại tại các điểm trung gian trong lịch sử bằng cách sử dụng lệnh "exec" (phím tắt "x").

Việc rebase tương tác sẽ dừng khi lệnh không thành công (ví dụ: thoát với trạng thái không phải 0) để cho bạn cơ hội khắc phục sự cố.

+0

Phiên bản git tôi bị kẹt với 1.7.10 không có tùy chọn dòng lệnh --exec vì vậy thay vào đó, tôi chèn "x make" theo cách thủ công sau mỗi lệnh chọn và nó đã xử lý. Cảm ơn. –

+0

Bạn có thể cần thêm tùy chọn '-p' &' --preserve-merges', nếu phạm vi của rebase bao gồm các lần hợp nhất. – Unapiedra

+0

~ Cuối cùng là gì? –

16

Bạn có thể muốn rev-list.

#!/usr/bin/env bash 
# test_commits.sh 

while read -r rev; do 
    git checkout "$rev" 
    if ! git submodule update && make clean && make; then 
     >&2 echo "Commit $rev failed" 
     exit 1 
    fi 
done < <(git rev-list "$1") 

Sau đó, bạn có thể sử dụng nó với

./test_commits.sh origin/master..master 
+4

Cần thêm dấu ngoặc kép để tránh việc mở rộng chuỗi và chia nhỏ. '" $ 1 "', '" $ rev "', v.v. Thu thập tất cả các kết quả đầu ra từ 'git rev-list' trước khi tách chuỗi và lặp lại chúng cũng có nghĩa là độ trễ lên phía trước cao hơn' trong khi đọc -r rev; làm ...; thực hiện <<(git rev-list "$ 1") ', luồng này sẽ được đọc trong nội dung khi chúng được đọc thay vì thu thập toàn bộ luồng và phân tích cú pháp nó lên phía trước. (Cách tiếp cận này cũng hiệu quả về bộ nhớ hơn với các danh sách sửa đổi rất lớn, vì những lý do hiển nhiên). –

+2

(Điều đó nói rằng, trong khi có chỗ cho cải tiến xung quanh thực hành tốt nhất shell, đây hoàn toàn là câu trả lời tốt nhất ở đây, và có +1 của tôi). –

+0

@CharlesDuffy - Tôi chưa bao giờ biết về cách phát trực tuyến đó trong nội dung của danh sách khi chúng được đọc - cảm ơn! –

1

Đây là một lớp lót đẹp bằng cách sử dụng xargs.

git rev-list @{upstream}..HEAD | xargs -n1 -I{} sh -c 'git checkout {} && git submodule update && make clean && make' 
+0

Tùy thuộc vào cách xa bạn muốn quay trở lại nó sẽ là tốt để thực hiện một bản sao lưu của '.git/logs/HEAD' trước đó nếu bạn không muốn có một thùng rác lên reflog. – CDanU