Как проверить, что в текущей ветке нечего делать?

172

Цель состоит в том, чтобы получить однозначный статус, который можно оценить с помощью команды оболочки.

Я пытался, git statusно он всегда возвращает 0, даже если есть элементы для фиксации.

git status
echo $?  #this is always 0

У меня есть идея, но я думаю, что это довольно плохая идея.

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

Любым другим путем?


обновите с последующим решением, см. сообщение Марка Лонгэйра

Я пробовал это, но это вызывает проблему.

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

Я получаю следующую ошибку [: ??: binary operator expected

сейчас я смотрю на мужчину и пробую git diff.

=================== код для моей надежды, и надеюсь, что лучший ответ ======================

#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
9nix00
источник
4
В обновленном разделе кажется, что вы на самом деле не делаете то, что предлагает eckes в его ответе - как он говорит, вы должны помещать двойные кавычки вокруг $(git status --porcelain). Кроме того, если вы хотите поместить восклицательные знаки в свое сообщение, вам нужно использовать одинарные кавычки, а не двойные кавычки - то есть echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'вместо этого
Марк Лонгэйр
4
как говорит Марк: нужно ставить двойные кавычки по всему$(git status --porcelain) , как я и говорил!
eckes
1
Эти вопросы были бы намного полезнее, если бы они не включали части ответов.
Oberlies
@ 9nix00 сделайте то, что вам сказали, отредактируйте и исправьте ошибку в приведенном выше сценарии оболочки: BUG: if [-z $ (некоторая команда)] FIX: if [-z "$ (некоторая команда)"]
MarcH

Ответы:

232

Альтернативой проверке того, является ли вывод git status --porcelainпустым, является проверка каждого условия, о котором вы заботитесь отдельно. Например, не всегда важно, есть ли на выходе файлы без отслеживания git status.

Например, чтобы увидеть, есть ли какие-либо локальные неустановленные изменения, вы можете посмотреть код возврата:

git diff --exit-code

Чтобы проверить, есть ли какие-либо изменения, которые поставлены, но не зафиксированы, вы можете использовать код возврата:

git diff --cached --exit-code

Наконец, если вы хотите узнать, есть ли в рабочем дереве какие-либо неотслеживаемые файлы, которые не игнорируются, вы можете проверить, является ли вывод следующей команды пустым:

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

Обновить: ниже вы спрашиваете, можете ли вы изменить эту команду, чтобы исключить каталоги из выходных данных. Вы можете исключить пустые каталоги, добавив --no-empty-directory, но чтобы исключить все каталоги в этом выводе, я думаю, что вам придется фильтровать вывод, например, с помощью:

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

Значение -vto egrepозначает вывод только тех строк, которые не соответствуют шаблону, а шаблон соответствует любой строке, заканчивающейся символом a /.

Марк Лонгэйр
источник
Я опирался на эти советы и у меня есть проблема. то есть используйте git ls-files --other --exclude-standard --directory, чтобы получить список включаемых каталогов. есть ли каким-то образом исключить эти каталоги?
9nix00
да, это я хочу. и я обновляю свой пост для нового скрипта-кода. Я думаю, ваше предложение более строго логично, хотя кода больше, и я надеюсь, что появятся лучшие ответы.
9nix00
3
@albfan: это находится на странице руководства git-diff : «Сделайте так, чтобы программа выходила с кодами, похожими на diff (1). То есть она выходит с 1, если были различия, а 0 означает, что нет различий».
Марк Лонгэйр
Просто чтобы указать, это было там по крайней мере с 2007 года 13da0fc0 , действительно удобно для сценариев оболочки и полностью совместимо со старыми версиями git
albfan
10
--quiet(что подразумевает --exit-code) также отключает вывод для тех, кто хочет только код выхода.
тел
113

Возвращаемое значение git statusпросто сообщает вам код выхода git status, если нет каких-либо изменений, которые должны быть зафиксированы.

Если вам нужна более читаемая версия git statusвывода, попробуйте

git status --porcelain

Смотрите описание git statusдля получения дополнительной информации об этом.

Пример использования (скрипт просто проверяет, git status --porcelainдает ли какой-либо вывод, анализ не требуется):

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

Обратите внимание, что вы должны заключить в кавычки строку для проверки, т.е. вывод git status --porcelain. Для получения дополнительных советов о тестовых конструкциях см. Руководство по расширенному написанию сценариев Bash ( Сравнение строк раздела ).

Экес
источник
привет, вы даете хорошее предложение, я попробовал это, но в скрипте это вызвало некоторые проблемы, я улучшил его, если мы используем это, если [-z $ (git status --porcelain)]; он получит некоторую ошибку, [: ??: ожидается бинарный оператор. Я нахожу руководство и использую его, если [-z $ (git status --short)]; это может работать, спасибо!
9nix00
извините, проблема все еще остается когда коммит чистый. использовать фарфор и шорт как хорошо. но когда коммит не чист. это приведет к ошибке. [: ??: ожидается бинарный оператор. Я думаю, может быть, мы должны попробовать использовать base64 для его кодирования. Дай мне попробовать! загрузка командных инструментов base64 .... lol
9nix00
это вызывает проблему, когда фиксация не является чистой.
9nix00
1
Отличное решение. Для повышения надежности вы можете добавить || echo noк подстановке команд, чтобы рабочая область не была ошибочно сообщена чистой, если произошел git statusсбой. Кроме того, ваш код (похвально) POSIX-совместимый, но поскольку вы ссылаетесь на руководство по bash, позвольте мне добавить, что если вы используете bash [[ ... ]]вместо POSIX-совместимого [ ... ], вам не нужно заключать в кавычки подстановку команд (хотя это не вредит) [[ -z $(git status --porcelain) ]].
mklement0
@eckes Я начал новое репо несколько дней назад, я добавил коммит, я попытался написать предварительный коммит-хук и проверить, что должно быть зафиксировано, а что вы говорите, не работает в моем случае.
alinsoar
33

Если вы похожи на меня, вы хотите знать, если есть:

1) изменения в существующих файлах 2) вновь добавленные файлы 3) удаленные файлы

и конкретно не хочу знать про 4) неотслеживаемые файлы.

Это должно сделать это:

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

Вот мой bash-код для выхода из скрипта, если репозиторий чист. Используется короткая версия опции неотслеживаемых файлов:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;
moodboom
источник
4
+1 за —untracked-files=no; Я думаю, что ваш тест может быть упрощен до [[ -z $(git status --untracked-files=no --porcelain) ]]. git statusне следует писать в stderr, если что-то фундаментальное не идет не так - и тогда вы действительно хотите увидеть этот вывод. (Если вам нужно более устойчивое поведение в этом событии, добавьте || echo noподстановку команд, чтобы проверка на чистоту все еще не прошла). Сравнение строк / -zоператор может работать с многострочными строками - в этом нет необходимости tail.
mklement0
2
спасибо @ mklement0, даже немного короче:[[ -z $(git status -u no --porcelain) ]]
moodboom
1
исправление: моя более короткая версия на самом деле просто проверяет состояние файла с именем "нет"! Bzzt. Должно быть: [[ -z $(git status -uno --porcelain) ]]
moodboom
2
Я ценю продолжение; это небольшая ошибка - урок заключается в том, что для коротких опций с необязательными аргументами аргумент должен добавляться напрямую , без пробелов между ними. Как насчет включения исправленной короткой версии прямо в ваш ответ?
mklement0
9

Это можно комбинировать git status --porcelainс простым grepдля выполнения теста.

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

Я использую это как простой однострочник иногда:

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

Добавьте -qsк своей команде grep, чтобы она замолчала.

Стив Прентис
источник
2
+1 за элегантность; небольшое предостережение: в случае git statusфатального сбоя (например, поврежденного репо) ваш тест по ошибке сообщит о чистом рабочем пространстве. Можно использовать один вариант git status --porcelain 2>&1, но это «съест» сообщение об ошибке, если вы используете grep с -q. (Работа с этим потеряет элегантность: (git status --porcelain || echo err) | grep -q .)
mklement0
В качестве альтернативы можно написать:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov
5

Из исходного кода git есть скрипт sh, который включает в себя следующее.

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
}

Этот фрагмент показывает, как его можно использовать git diff-filesи git diff-indexвыяснить, есть ли какие-либо изменения в ранее известных файлах. Однако это не позволяет вам узнать, был ли добавлен новый неизвестный файл в рабочее дерево.

Arrowmaster
источник
это отлично работает, за исключением новых файлов. мы можем добавить это. если ! git ls-files - другое --exclude-standard --directory | grep -c -v '/ $' затем выйти из 0, иначе echo "пожалуйста, зафиксируйте свой новый файл, если вы не хотите добавлять его, пожалуйста, добавьте его в файл git-ignore." выход 1 fi
9nix00
Просто if [ -n "$(git ls-files --others --exclude-standard)" ]без каких-либо дополнительных трубопроводов или greping должно быть достаточно для обнаружения неотслеживаемых файлов.
Arrowmaster
5

я бы сделал тест на это:

git diff --quiet --cached

или это должно быть явно:

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

где:

--exit-код

Сделайте выход из программы с кодами, похожими на diff (1). То есть, он завершается с 1, если были различия, а 0 означает, что нет различий.

--тихо

Отключить все выходные данные программы. Подразумевает - Exit-код

archf
источник
3

Я немного опоздал в обсуждении, но если вам нужен только код выхода 0, если git status --porcelainничего не возвращается и еще! = 0, попробуйте это:

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

Это приведет к тому, что количество строк будет кодом выхода, что может привести к проблемам при наличии более 255 строк. Так

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

будет учитывать это;)

Skeeve
источник
1
Это в основном будет неопределенным, если будет более 255 строк вывода.
Трипли
Хорошо заметили, спасибо!
Скив
2

Я использую это в сценарии, чтобы:

  • 0 когда все чисто
  • 1 когда есть файлы diff или неотслеживаемые

    [-z "$ (git status --porcelain)"]

грубее
источник
использование if ! git diff --quiet; thenчище и эффективнее (я думаю). Другими словами, используйте код выхода, а не стандартный вывод.
Александр Миллс
1
@AlexanderMills git diff --quietведет себя иначе, чем git status --porcelainдля кэшированных изменений.
Мартин фон Виттих
0

Не красиво, но работает:

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

Не уверен, зависит ли сообщение от локали, поэтому, возможно, поставьте LANG=Cперед.

Тильман Фогель
источник