Как программно определить, есть ли незафиксированные изменения? - PullRequest
192 голосов
/ 07 октября 2010

В Makefile я хотел бы выполнить определенные действия, если есть незафиксированные изменения (либо в рабочем дереве, либо в индексе). Какой самый чистый и эффективный способ сделать это? Команда, которая завершается с возвращаемым значением ноль в одном случае и ненулевое значение в другом, подойдет моим целям.

Я могу запустить git status и передать вывод через grep, но я чувствую, что должен быть лучший способ.

Ответы [ 8 ]

247 голосов
/ 07 октября 2010

ОБНОВЛЕНИЕ : ОП Даниэль Штутцбах указывает в комментариях , что эта простая команда git diff-index сработала для него:

git diff-index --quiet HEAD --

Затем вы можете увидеть " Как проверить, успешно ли выполнена команда? ", если вы используете ее в скрипте bash:

git diff-index --quiet HEAD -- || echo "untracked"; // do something about it

Примечание: as прокомментировал от Энтони Соттил

git diff-index HEAD ... потерпит неудачу на ветви, в которой нет фиксаций (например, недавно инициализированный репозиторий).
OneОбходной путь, который я нашел, это git diff-index $(git write-tree) ...

И haridsv указывает в комментариях , что git diff-files на new *Файл 1038 * не определяет его как разность.
Кажется, что более безопасный подход - сначала запустить git add в спецификации файла, а затем использовать git diff-index, чтобы увидеть, добавлено ли что-либо в индекс перед запуском git commit.

git add ${file_args} && \
git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'

Оригинальный ответ:

«Программно» означает никогда не полагаться на фарфоровые команды .
Всегда гely on сантехнические команды .

См. также « Проверка наличия грязного индекса или неотслеживаемых файлов с помощью Git » для альтернатив (например, git status --porcelain)

Вы можете черпать вдохновение из новой "require_clean_work_tree function ", которая написана так, как мы говорим ;) (начало октября 2010 года)

require_clean_work_tree () {
    # Update the index
    git update-index -q --ignore-submodules --refresh
    err=0

    # Disallow unstaged changes in the working tree
    if ! git diff-files --quiet --ignore-submodules --
    then
        echo >&2 "cannot $1: you have unstaged changes."
        git diff-files --name-status -r --ignore-submodules -- >&2
        err=1
    fi

    # Disallow uncommitted changes in the index
    if ! git diff-index --cached --quiet HEAD --ignore-submodules --
    then
        echo >&2 "cannot $1: your index contains uncommitted changes."
        git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
        err=1
    fi

    if [ $err = 1 ]
    then
        echo >&2 "Please commit or stash them."
        exit 1
    fi
}
83 голосов
/ 22 февраля 2012

Хотя другие решения очень тщательны, если вы хотите что-то действительно быстрое и грязное, попробуйте что-то вроде этого:

[[ -z $(git status -s) ]]

Он просто проверяет, есть ли какие-либо выходные данные в сводке состояния.

51 голосов
/ 07 октября 2010

git diff --exit-code вернет ненулевое значение, если будут какие-либо изменения;git diff --quiet то же самое без вывода.Поскольку вы хотите проверить рабочее дерево и индекс, используйте

git diff --quiet && git diff --cached --quiet

или

git diff --quiet HEAD

. Любой из них сообщит вам, есть ли внесенные изменения, которые находятся на стадии постановки, или нет.

14 голосов
/ 10 ноября 2016

Расширяя ответ @ Nepthar:

if [[ -z $(git status -s) ]]
then
  echo "tree is clean"
else
  echo "tree is dirty, please commit changes before running this"
  exit
fi
4 голосов
/ 14 января 2017

Как указано в другом ответе, достаточно простой команды:

git diff-index --quiet HEAD --

Если вы опустите последние две черты, команда не выполнится, если у вас есть файл с именем HEAD.

Пример:

#!/bin/bash
set -e
echo -n "Checking if there are uncommited changes... "
trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
git diff-index --quiet HEAD --
trap - ERR
echo -e "\033[0;32mAll set!\033[0m"

# continue as planned...

Предупреждение: эта команда игнорирует неотслеживаемые файлы.

2 голосов
/ 03 февраля 2019

Я создал несколько удобных псевдонимов git, чтобы вывести список неподготовленных и промежуточных файлов:

git config --global alias.unstaged 'diff --name-only'
git config --global alias.staged 'diff --name-only --cached'

Тогда вы можете легко сделать такие вещи, как:

[[ -n "$(git unstaged)" ]] && echo unstaged files || echo NO unstaged files
[[ -n "$(git staged)" ]] && echo staged files || echo NO staged files

Вы можете сделать это большедля чтения, создав скрипт где-то на вашем PATH с именем git-has:

#!/bin/bash
[[ $(git "$@" | wc -c) -ne 0 ]]

Теперь приведенные выше примеры можно упростить до:

git has unstaged && echo unstaged files || echo NO unstaged files
git has staged && echo staged files || echo NO staged files

Для полноты здесьпохожие псевдонимы для неотслеживаемых и игнорируемых файлов:

git config --global alias.untracked 'ls-files --exclude-standard --others'
git config --global alias.ignored 'ls-files --exclude-standard --others --ignored'
0 голосов
/ 08 марта 2017

Вот лучший, самый чистый способ.

function git_dirty {
    text=$(git status)
    changed_text="Changes to be committed"
    untracked_files="Untracked files"

    dirty=false

    if [[ ${text} = *"$changed_text"* ]];then
        dirty=true
    fi

    if [[ ${text} = *"$untracked_files"* ]];then
        dirty=true
    fi

    echo $dirty
}
0 голосов
/ 09 ноября 2016

С Python и GitPython:

git.Repo(path).is_dirty(untracked_files=True)

Возвращает True, если хранилище не очищено

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...