Git получить рабочее дерево для каждой ветви в отдельных папках - Bash
Мне нужно написать bash-скрипт, который копирует ветки нашего репозитория на наш локальный веб-сервер linux каждый час.
У нас есть удаленный репозиторий git (gitolite) с именами веток "master" "testing" "feature-featurename" "hotfix-number"
каждая из этих веток должна иметь свое рабочее дерево, скопированное в /var/www/html/branchname
Прежде всего: как мне скопировать разные рабочие деревья в разные папки? Второе: как я могу автоматизировать этот процесс, если ветки "feature-" и "hotfix-" постоянно меняют имена?
Это не имеет ничего общего с Git-хуком, это должен быть скрипт, запущенный на другом сервере, который запускается заданием cron.
3 ответа
Ужасный лайнер
mkdir -p /var/www/html
git clone --bare user@git-server:/your-repo.git && cd your-repo.git
git for-each-ref --format='%(refname)' refs/heads/ | grep 'branch-pattern' | while read branchRef; do
branchName=${branchRef#refs/heads/}
git archive --format=tar --prefix="$branchName/" "$branchRef" | tar -C/var/www/html -x
done
Давайте разберемся с этим:
Убедитесь, что целевой каталог существует. Наверное, не обязательно для вас.
mkdir -p /var/www/html
Клонируйте репозиторий git и войдите в каталог
git clone --bare user@git-server:/your-repo.git
Список веток. Это будет выполнено из клонированного каталога. Обратите внимание, что
git branch
не используется, так как это может иметь неожиданные результаты при использовании в скриптах.git for-each-ref --format='%(refname)' refs/heads/
Фильтр для веток, которые вы хотите. В вашем случае шаблон, вероятно, будет что-то вроде
grep -E "(master)|(testing)|(feature-.*)"
и т.п.grep 'branch-pattern'
while
оператор читает имя каждой ветви и присваивает егоbranch
переменная- Создать
branchName
переменная, которая является именем ветви, исключая префикс ref. Обратите внимание, что это зависит от bash. git archive
создает архив tar выбранной ветви с префиксом всех записей именем ветви. Архив отправляется на стандартный выводgit archive --format=tar --prefix="$branch/" "$branch"
Немедленно распакуйте архив в его целевое местоположение
tar -C/var/www/html -x
Как мне скопировать разные рабочие деревья в разные папки?
Это делается с помощью git worktree, как показано в user7050130 Адельсбергера . ответе
Этот ответ заканчивается словами:
Вы также можете использовать
git worktree list --porcelain
вместо прямого поиска каталогов рабочего дерева - и это может быть предпочтительнее в нечетных случаях, таких как (опять же) ветки с именами.
На самом деле вы должны, особенно с Git 2.31 (1 квартал 2021 г.): ( ) теперь аннотирует рабочие деревья как обрезаемые, показывает заблокированные и обрезаемые атрибуты в режиме и получил опцию.
См. , , коммит 862c723, коммит 47409e7 (27 января 2021 г.) и коммит eb36135, коммит fc0c7d5, коммит a29a8b7 (19 января 2021 г.) Рафаэля Сильвы (
raffs
).
(Объединено Junio C Hamano --
gitster
-- в коммите 02fb216, 10 февраля 2021 г.)
коммит 076b444: обучение подробному режиму
Помощь: Эрик Саншайн
Подпись: Рафаэль Сильва
Рецензент: Эрик Саншайн
" " ( ) аннотирует каждое рабочее дерево в соответствии с его состоянием, таким как обрезаемое или заблокированное, однако не сразу становится очевидным, почему эти рабочие деревья аннотируются.
Для обрезаемых рабочих деревьев доступна причина, которая возвращаетсяshould_prune_worktree()
а для заблокированных рабочих деревьев причина может быть указана пользователем черезlock
команда.Давайте научим "" а
--verbose
режим, который выводит причину, по которой рабочие деревья аннотируются.
Причина в том, что текст может принимать практически любой размер, а добавление текста в формате столбцов по умолчанию затруднит расширение команды другими аннотациями и не будет хорошо вписываться в экран.
Чтобы устранить этот недостаток, аннотация затем перемещается на следующую строку с отступом, за которым следует причина. Если причина недоступна, аннотация остается на той же строке, что и само рабочее дерево.Вывод "" с подробным становится таким:
$ git worktree list --verbose ... /path/to/locked-no-reason acb124 [branch-a] locked /path/to/locked-with-reason acc125 [branch-b] locked: worktree with a locked reason /path/to/prunable-reason ace127 [branch-d] prunable: gitdir file points to non-existent location ...
теперь включает в свою справочную страницу :
Для этих аннотаций также может быть доступна причина, и это можно увидеть в подробном режиме. Затем аннотация перемещается на следующую строку с отступом, за которым следует дополнительная информация.
$ git worktree list --verbose /path/to/linked-worktree abcd1234 [master] /path/to/locked-worktree-no-reason abcd5678 (detached HEAD) locked /path/to/locked-worktree-with-reason 1234abcd (brancha) locked: working tree path is mounted on a portable device /path/to/prunable-worktree 5678abc1 (detached HEAD) prunable: gitdir file points to non-existent location
Обратите внимание, что аннотация перемещается на следующую строку, если доступна дополнительная информация, в противном случае она остается на той же строке, что и само рабочее дерево.
А также:
коммит 9b19a58
worktree
: учитьlist
аннотировать обрезаемое рабочее деревоПомощь: Эрик Саншайн
Подпись: Рафаэль Сильва
Рецензент: Эрик Саншайн
" Команда " ( manmanman ) показывает абсолютный путь к рабочему дереву, проверенную фиксацию, имя ветки и аннотацию "", если рабочее дерево заблокировано, однако она не указывает, можно ли обрезать рабочее дерево.
Команда «prune» удалит рабочее дерево, если оно может быть сокращено, если не указан параметр.
Это может привести к удалению рабочего дерева без ведома пользователя, пока не стало слишком поздно, если пользователь забудет передать--dry-run
например.
Если команда «список» показывает, какое рабочее дерево можно обрезать, пользователь может проверить перед запуском « " ( man) и, надеюсь, предотвращает случайное удаление рабочего дерева в худшем случае.Давайте учить»
git worktree list
", чтобы показать, когда рабочее дерево является подходящим кандидатом как для формата по умолчанию, так и для формата фарфора.В формате по умолчанию добавляется «сокращаемый» текст:
$ git worktree list /path/to/main aba123 [main] /path/to/linked 123abc [branch-a] /path/to/prunable ace127 (detached HEAD) prunable
в
--porcelain
формат добавляется обрезаемая метка с указанием причины:$ git worktree list --porcelain ... worktree /path/to/prunable HEAD abc1234abc1234abc1234abc1234abc1234abc12 detached prunable gitdir file points to non-existent location ...
теперь включает в свою справочную страницу :
ветвь, извлеченная в данный момент (или «отделенная HEAD», если нет), «заблокирована», если рабочее дерево заблокировано, «обрезаемое», если рабочее дерево может быть удалено
prune
команда.
git worktree
теперь включает в свою справочную страницу :
Команда также показывает аннотации для каждого рабочего дерева в соответствии с его состоянием. Эти аннотации:
locked
, если рабочее дерево заблокировано.prunable
, если рабочее дерево можно обрезать черезgit worktree prune
.$ git worktree list /path/to/linked-worktree abcd1234 [master] /path/to/locked-worktreee acbd5678 (brancha) locked /path/to/prunable-worktree 5678abc (detached HEAD) prunable
Итак, сначала вам нужен список филиалов. Для сценариев лучше всего использовать команду for-each-ref
, Предполагая, что вы просто хотите использовать локальные имена веток, используйте что-то вроде
git for-each-ref refs/heads/* |cut -d\/ -f3
Кроме того, пара вещей в приведенной выше команде предполагает, что вы не используете ветви в "пространствах имен". Если вы используете имена филиалов, как qa/feature-1
- содержащий /
- тогда это меняет несколько вещей. Приведенная выше команда просто становится
git for-each-ref refs/heads |cut -d\/ -f3-
но большая проблема в том, что вам, вероятно, придется больше думать о том, как имена ветвей должны соответствовать именам каталогов. Поэтому сейчас я буду исходить из предположения, что имена ветвей не будут содержать /
,
Вам нужно обработать каждую ветку, поэтому
git for-each-ref refs/heads/* |cut -d\/ -f3 |while read branch; do
# ... will process each branch here
done
Теперь вы можете использовать git worktree
оптимизировать отдельные проверки. (Обратите внимание, что это должно быть гораздо более эффективным, чем использование archive
скопировать весь контент фиксации для каждой ветви, а затем вызвать tar
отменить работу, которую ты не хотел archive
делать в первую очередь.)
Чтобы убедиться, что все необходимые рабочие деревья определены
git for-each-ref refs/heads/* |cut -d\/ -f3 |while read branch; do
if [ ! -d .git/worktrees/$branch ]; then
git worktree add /var/www/html/$branch $branch
fi
done
Теперь одна вещь об этом состоит в том, что, когда ветви перемещаются (то есть, когда получаются толчки), это приводит к тому, что рабочие деревья "не синхронизированы", так что вы, кажется, ставили "отмену" каждого изменения, сделанного нажатием. (Защита для рабочего дерева по умолчанию, кажется, не применяется.)
Но это похоже на ваши требования; альтернативой будет обновление каталогов при появлении толчков, которые вы отклоняете в своем описании проблемы. Таким образом, ваш сценарий должен, в этом случае, синхронизировать рабочее дерево с новыми изменениями, "отменив" их
git for-each-ref refs/heads/* |cut -d\/ -f3 |while read branch; do
if [ ! -d .git/worktrees/$branch ]; then
git worktree add /var/www/html/$branch $branch
fi
git reset --hard HEAD
done
Конечно, иногда ветви уходят; если вы не хотите использовать устаревшие метаданные рабочего дерева, вы можете добавить
git worktree prune
Вы также можете использовать git worktree list --porcelain
вместо непосредственного поиска каталогов рабочего дерева - и это может быть предпочтительнее в нечетных случаях, таких как (опять же) ветви пространства имен.