Xác định xem thư mục làm việc của Git có sạch khỏi tập lệnh không


83

Tôi có một kịch bản chạy rsyncvới một thư mục làm việc Git là đích. Tôi muốn tập lệnh có hành vi khác nhau tùy thuộc vào việc thư mục làm việc có sạch không (không có thay đổi để cam kết) hay không. Chẳng hạn, nếu đầu ra của git statusnhư dưới đây, tôi muốn tập lệnh thoát:

git status
Already up-to-date.
# On branch master
nothing to commit (working directory clean)
Everything up-to-date

Nếu thư mục không sạch thì tôi muốn nó thực thi thêm một số lệnh.

Làm cách nào để kiểm tra đầu ra như trên trong tập lệnh shell?


Sẽ kiểm tra một trạng thái từ lệnh cuối cùng giúp đỡ ở đây? ($?)
UVV

Bạn có thể cho biết thêm chi tiết xin vui lòng? Ý tưởng chính cho kịch bản của bạn là gì?
tachomi

@tachomi Tôi đã thêm bối cảnh trong bản chỉnh sửa
brentwpeterson

bạn chỉ có thể cho rằng nó không sạch sẽ và làm git reset --hard origin/branchnếu đó là những gì bạn sẽ làm ... giống như nếu bạn đang cố gắng dọn dẹp sau khi biên dịch một cái gì đó, v.v.
SnakeDoc

1
@SnakeDoc Bạn có thể, nhưng tôi giả sử rằng trường hợp nghịch đảo sẽ phổ biến hơn, tức là thoát nếu thư mục làm việc bị bẩn để tránh thay đổi cục bộ. Xem xét cả hai trường hợp sẽ làm cho câu hỏi hữu ích hơn cho độc giả trong tương lai.
Thomas Nyman

Câu trả lời:


134

Phân tích cú pháp đầu ra git statuslà một ý tưởng tồi vì đầu ra được dự định là con người có thể đọc được, không phải máy có thể đọc được. Không có gì đảm bảo rằng đầu ra sẽ giữ nguyên trong các phiên bản Git trong tương lai hoặc trong các môi trường được cấu hình khác nhau.

Nhận xét của UVV đang đi đúng hướng, nhưng thật không may, mã trả về git statuskhông thay đổi khi có những thay đổi không được cam kết. Tuy nhiên, nó cung cấp --porcelaintùy chọn, khiến đầu ra của git status --porcelainđược định dạng theo định dạng dễ phân tích cú pháp cho các tập lệnh sẽ ổn định trên các phiên bản Git và bất kể cấu hình người dùng.

Chúng tôi có thể sử dụng đầu ra trống git status --porcelainlàm chỉ báo rằng không có thay đổi nào được cam kết:

if [ -z "$(git status --porcelain)" ]; then 
  # Working directory clean
else 
  # Uncommitted changes
fi

Nếu chúng ta không quan tâm đến các tệp không bị theo dõi trong thư mục làm việc, chúng ta có thể sử dụng --untracked-files=notùy chọn để bỏ qua các tệp đó:

if [ -z "$(git status --untracked-files=no --porcelain)" ]; then 
  # Working directory clean excluding untracked files
else 
  # Uncommitted changes in tracked files
fi

Để làm cho điều này mạnh mẽ hơn đối với các điều kiện thực sự gây ra git statuslỗi mà không có đầu ra stdout, chúng ta có thể tinh chỉnh kiểm tra thành:

if output=$(git status --porcelain) && [ -z "$output" ]; then
  # Working directory clean
else 
  # Uncommitted changes
fi

Cũng đáng lưu ý rằng, mặc dù git statuskhông cung cấp mã thoát có ý nghĩa khi thư mục làm việc không sạch sẽ, git diffcung cấp --exit-codetùy chọn, làm cho nó hoạt động tương tự như tiện ích diff , nghĩa là thoát khỏi trạng thái 1khi có sự khác biệt và 0khi không tìm thấy.

Sử dụng điều này, chúng tôi có thể kiểm tra các thay đổi chưa được thực hiện với:

git diff --exit-code

và dàn dựng, nhưng không cam kết thay đổi với:

git diff --cached --exit-code

Mặc dù git diffcó thể báo cáo về các tệp không bị theo dõi trong các mô hình con thông qua các đối số thích hợp --ignore-submodules, nhưng thật không may là dường như không có cách nào để báo cáo về các tệp không bị theo dõi trong thư mục làm việc thực tế. Nếu các tệp không bị theo dõi trong thư mục làm việc có liên quan, git status --porcelaincó lẽ là đặt cược tốt nhất.


4
ughhh git status --porcelainsẽ thoát với mã 0 ngay cả khi có những thay đổi không được tổ chức cho các tệp cam kết và không bị theo dõi.
Alexander Mills

Tôi đã quan tâm đến việc xác định trước thời hạn nếu git stashlàm bất cứ điều gì (nó không tạo ra mã trả lại hữu ích). Tôi đã phải thêm --ignore-submodulesvào nếu không git statussẽ chỉ ra những thay đổi mô hình con mà git stashbỏ qua.
Ngõ Devin

1
@AlexanderMills: Tôi quan sát tương tự. Nhưng sau đó kiểm tra những gì if [ -zđang làm. Có -znghĩa là nếu chuỗi sau trống, if ước lượng thành true. Nói cách khác, nếu git status --porcelainkết quả này không có chuỗi, thì repo sạch. Nếu không, nó liệt kê các tệp đã sửa đổi / thêm / xóa và không còn là một chuỗi trống. Sau ifđó đánh giá để false.
Adeynack

19

Sử dụng:

git diff-index --quiet HEAD

Mã trả về phản ánh trạng thái của thư mục làm việc (0 = sạch, 1 = bẩn). Các tập tin không bị theo dõi được bỏ qua.


6
Trả về 0 khi có các tệp không bị theo dõi trong thư mục hiện tại.
Adam Parkin

2
Nếu các tệp đã được chạm / ghi đè nhưng khác với chỉ mục, trước tiên bạn cần chạy git update-index --refreshtrước git diff-index HEAD. Thông tin thêm: stackoverflow.com/q
432807971/1407170

@AdamParkin Tôi chỉ cần thêm tất cả các tệp với git add .trước khi phát hành nó. Thông thường đó là cách để sử dụng nó trong một kịch bản
ceztko

Điều đó thật tuyệt. Lưu ý rằng mã trả về / thoát không khác cũng được hiểu là 'lỗi', nếu bạn đang ở trong tập lệnh có tập -e thì tập lệnh của bạn sẽ thoát nếu 'bẩn'. Điều này có thể tránh được bằng cách thực hiện set +etrước cuộc gọi đến gitvà thêm set -elại sau khi bạn đã đánh giá $?.
orion elenzil

1

Mở rộng nhỏ cho câu trả lời tuyệt vời của André .

Đây là một cách để đánh giá kết quả và cũng tránh cạm bẫy nếu bạn đang ở trong một kịch bản mà trước đây đã ban hành bộ -e .

Các tập tin không bị theo dõi được bỏ qua.

set +e
git diff-index --quiet HEAD

if [ $? == 1 ] ; then
  set -e
  GIT_MODS="dirty"
else
  set -e
  GIT_MODS="clean"
fi
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.