Как узнать, что локальное репо отличается от удаленного репо без извлечения?
Я получил десятки репозиториев, мой скрипт должен обновить их, если возникнет какая-либо разница, новые коммиты, новый тег, новая ветка. В моем случае выборка идет медленно для десятков репозиториев, и я хотел бы знать, может ли какая-нибудь быстрая команда удовлетворить мое требование.
3 ответа
Вы можете использовать git ls-remote
Сантехническая команда для получения состояния пультов без извлечения.
Здесь давайте использовать сам git в качестве облегченной базы данных, чтобы отслеживать состояние удаленного компьютера.
Поместите следующее в сценарий; Вы можете включить его позже как функцию оболочки git alias для удобства. Беги внутри своего репо.
REMOTE_SUM=$(git ls-remote --tags --heads 2>/dev/null | git hash-object --stdin)
if git cat-file -e $REMOTE_SUM
then
echo Remote check-summed up-to-date.
else
echo Remote changed, fetching...
git ls-remote --tags --heads 2>/dev/null | \
git hash-object -w --stdin &>/dev/null
git fetch
fi
Некоторая необходимая проверка ошибок была опущена, а код был продублирован для ясности.
объяснение
Перечисление всех удаленных советов с git ls-remote --tags --heads
генерирует выходные данные, такие как:
От /home/user/tmp/repo2 777201715768a4d82f374f7224e68164a916ac1f refs/heads/bar 78981922613b2afb6025042ff6bd878ac1994e85 refs/heads/master ...
В свою очередь, мы хэшируем вышеописанное изображение удаленного репо как единый хеш через git hash-object --stdin
и проверьте, видели ли мы это ранее, запрашивая хеш в git с git cat-file -e
, Если мы этого не видели, удаленное изображение должно было измениться, и мы сначала записали его в git с помощью git hash-object -w
, чтобы приспособить расы между извлечением и фиксацией на пульте, а затем приступить к извлечению пульта.
Можно интегрировать это с функциональностью git pre-fetch: функциональностью pre-fetch hook в git, но это выходит за рамки этого ответа.
добавление
Обратите внимание, что выше будет генерировать свободные объекты в git, которые иногда нужно будет собирать с git gc
и, возможно, --prune
в явном виде.
Кроме того, вышесказанное должно работать до тех пор, пока коммиты специально не переставляются таким образом, чтобы концы ветвей оставались неизменными. Это было бы / весьма необычно / и идет вразрез с руководящими принципами git по изменению отправленного состояния, но, эй, худшее, что может случиться, это то, что вы пропускаете выборку.
Также обратите внимание, что ls-remote
работает на одном пульте. Для работы с несколькими пультами вам нужно будет расширить сценарий, создав список пультов с git remote show
и работать с каждым по очереди.
У вас нет доступа к origin
сервер
Вы не можете использовать только git
,
РЕДАКТИРОВАТЬ
Согласно другому ответу, git ls-remote
может быть полезным для вас.
Тем не менее, как вы должны ls-remote
во всех репозиториях, если ваша проблема связана с задержкой в сети, она не будет решена с помощью ls-remote
,
У вас есть доступ к origin
сервер
- Настройте ловушку, когда на репо на сервере происходит запись. Хук будет помечать репо как измененный. Вы можете, например, создать
repo_name__MODIFIED
файл где-то на сервере). - Перед обновлением репо проверьте, не модифицирован ли репо. Для данного примера проверьте, является ли файл
repo_name__MODIFIED
существуют на сервере. - Если хранилище было изменено, перед обновлением отметьте его как неизмененное (непосредственно перед извлечением). В случае нашего примера просто удалите
repo_name__MODIFIED
файл на сервере.
Заметка
Почему выборка так долго? git
будет только получать новые коммиты, если нет изменений в origin
, это должно быть очень быстро!
Если вы настроили свои локальные репозитории, используя git clone
или же git remote add $REMOTE_NAME $REMOTE_URL
, всю информацию, которая вам нужна для сравнения ваших локальных филиалов с их удаленными коллегами (на момент вашего последнего git fetch
) уже есть.
Если вы создали удаленные ветви отслеживания, git status
говорит вам, если о различиях с удаленной веткой вы отслеживаете, как это.
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: perl/Makefile.am
no changes added to commit (use "git add" and/or "git commit -a")
Также есть разбираемая форма:
$ git status --porcelain -b
## master...origin/master [behind 1]
M perl/Makefile.am