Rsync: exclude from gitignore

В данной заметке описано, как и для чего мне пригодился файл .gitignore при копировании файлов через rsync.

Для удаленного заказчика необходимо поставлять программный код в виде релизов. Поставка осуществляется архивом tar.gz из ветки мастер в закрытый контур, где нет ни исходящего интернета, ни системы контроля версий. Из возможностей – только утилиты Linux.

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

Можно было бы поступить просто: распаковывать архив на целевом сервере, выполняя rsync -av source_code/ target_dir. Но в таком случае файлы, которые в процессе разработки были удалены, не будут удаляться из целевой директории и эта директория превратится в помойку с неактуальными данными. Такой вариант не подходит.

Ключ –delete у rsync идеально же решит возникшую проблему, который будет удалять по пути назначения всё то, чего нет в исходной директории. Но есть одна проблема…

В исходном репозитории исполнителя хранится только разрабатываемый программный код проекта на битрикс. Соответственно, в .gitignore прописаны исключения для множества директорий (/bitrix, /upload, /crm и прочие, которые не хранятся в гите). При выполнении команды rsync -av --delete source_code/ target_dir на сервере заказчика в целевом каталоге окажется только релизный код, а ядро битрикса, пользовательский аплоад и прочие директории вне гита будут удалены.

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

В данном случае используется расширенная версия ключей exclude\include под названием filter:--filter=':- /path/to/.gitignore'

Filter принимает на вход файл, в котором указаны директории для копирования или исключения. Но т.к. файл в формате .gitignore, для этого используется конструкция “:- “. Обращаю внимание, что после знака “-” обязательно следует пробел, который указывает выполнять слияние файлов из gitignore понятный для –filter формат.

Все файлы в .gitignore должны начинаться со слеша, чтобы rsync исключал все файлы с такими названиями не рекурсивно по всей директории, а относительно корня. Например, если указать файл test без слеша в гитигнор, то rsync будет искать по всему каталогу такой файл и исключать из копирования, в результате чего могут быть различные неприятные сюрпризы в виде “недоехавших” файлов.

Также возникает нюанс: в .gitignore попадает вся директория с ядром bitrix, но из неё средствами gitignore может исключаться какой-либо файл, например, /bitrix/.access.php, а его необходимо также копировать по адресу назначения в случае изменения. Для этого используется ключ include, который явно указывает скопировать необходимый файл, а под синтаксис .gitignore (!/bitrix/.access.php) данный файл не попадает, а потому исключение не сработает и файл окажется по адресу назначения.

Итого для примера как выглядит .gitignore:

/.idea/
 /.git/*
 /.pki/*
 /_test/
 /bitrix/*
 !/bitrix/access.php
 /builds/*
 /desktop_app/*
 /upload/*

Таким образом, отправка релиза в архиве к заказчику выполняется следующим образом:

  1. Архив передается заказчику любым удобным способом, они размещают его на целевых серверах
  2. Создается временная директория на сервере: mkdir -p /tmp/release_`date +%d.%m.%Y`
  3. Во временную директорию распаковывается архив с релизом: tar -xzvf /tmp/master.tar.gz -C /tmp/release_`date +%d.%m.%Y`
  4. И выполняется копирование в целевую директорию:
rsync -av --delete --include='bitrix/.access.php' --filter=':- /tmp/release_date +%d.%m.%Y/master/.gitignore' /tmp/release_date +%d.%m.%Y/master/ /mnt/u01/ext_www/target-site.ru

В результате на сайт доезжают только те изменения, которые были в исходном архиве, а всё остальное удаляется, кроме файлов, указанных в .gitignore.

Заключение

Данный способ мне кажется жутко кустарным и костыльным – так не стоит не делать где-то в продакшене, если есть доступ в гит. Тем не менее, в моём случае при текущих условиях иных более корректных или простых вариантов я придумать не смог, а потому способ рабочий и выполняет поставленную задачу.

P.S. Прочие возможности при работе с filter у rsync можно найти в man rsync, там много разных интересных примеров на различные ситуации.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: