Làm thế nào để kiểm tra nếu không có gì để cam kết trong chi nhánh hiện tại?


172

Mục tiêu là để có được một trạng thái rõ ràng có thể được đánh giá trong một lệnh shell.

Tôi đã thử git statusnhưng nó luôn trả về 0, ngay cả khi có các mục cần cam kết.

git status
echo $?  #this is always 0

Tôi có một ý tưởng nhưng tôi nghĩ nó là một ý tưởng tồi.

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

bất kỳ cách nào khác?


cập nhật với giải quyết sau đây, xem bài viết của Mark Longair

Tôi đã thử điều này nhưng nó gây ra một vấn đề.

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

Tôi nhận được lỗi sau đây [: ??: binary operator expected

Bây giờ, tôi đang nhìn người đàn ông và thử git diff.

=================== mã cho hy vọng của tôi và hy vọng câu trả lời tốt hơn ======================

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

4
Trong phần cập nhật, có vẻ như bạn không thực sự làm những gì eckes gợi ý trong câu trả lời của anh ấy - như anh ấy nói, bạn cần đặt dấu ngoặc kép xung quanh $(git status --porcelain). Ngoài ra, nếu bạn muốn đặt dấu chấm than trong tin nhắn của mình, bạn sẽ cần sử dụng dấu ngoặc đơn thay vì dấu ngoặc kép - nghĩa là echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'thay vào đó
Mark Longair

4
như Mark nói: bạn cần đặt dấu ngoặc kép xung quanh$(git status --porcelain) , giống như tôi đã nói với bạn!
eckes

1
Câu hỏi này sẽ hữu ích hơn rất nhiều, nếu nó không bao gồm các phần của câu trả lời.
oberlies

@ 9nix00 làm những gì bạn đã được thông báo và chỉnh sửa và sửa lỗi trong tập lệnh shell của bạn ở trên: BUG: if [-z $ (một số lệnh)] FIX: if [-z "$ (một số lệnh)"]
MarcH

Câu trả lời:


232

Một cách khác để kiểm tra xem đầu ra git status --porcelaincó trống hay không là kiểm tra từng điều kiện bạn quan tâm riêng. Chẳng hạn, người ta có thể không quan tâm, ví dụ, nếu có các tệp không được theo dõi trong đầu ra của git status.

Ví dụ: để xem có bất kỳ thay đổi cục bộ nào không, bạn có thể xem mã trả về của:

git diff --exit-code

Để kiểm tra xem có bất kỳ thay đổi nào được dàn dựng nhưng không được cam kết hay không, bạn có thể sử dụng mã trả về của:

git diff --cached --exit-code

Cuối cùng, nếu bạn muốn biết liệu có bất kỳ tệp nào không bị theo dõi trong cây làm việc của bạn không bị bỏ qua hay không, bạn có thể kiểm tra xem đầu ra của lệnh sau có trống không:

git ls-files --other --exclude-standard --directory

Cập nhật: Bạn hỏi bên dưới liệu bạn có thể thay đổi lệnh đó để loại trừ các thư mục trong đầu ra. Bạn có thể loại trừ các thư mục trống bằng cách thêm --no-empty-directory, nhưng để loại trừ tất cả các thư mục trong đầu ra đó tôi nghĩ bạn sẽ phải lọc đầu ra, chẳng hạn như với:

git ls-files --other --exclude-standard --directory | egrep -v '/$'

Các -vđể egrepphương tiện để chỉ dòng đầu ra mà không phù hợp với mô hình và mô hình phù hợp với bất kỳ dòng kết thúc với một /.


Tôi nghiêng những lời khuyên này và có một vấn đề. có nghĩa là, sử dụng git ls-files --ther --exclude-standard --directory lấy danh sách bao gồm các thư mục. Có cách nào đó loại trừ các thư mục này?
9nix00

vâng, đây là tôi muốn và tôi cập nhật bài viết của mình cho mã script mới. Tôi nghĩ đề xuất của bạn hợp lý chặt chẽ hơn mặc dù nhiều mã hơn lol ... và Hy vọng câu trả lời tốt hơn xuất hiện.
9nix00

3
@albfan: đó là trong trang git-diff man : "Tạo chương trình thoát với các mã tương tự như diff (1). Nghĩa là, nó thoát với 1 nếu có sự khác biệt và 0 có nghĩa là không có sự khác biệt."
Mark Longair

Chỉ cần chỉ ra rằng, nó đã ở đó ít nhất từ ​​năm 2007 13da0fc0 , thực sự tiện dụng cho các kịch bản shell và hoàn toàn tương thích với các phiên bản cũ của git
albfan

10
--quiet(ngụ ý --exit-code) cũng im lặng đầu ra, cho những người chỉ muốn mã thoát.
phs

113

Giá trị trả về của git statuschỉ cho bạn biết mã thoát git status, chứ không phải nếu có bất kỳ sửa đổi nào được cam kết.

Nếu bạn muốn phiên bản git statusđầu ra dễ đọc hơn trên máy tính , hãy thử

git status --porcelain

Xem mô tả git statusđể biết thêm thông tin về điều đó.

Sử dụng mẫu (tập lệnh đơn giản kiểm tra nếu git status --porcelainđưa ra bất kỳ đầu ra nào, không cần phân tích cú pháp):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

Xin lưu ý rằng bạn phải trích dẫn chuỗi để kiểm tra, tức là đầu ra của git status --porcelain. Để biết thêm gợi ý về các cấu trúc thử nghiệm, hãy tham khảo Hướng dẫn về Bash Script nâng cao ( So sánh chuỗi phần ).


xin chào, bạn đưa ra một gợi ý hay, tôi đã thử nó, nhưng trong kịch bản, nó gây ra một số vấn đề, tôi đã cải thiện nó, nếu chúng ta sử dụng điều này nếu [-z $ (git status --por chì)]; nó sẽ gặp một số lỗi, [: ??: toán tử nhị phân dự kiến ​​tôi tìm hướng dẫn và sử dụng cái này nếu [-z $ (git status --short)]; Điều này có thể làm việc, cảm ơn!
9nix00

xin lỗi, vẫn còn nguyên nhân gây ra vấn đề khi cam kết sạch sẽ. dùng sứ và ngắn cả ok. nhưng khi cam kết không sạch sẽ. nó sẽ gây ra lỗi [: ??: toán tử nhị phân dự kiến. Tôi nghĩ có lẽ chúng ta nên thử sử dụng base64 để mã hóa nó. để tôi thử! tải xuống các công cụ lệnh base64 .... lol
9nix00

Nó gây ra vấn đề khi cam kết không sạch sẽ.
9nix00

1
Giải pháp tuyệt vời. Để tăng thêm sức mạnh, bạn có thể thêm || echo novào thay thế lệnh để không gian làm việc không bị báo cáo nhầm nếu git statuskhông thành công về cơ bản. Ngoài ra, mã của bạn (đáng khen ngợi) tuân thủ POSIX, nhưng vì bạn liên kết với hướng dẫn bash, hãy để tôi nói thêm rằng nếu bạn sử dụng bash's [[ ... ]]thay vì tương thích POSIX [ ... ], bạn không cần trích dẫn thay thế lệnh (mặc dù vậy không có hại) : [[ -z $(git status --porcelain) ]].
mkuity0

@eckes Tôi đã bắt đầu một repo mới vài ngày trước, tôi đã thêm một cam kết, tôi đã cố gắng viết một số hook-commit trước và kiểm tra những gì sẽ được cam kết và những gì bạn nói không hoạt động trong trường hợp của tôi.
alinsoar

33

Nếu bạn giống như tôi, bạn muốn biết nếu có:

1) thay đổi tệp hiện có 2) tệp mới được thêm 3) tệp bị xóa

và đặc biệt không muốn biết về 4) tệp không bị theo dõi.

Điều này nên làm điều đó:

git status --untracked-files=no --porcelain

Đây là mã bash của tôi để thoát tập lệnh nếu repo sạch. Nó sử dụng phiên bản ngắn của tùy chọn tệp không bị theo dõi:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;

4
+1 cho —untracked-files=no; Tôi nghĩ rằng bài kiểm tra của bạn có thể được đơn giản hóa [[ -z $(git status --untracked-files=no --porcelain) ]]. git statuskhông nên viết thư cho stderr, trừ khi một cái gì đó cơ bản đi sai - và sau đó bạn làm muốn nhìn thấy đầu ra. (Nếu bạn muốn hành vi mạnh mẽ hơn trong sự kiện đó, hãy thêm || echo novào thay thế lệnh để kiểm tra độ sạch vẫn không thành công). So sánh chuỗi / -ztoán tử có thể xử lý các chuỗi nhiều dòng - không cần tail.
mkuity0

2
cảm ơn @ mkuity0, thậm chí ngắn hơn một chút:[[ -z $(git status -u no --porcelain) ]]
psychboom

1
sửa: phiên bản ngắn hơn của tôi thực sự chỉ kiểm tra trạng thái trên tệp có tên "không"! Bzzt. Nên là: [[ -z $(git status -uno --porcelain) ]]
psychboom

2
Tôi đánh giá cao việc theo dõi; đó là một lỗi tinh vi - bài học là các tùy chọn ngắn với các đối số tùy chọn phải có đối số được nối trực tiếp , không có khoảng trắng ở giữa. Làm thế nào về việc kết hợp phiên bản ngắn được sửa trực tiếp vào câu trả lời của bạn?
mkuity0

9

Có thể kết hợp git status --porcelainvới đơn giản grepđể thực hiện kiểm tra.

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

Đôi khi tôi sử dụng nó như một lớp lót đơn giản:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

Thêm -qsvào lệnh grep của bạn để làm cho nó im lặng.


2
+1 cho sự thanh lịch; cảnh báo nhẹ: nên git statusthất bại nghiêm trọng (ví dụ, một repo bị hỏng), bài kiểm tra của bạn sẽ báo cáo nhầm không gian làm việc sạch sẽ . Một tùy chọn là sử dụng git status --porcelain 2>&1, nhưng điều đó sẽ 'ăn' thông báo lỗi nếu bạn đã sử dụng grep với -q. (Đối phó với điều đó sẽ làm mất đi sự thanh lịch (git status --porcelain || echo err) | grep -q .:)
mkuity0

cách khác, người ta có thể viết:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov

5

Từ mã nguồn git, có một tập lệnh sh bao gồm các đoạn sau.

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

Sniplet này cho thấy khả năng sử dụng git diff-filesgit diff-indextìm hiểu xem có bất kỳ thay đổi nào đối với các tệp đã biết trước đó hay không. Tuy nhiên, nó không cho phép bạn tìm hiểu xem một tệp không xác định mới đã được thêm vào cây làm việc.


Điều này hoạt động tốt, ngoại trừ các tập tin mới. chúng ta có thể thêm cái này nếu ! git ls-files --ther --exclude-standard --directory | grep -c -v '/ $' sau đó thoát 0 echo khác "vui lòng cam kết tệp mới của bạn, nếu bạn không muốn thêm nó, vui lòng thêm nó vào tệp git-bỏ qua." thoát 1 fi
9nix00

Chỉ cần if [ -n "$(git ls-files --others --exclude-standard)" ]không có bất kỳ đường ống hoặc greping bổ sung là đủ để phát hiện các tập tin không bị theo dõi.
Arrowmaster

5

Tôi sẽ làm một bài kiểm tra về điều này:

git diff --quiet --cached

hoặc điều này là rõ ràng:

git diff --quiet --exit-code --cached

Ở đâu:

--exit-code

Thực hiện thoát chương trình với các mã tương tự như diff (1). Đó là, nó thoát với 1 nếu có sự khác biệt và 0 có nghĩa là không có sự khác biệt.

--Yên tĩnh

Vô hiệu hóa tất cả đầu ra của chương trình. Hàm ý - mã -exit


3

Tôi hơi muộn trong cuộc thảo luận, nhưng nếu chỉ cần bạn có mã thoát là 0 nếu git status --porcelainkhông trả về gì và! = 0 khác, hãy thử điều này:

exit $( git status --porcelain | wc -l )

Điều này sẽ làm cho số lượng dòng là mã thoát, có nguy cơ gặp sự cố khi có hơn 255 dòng. Vì thế

exit $( git status --porcelain | head -255 | wc -l )

sẽ giải thích cho điều đó;)


1
Điều này về cơ bản sẽ không được xác định nếu có hơn 255 dòng đầu ra.
tripleee

Cũng phát hiện, Cảm ơn!
Skeeve

2

Tôi đang sử dụng điều này trong một kịch bản để có:

  • 0 khi mọi thứ sạch sẽ
  • 1 khi có một tập tin khác hoặc không bị theo dõi

    [-z "$ (trạng thái git - công ty)"]


sử dụng if ! git diff --quiet; thenlà sạch hơn và hiệu quả hơn (tôi nghĩ). Nói cách khác, sử dụng mã thoát, không phải thiết bị xuất chuẩn.
Alexander Mills

1
@AlexanderMills git diff --quiethành xử khác với git status --porcelaincác thay đổi được lưu trong bộ nhớ cache.
Martin von Wittich

0

Không xinh, nhưng hoạt động:

git status | grep -qF 'working directory clean' || echo "DIRTY"

Không chắc chắn liệu tin nhắn có phụ thuộc vào miền địa phương hay không, vì vậy có thể đặt LANG=Cphía trước.

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.