Làm cách nào để kiểm tra tập lệnh Bash nếu kho Git cục bộ của tôi có thay đổi?


175

Có một số tập lệnh không hoạt động chính xác nếu chúng kiểm tra các thay đổi.

Tôi đã thử nó như thế này:

VN=$(git describe --abbrev=7 HEAD 2>/dev/null)

git update-index -q --refresh
CHANGED=$(git diff-index --name-only HEAD --)
if [ ! -z $CHANGED ];
    then VN="$VN-mod"
fi

Có một số loại kiểm tra boolean nếu đã có thay đổi kể từ lần xác nhận cuối cùng, hoặc làm thế nào tôi có thể thực sự kiểm tra nếu có thay đổi mới cho kho lưu trữ cục bộ của mình không?

Tôi đang làm tất cả điều này cho một kịch bản tạo phiên bản (mà tôi tìm thấy ở đâu đó ở đây).


3
Có chuyện gì với bạn git statusvậy?
karlphillip

4
@karlphillip: Nó xử lý rất nhiều mà bạn không thực sự cần.
Cascabel

1
@karlphillip đó là lệnh "sứ", có nghĩa là: không phù hợp để sử dụng trong tập lệnh vì đầu ra được thiết kế để con người đọc và có thể thay đổi (giữa các phiên bản hoặc do nội địa hóa)
Andrew Spencer

Câu trả lời:


199

Những gì bạn đang làm sẽ gần như hoạt động: bạn nên trích dẫn $CHANGEDtrong trường hợp nó trống và -zkiểm tra trống, có nghĩa là không có thay đổi. Ý bạn là:

if [ -n "$CHANGED" ]; then
    VN="$VN-mod"
fi

Một trích dẫn từ Git's GIT-VERSION-GEN:

git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty"

Có vẻ như bạn đã sao chép nó, nhưng bạn chỉ quên chi tiết đó của trích dẫn.

Tất nhiên, bạn cũng có thể làm điều này:

if git diff-index --quiet HEAD --; then
    # No changes
else
    # Changes
fi

Hoặc nếu bạn chỉ quan tâm đến trường hợp "có gì đó đã thay đổi":

if ! git diff-index --quiet HEAD --; then
    VN="$VN-mod"
fi

Việc sử dụng --quietcó lợi ích là Git có thể ngừng xử lý ngay khi gặp một khác biệt duy nhất, do đó nó có thể không phải kiểm tra toàn bộ cây công việc của bạn.


2
Xin chào, đó là một trong những câu trả lời hay nhất cho một câu hỏi, bạn chỉ cần cung cấp cho tôi tất cả thông tin mà tôi cần và những người khác tôi cũng cần :). Tôi sẽ chỉ cần cái cuối cùng, "một cái gì đó đã thay đổi" :) và bạn đã đúng, tôi đã sao chép nó.
kmindi

9
Kịch bản hoàn thành bash tuyệt vời dường như được sử dụng git diff --no-ext-diff --quiet --exit-codeđể xác định trạng thái bẩn.
mjs

3
@mjs: Đó thực sự là một nơi tuyệt vời để tìm kiếm những thứ như thế này! Các --no-ext-difftùy chọn là tốt cho sự an toàn (trong trường hợp ai đó đã cấu hình một tài xế khác bên ngoài), mặc dù --exit-codekhông phải là cần thiết, vì nó ngụ ý bởi --quiet.
Cascabel

4
Điều này không hiệu quả với tôi vì nó không báo cáo các tệp không bị theo dõi
Cookie

1
git diff-indexbáo cáo thay đổi ngay cả khi chỉ thay đổi thời gian sửa đổi tệp (và không phải nội dung của chúng). Nếu bạn touchlà một tập tin, nó sẽ báo cáo sửa đổi rằng chạy git statussẽ thiết lập lại. Sử dụng git statusnhư dưới đây là tốt hơn.
Sampo

302

Sử dụng git status:

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi

15
Câu trả lời tốt nhất, một sự xấu hổ các câu trả lời từ 'kiến trúc sư vỏ và git' được đánh giá cao hơn.
jwg

4
Điều này thật tuyệt vời khi nó tính đến các tệp không đảo ngược và cũng sử dụng sứ, nó sẽ tương thích hơn với các phiên bản git khác nhau.
Jayd

25
Để bỏ qua các tệp không bị theo dõi: if [[ git status --porcelain --untracked-files=no]]; sau đó
bão_m2138

4
Để kiểm tra các thay đổi cục bộ -> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
Carlos Saltos

3
Mã này làm gì: Thực thi git status --porcelainxem nếu đầu ra không trống. Nếu vậy có nghĩa là có những thay đổi hiện tại.
bhathiya-perera

18

Mặc dù câu trả lời của Jefromi là tốt, nhưng tôi đăng bài này chỉ để tham khảo.

Từ mã nguồn Git, có một đoạn shmã 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
}

Để tham khảo và nếu tôi đọc đúng, đây $1là một chuỗi đặt tên cho một tác vụ bạn muốn chạy và $2là một chuỗi tùy chọn có chứa một thông báo lỗi tùy chỉnh khi thất bại. Ví dụ: gọi nó như thếrequire_clean_work_tree deploy "Skipping deploy, clean up your work tree or run dev-push"
Ô

6

Tôi đã có một vấn đề tương tự, nhưng tôi cũng phải kiểm tra các tập tin được thêm vào. Vì vậy, tôi đã làm như sau:

cd /local/repo
RUN=0
git diff --no-ext-diff --quiet --exit-code || RUN=1
if [ $RUN = 0 ]; then
    RUN=`git ls-files --exclude-standard --others| wc -l`
fi

if [ $RUN = 0 ]; then
    exit 0
fi

5

git status là bạn của bạn

Thay đổi thư mục Git git statusđể làm việc:

cd c:/path/to/.git

Đặt một biến để đặt cây công việc để bạn không gặp phải 'Lỗi hoạt động này phải được chạy trong cây công việc':

WORKTREE=c:/path/to/worktree

Nắm bắt git status đầu ra trong một biến Bash

Sử dụng --porcelainđảm bảo ở định dạng chuẩn và có thể phân tích cú pháp:

CHANGED=$(git --work-tree=${WORKTREE} status --porcelain)

Nếu -n (không null), chúng tôi có thay đổi.

if [ -n "${CHANGED}" ]; then
  echo 'changed';

else
  echo 'not changed';
fi

1
Điều này cũng có lợi ích trong việc phát hiện các tệp không bị theo dõi.
Luiz C.

2

Điều này cũng hoạt động:

if [ $(git status --porcelain | wc -l) -eq "0" ]; then
  echo "  🟢 Git repo is clean."
else
  echo "  🔴 Git repo dirty. Quit."
  exit 1
fi

1

Điều này hoạt động độc đáo. Nó cũng sẽ liệt kê các tập tin bị ảnh hưởng:

if git diff-index --name-status --exit-code HEAD;
then
    echo Git working copy is clean...;
else
    echo ;
    echo ERROR: Git working copy is dirty!;
    echo Commit your changes and try again.;
fi;

1
nếu bạn không muốn thấy diff git diff --no-ext-diff --quiet --exit-codecũng làm việc.
Alex

1

Dưới đây là một tập hợp tốt các hàm script Bash để kiểm tra xem có diff hay không, in nó cho người dùng và nhắc người dùng nếu họ muốn cam kết thay đổi trước khi triển khai. Nó được xây dựng cho ứng dụng Heroku và Python, nhưng nó cần ít thay đổi cho bất kỳ ứng dụng nào khác.

commit(){
    echo "Please enter a commit message..."
    read msg
    git add . --all
    git commit -am $msg
}

check_commit(){
    echo ========== CHECKING FOR CHANGES ========
    changes=$(git diff)
    if [ -n "$changes" ]; then
        echo ""
        echo "*** CHANGES FOUND ***"
        echo "$changes"
        echo ""
        echo "You have uncomitted changes."
        echo "Would you like to commit them (y/n)?"
        read n
        case $n in
            "y") commit;;
            "n") echo "Changes will not be included...";;
            *) echo "invalid option";;
        esac
    else
        echo "... No changes found"
    fi
}

deploy(){
    check_commit
    echo ========== DEPLOYING TO HEROKU ========
    git push heroku master
    heroku run python manage.py syncdb
}

Bạn có thể sao chép từ Gists trên: https://gist.github.com/sshadmand/f33afe7c9071bb725105


1

Câu hỏi của OP đã hơn 9 tuổi. Tôi không biết những gì đã man git-statusnói sau đó, nhưng đây là những gì nó nói bây giờ:

--porcelain[=<version>]  
Give the output in an easy-to-parse format for scripts. This is similar to the 
short output, but will remain stable across Git versions and regardless of user 
configuration. See below for details.  

The version parameter is used to specify the format version. This is optional and 
defaults to the original version v1 format.  

Điều này cho thấy rằng --porcelain đối số rất phù hợp để kiểm tra trạng thái của một repo để thay đổi.

Viết câu hỏi của OP, "Có một loại kiểm tra boolean nào nếu có thay đổi kể từ lần cam kết cuối cùng không, hoặc làm thế nào tôi có thể thực sự kiểm tra nếu có thay đổi mới đối với kho lưu trữ cục bộ của mình?"

Tôi không nghĩ rằng bashcó các kiểu dữ liệu boolean mỗi se , nhưng điều này có thể đủ gần:

[ -z "`git status --porcelain`" ] && echo "NULL-NO DIFFS" || echo "DIFFS EXIST"

Điều này có thể được tạo lại if-then-elsedưới dạng biểu mẫu cho tập lệnh hoặc được thực thi dưới dạng fm là CLI khi ở trong thư mục git repo . Mặt khác, sử dụng -Ctùy chọn với thông số đường dẫn đến repo quan tâm:

git -C ~/path/to/MyGitRepo status --porcelain 

Phụ lục:

  1. Một số lời khuyên sử dụng -u, --untracked-filetùy chọn để tránh báo cáo trạng thái trên các tệp mà một người muốn bỏ qua. Lưu ý điều này đi kèm với một tác dụng phụ đáng tiếc : các tệp mới được thêm vào cũng không được đặt trạng thái. Tùy chọn này hữu ích trong một số tình huống , nhưng hãy xem xét cẩn thận trước khi sử dụng.

0

Đây là cách tôi làm điều đó ...

CHANGES=`git status | grep "working directory clean"`
if [ ! CHANGES -eq "" ] then
    # do stuff here
else
    echo "You have uncommitted changes..."
fi

3
Tôi thích sử dụng trạng thái git, nhưng tốt hơn là sử dụng --porclus trong các tập lệnh và so sánh kết quả với một chuỗi trống để không thay đổi, vì nó được đảm bảo không thay đổi theo cách không tương thích giữa các phiên bản.
Paul Chernoch

0
nano checker_git.sh

dán cái này

#!/bin/bash

echo "First arg: $1"

cd $1

bob="Already up-to-date."
echo $bob

echo $(git pull) > s.txt
cat s.txt
if [ "$(cat s.txt)" == "$bob" ]
then
echo "up"
else
echo "not up"

fi
rm -rf st.txt

chạy sh checker_git.sh gitpath


0

Dựa trên @ Storm_m2138 nhận xét cho câu trả lời ( liên kết ) của @ RyanMoon Tôi đang sử dụng thông tin sau Powershell.

function hasChanges($dir="."){ $null -ne (iex "git -C $dir status --porcelain --untracked-files=no") }

gci -Directory | ?{ hasChanges $_ } | %{ Write-Host "$_ has changes" }
gci -Directory | ?{ hasChanges $_ } | %{ iex "git -C $_ add -u"; iex "git -C $_ commit -m"Somemthing" }
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.