Як перевірити, чи не має нічого робити в поточній галузі?


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

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-файли - інше --exclude-standard --директорія, щоб список включав каталоги. чи можна якось виключити ці каталоги?
9nix00

так, це я хочу. і я оновлюю свій пост на новий скрипт-код. Я думаю, що ваша пропозиція є більш суворою логічною, хоча більше коду ...
9nix00

3
@albfan: це на сторінці чоловіка git-diff : "Зробіть програму виходу з кодами, подібними до diff (1). Тобто, вона закінчується з 1, якщо були відмінності, а 0 означає, що відмінностей немає".
Марк Лонгейр

Зазначимо , що він там принаймні з 2007 року 13da0fc0 , дійсно зручний для скриптів оболонки і повністю сумісний із старими версіями git
albfan

10
--quiet(що означає --exit-code) також замовчує вихід, для тих, хто хоче лише код виходу.
ph

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 - шорт)]; це може спрацювати, дякую!
9nix00

Вибачте, проблема все ще є. коли фіксація чиста. використовувати порцеляновий та короткий як добре. але коли фіксація не є чистою. це призведе до помилки. [: ??: очікується двійковий оператор. Я думаю, можливо, ми повинні спробувати використовувати base64 для його кодування. Дозвольте мені спробувати! завантаження командних інструментів base64 .... lol
9nix00

це може спричинити проблеми, коли фіксація не є чистою.
9nix00

1
Прекрасне рішення. Для додаткової надійності ви можете додати || echo noдо заміни команди, щоб робоча область не була помилково повідомлена про чисту, якщо вона git statusне працює принципово. Також ваш код (похвально) сумісний з POSIX, але оскільки ви посилаєтесь на керівництво по bash, дозвольте додати, що якщо ви використовуєте bash's [[ ... ]]замість POSIX-сумісного [ ... ], вам не потрібно двічі цитувати заміну команди (хоча це не шкодить) : [[ -z $(git status --porcelain) ]].
mklement0

@eckes Я розпочав нову репортажу кілька днів тому, я додав зобов’язання, я спробував написати якийсь попередній фіксований гачок і перевірити, що потрібно зробити, а що ви, на вашу думку, не працювали в моєму випадку.
alinsoar

33

Якщо ви схожі на мене, ви хочете знати, чи є:

1) зміни до існуючих файлів 2) нещодавно додані файли 3) видалені файли

і спеціально не хочу знати про 4) незатребувані файли.

Це слід зробити:

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

Ось мій баш-код, щоб вийти зі скрипту, якщо репо буде чистим. Він використовує коротку версію опції відслідковуваних файлів:

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

4
+1 для —untracked-files=no; Я думаю, що ваш тест можна спростити [[ -z $(git status --untracked-files=no --porcelain) ]]. git statusне слід використовувати потоки, якщо що - то фундаментальне піде не так - і тоді ви дійсно хочете , щоб побачити , що вихід. (Якщо ви хотіли більш сприятливої ​​поведінки в цьому випадку, додайте || 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
ВасиліНовіков

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з’ясувати, чи є якісь зміни раніше відомих файлів. Однак це не дозволяє дізнатися, чи був доданий новий невідомий файл до робочого дерева.


це добре працює за винятком нових файлів. ми можемо додати це. якщо! git ls-файли - інше --exclude-standard --директорія | grep -c -v '/ $', тоді вийдіть з 0 else echo "будь ласка, введіть новий файл, якщо ви не хочете його додати, будь ласка, додайте його у файл git-ignore". вихід 1 fi
9nix00

Просто if [ -n "$(git ls-files --others --exclude-standard)" ]без будь-яких додаткових конфігурацій або копіювання має бути достатньо для виявлення файлів, що не відслідковуються.
Arrowmaster

5

Я б зробив тест на це:

git diff --quiet --cached

або це має бути явним:

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

де:

--exit-код

Зробіть вихід програми за допомогою кодів, подібних до diff (1). Тобто він закінчується з 1, якщо були відмінності, а 0 означає, що різниці немає.

--тихо

Вимкнути весь вихід програми. Implies --exit-код


3

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

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

Це зробить кількість рядків кодом виходу, ризикуючи отримати проблеми, коли буде більше 255 рядків. Так

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

буде враховувати це;)


1
Це в основному буде невизначено, якщо буде більше 255 рядків виводу.
трійчатка

Добре помічений, спасибі!
Сків

2

Я використовую це в сценарії, щоб мати:

  • 0, коли все чисто
  • 1, коли є файли відмінності або відслідковування

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


використання if ! git diff --quiet; thenє більш чистим і ефективним (я думаю). Іншими словами, використовуйте код виходу, а не stdout.
Олександр Міллс

1
@AlexanderMills git diff --quietведе себе інакше, ніж git status --porcelainдля кешованих змін.
Мартін фон Віттіч

0

Не дуже, але працює:

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

Не впевнений, чи залежить повідомлення від локальної локальності, тому, можливо, поставте LANG=Cпопереду.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.