Сценарий оболочки, чтобы проверить git на наличие изменений, а затем просмотреть измененные файлы?

Я пытаюсь написать сценарий оболочки, который выполняет следующие действия:

  1. Проверяет удаленный репозиторий git на предмет внесения изменений.
  2. Если есть изменения в удаленном репозитории git, потяните эти изменения.
  3. Перебирает новые или измененные файлы.

В ходе своих исследований я нашел некоторые из необходимых команд для выполнения этих задач, но мне не удалось заставить их работать вместе в сценарии оболочки.

Вот сценарий с некоторыми из имеющихся у меня команд:

#!/bin/sh

#Check if there are any changed files
git --git-dir="/dir/.git" fetch origin

if git --git-dir="/dir/.git" log HEAD..origin/master --oneline
then

#Output the modified files from the last pull
        git --git-dir="/dir/.git" diff --name-status ORIG_HEAD..

fi

Вот что мне не удалось заставить работать с командами в этом скрипте:

  1. Оператор if для проверки наличия изменений или не всегда верен. Я пробовал операторы if с другими командами git, и они также всегда верны. Кажется, что git не работает как обычные команды оболочки, когда вы получаете ответ 0 или 1. Как я могу заставить команду git, подобную этой или другие команды git, возвращать правильные ответы в операторе if?
  2. Как я могу назначить переменные, выводимые из команды, чтобы увидеть измененные файлы в массиве, чтобы я мог перебирать их, используя for?

Если в этом случае команды в моем сценарии не работают, что лучше?

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


person startupsmith    schedule 05.12.2012    source источник


Ответы (4)


Для вашего первого вопроса вы можете использовать git diff --quiet (или git diff --exit-code, но обычно, когда вы используете его для кода выхода, вы хотите, чтобы он все равно не печатал вывод, а git diff --quiet подразумевает --exit-code), чтобы определить, были ли какие-либо изменения. Это даст вам значение 1, если есть изменения, и 0, если их нет. Итак, если вы хотите иметь код, который будет запускаться только при наличии изменений:

if ! git --git-dir="/dir/.git" diff --quiet
then
    # do stuff...
fi

Что касается вашего второго вопроса, я бы рекомендовал цикл while read ... для чтения строк из git diff-tree:

git --git-dir="/dir/.git" diff-tree ORIG_HEAD.. | \
    while read srcmode dstmode srcsha dstsha status srcfile dstfile
    do
        # do something with $srcfile and $dstfile
    done

Обратите внимание, что $srcmode будет иметь дополнительный : в начале, а $dstfile будет иметь значение только в том случае, если файл был переименован. Если вы не хотите беспокоиться о переименовании, передайте --no-renames, и вместо переименований вы увидите только добавления и удаления.

person Brian Campbell    schedule 05.12.2012

Вы можете просто использовать git diff --name-only для вывода списка всех имен измененных файлов.

Например, вот простой скрипт для вывода списка всех отредактированных файлов PHP и проверки синтаксиса.

#!/bin/bash
files=`git diff --name-only | grep -E '.php$' `
for file in $files; do
  php -l $file
done
person RousseauAlexandre    schedule 09.08.2017

Вы правы, git обычно не завершает работу с ненулевым статусом, если нет ошибки. Самый простой способ обнаружить незафиксированные изменения - это примерно так:

 let changes=0
 while read status filename; do
    let changes=1
    # do something with this filename/status
 done < <(git status --porcelain)
 if (( ! changes )); then
    echo "No changes."
 fi

В общем, если вы собираетесь управлять git из кода, вы должны использовать --porcelain в тех подкомандах, которые его поддерживают, чтобы заставить его действовать более удобным для автоматизации способом. Вы также можете изучить библиотеки для других языков для взаимодействия с git без создания собственных команд оболочки; например, в Ruby есть упорство.

Теперь, в вашем случае, вы хотите определить, что изменилось в восходящем направлении. Для этого вы, вероятно, захотите использовать git diff-tree. Логика аналогична приведенной выше:

 git fetch   # not pull
 while read filename; do
   # do something with filename
 done < <(git diff-tree --name-only origin/master master)  # or whatever branch you're using
person Mark Reed    schedule 05.12.2012
comment
Привет Марк. Спасибо за ваш ответ. Я попытался запустить ваш сценарий, но получаю следующую ошибку: синтаксическая ошибка рядом с неожиданным токеном <' done ‹‹ (git status --porcelain) '. Есть идеи, каким должен быть правильный синтаксис? - person startupsmith; 05.12.2012
comment
Вы уверены, что используете bash? - person Mark Reed; 05.12.2012
comment
Привет Марк. Вы правы, я не использовал bash ... теперь он работает. Мне нужно разобраться в этом подробнее, но из того, что я вижу, этот сценарий будет перебирать измененные файлы до того, как они будут извлечены из удаленного репозитория? - person startupsmith; 05.12.2012
comment
извините, это не так - он перебирает файлы, в рабочей копии которых есть изменения, которые еще не были зафиксированы. Вы ищете изменения из апстрима, поэтому git diff-tree, вероятно, то, что вам нужно. См. Мой отредактированный ответ и @BrianCampbell's. - person Mark Reed; 05.12.2012
comment
Привет Марк. Проблема с git fetch заключается в том, что он не объединяет изменения с удаленного компьютера для обновления локальных файлов. Когда я просматриваю файлы, мне нужно, чтобы файлы были актуальными ... Я пробовал использовать git pull, но, похоже, он не хочет объединяться, когда я выполняю его из сценария. Должен ли git pull быть возможен в сценарии для того, что я пытаюсь сделать, или мне нужно будет сделать что-то еще? - person startupsmith; 06.12.2012
comment
Конечно, у вас должна быть возможность git pull из сценария. После объединения изменений между двумя ветвями master не будет никаких различий, поэтому вам придется вместо этого сравнивать HEAD^ и HEAD. - person Mark Reed; 06.12.2012

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

``` bash
# Get to code.  Exit if unsaved changes in repo
if `git status | grep -q "nothing to commit"`; then
  git checkout --quiet $BRANCH || exit 1
else
  echo "ERROR: repo has unsaved changes"
  exit 1
fi
```

Это самая простая вещь, которую я смог найти, которая проверяет наличие новых, измененных и размещенных файлов.

person Michael Cole    schedule 31.08.2018