Визначте, чи чистий робочий каталог Git із сценарію


82

У мене є скрипт, який працює rsyncза призначенням Git. Я хочу, щоб сценарій відрізнявся поведінкою в залежності від того, чи працює робочий каталог чистим (ніяких змін для введення), чи ні. Наприклад, якщо вихідний показник git statusнаведено нижче, я хочу, щоб сценарій вийшов:

git status
Already up-to-date.
# On branch master
nothing to commit (working directory clean)
Everything up-to-date

Якщо каталог не чистий, я хотів би, щоб він виконав ще кілька команд.

Як я можу перевірити вихід на зразок вище в сценарії оболонки?


Чи допоможе перевірка стану з останньої команди тут? ($?)
UVV

Чи можете ви детальніше розповісти? Яка головна ідея вашого сценарію?
tachomi

@tachomi Я додав контекст у редагуванні
brentwpeterson

ви можете просто припустити, що це не чисто, і робити, git reset --hard origin/branchякщо це те, що ви збираєтеся ... як, наприклад, якщо ви намагаєтеся очистити після того, як щось скласти тощо.
SnakeDoc,

1
@SnakeDoc Ви могли б, але я припускаю, що зворотний випадок буде більш поширеним, тобто вийти, якщо робочий каталог забруднений, щоб уникнути маніпулювання локальними змінами. Розгляд обох випадків зробить питання кориснішим для майбутніх читачів.
Thomas Nyman

Відповіді:


133

Розбір результатів git status- погана ідея, оскільки результат має бути читаним для людини, а не для машинного зчитування. Немає гарантії, що вихід буде залишатися однаковим у майбутніх версіях Git або в інших налаштованих середовищах.

Коментар ультрафіолетових випромінювань стоїть на правильному шляху, але, на жаль, код повернення git statusне змінюється, коли є незаперечні зміни. Однак він надає --porcelainможливість, що призводить git status --porcelainдо форматування результатів у простому для розбору форматі сценаріїв, і залишатиметься стабільним у всіх версіях Git і незалежно від конфігурації користувача.

Ми можемо використовувати порожній вихідний показник git status --porcelainяк індикатор того, що ніяких змін не слід здійснювати:

if [ -z "$(git status --porcelain)" ]; then 
  # Working directory clean
else 
  # Uncommitted changes
fi

Якщо нам не байдуже непотрібні файли в робочому каталозі, ми можемо скористатися --untracked-files=noопцією, щоб нехтувати такими:

if [ -z "$(git status --untracked-files=no --porcelain)" ]; then 
  # Working directory clean excluding untracked files
else 
  # Uncommitted changes in tracked files
fi

Щоб зробити це більш надійним щодо умов, які насправді призводять git statusдо виходу з ладу без виходу stdout, ми можемо вдосконалити чек на:

if output=$(git status --porcelain) && [ -z "$output" ]; then
  # Working directory clean
else 
  # Uncommitted changes
fi

Варто також зазначити, що, хоча git statusне дає значущого коду виходу, коли робочий каталог нечистий, він git diffнадає --exit-codeможливість, завдяки чому він поводиться аналогічно утиліті diff , тобто виходить зі статусом, 1коли були відмінності і 0коли жодної не було знайдено.

Використовуючи це, ми можемо перевірити наявність нестандартних змін за допомогою:

git diff --exit-code

і поетапно, але не вносив змін із:

git diff --cached --exit-code

Хоча git diffможна звітувати про відслідковувані файли в підмодулях за допомогою відповідних аргументів --ignore-submodules, але, на жаль, здається, що немає ніякого способу, щоб він звітував про незараховані файли у фактичному робочому каталозі. Якщо непотрібні файли в робочому каталозі є актуальними, git status --porcelainце, мабуть, найкраща ставка.


4
ughhh git status --porcelainвийде з кодом 0, навіть якщо є зміни, не встановлені для файлів фіксації та відслідковування.
Олександр Міллс

Мені було цікаво визначитись заздалегідь, чи git stashбуду щось робити (він не видає корисний код повернення). Я повинен був додати, --ignore-submodulesяк інакше git statusвказували б зміни підмодуля, які git stashігноруються.
Девін Лейн

1
@AlexanderMills: я спостерігав те саме. Але потім перевірив, що if [ -zробить. Це -zозначає, що якщо наступний рядок порожній, значення if оцінюється до true. Іншими словами, якщо це не git status --porcelainпризведе до рядків, репо буде чистим. Якщо ні, він містить список модифікованих / доданих / видалених файлів і більше не є порожнім рядком. ifПотім обчислює false.
Адейнак

19

Використання:

git diff-index --quiet HEAD

Код повернення відображає стан робочого каталогу (0 = чистий, 1 = брудний). Файли, що не відслідковуються, ігноруються.


6
Повертає 0, коли в поточному каталозі є незавершені файли.
Адам Паркін

2
Якщо файли торкнулися / перезаписали, але в іншому випадку ідентичні індексу, спершу потрібно запустити git update-index --refreshзаздалегідь git diff-index HEAD. Більш детальна інформація: stackoverflow.com/q/34807971/1407170
sffc

@AdamParkin Я просто додаю всі файли, git add .перш ніж їх видавати. Зазвичай це спосіб використовувати його в сценарії
ceztko

Це чудово. Зауважте, що невід'ємний код повернення / виходу також інтерпретується як "помилка", яка, якщо ви знаходитесь у скрипті з набором -e, ваш сценарій вийде, якщо "брудний". Цього можна уникнути, виконавши set +eперед викликом git, та додавши set -eще раз після того, як ви оцінили $?.
orion elenzil

1

Незначне продовження на відмінну відповідь Андре .

Це один із способів оцінити результати, а також уникнути неполадок, якщо ви в сценарії, який раніше видав набір -e .

Файли, що не відслідковуються, ігноруються.

set +e
git diff-index --quiet HEAD

if [ $? == 1 ] ; then
  set -e
  GIT_MODS="dirty"
else
  set -e
  GIT_MODS="clean"
fi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.