VCSH — спасение настроек в $HOME

Как ни странно, я только недавно познакомился с VCHS — надстройкой над Git, призванной облегчить резервирование конфигурационных файлов, расположенных в домашней директории (Version control system for $HOME — один из вариантов расшифровки аббревиатуры). Очень жаль, что этого не произошло раньше, и бэкап конфигов делался нерегулярно, кое-как, с изобретением различных костылей. Но, всё это в прошлом! Итак, что же представляет собой VCSH и как ей пользоваться?

Сильные стороны VCSH

Первое преимущество использования VCSH по сравнению с чистым git — конфиги остаются лежать в домашней директории, а история их изменений хранится отдельно в каталоге ${HOME}/.config/vcsh/repo.d, что позволяет группировать файлы конфигов в разные наборы, хранящиеся в отдельных репозиториях и не зависящие друг от друг. Зачем это нужно? Таким способом можно синхронизировать на нескольких машинах только нужные везде конфиги, не таская лишние настройки повсюду. Например — иметь одинаковые настройки Vim и bash на локальной и удаленной машинах, не перенося конфиг mplayer на сервер, где и самого-то плеера нет. Еще плюс — $HOME является для VCSH рабочей директорией, что позволяет при помощи git status получить информацию об изменении существующих или появлении новых файлов в $HOME (кроме перечисленных в .gitignore), например — сведения о конфигах, созданных в процессе установки какой-то программы.

Установка, настройка

Установка в Debian элементарна, места VCSH требует совсем немного:

dimio@ibm $ sudo aptitude install vcsh
Следующие НОВЫЕ пакеты будут установлены:
libio-pty-easy-perl{a} libio-pty-perl{a} mr{a} myrepos{a} vcsh
0 пакетов обновлено, 5 установлено новых, 0 пакетов отмечено для удаления, и 0 пакетов не обновлено.
Необходимо получить 121 kB архивов. После распаковки 434 kB будет занято.

Как видно из списка устанавливаемых пакетов, VCSH в работе использует perl с библиотеками для создания псевдотерминалов и утилиту для массового управления репозиториями — myrepos. Сам git у меня уже стоит, потому он и его зависимости — отсутствуют в списке устанавливаемых пакетов.
Также перед началом работы имеет смысл сделать резервную копию всех конфигов, расположенных в домашней директории:
find ${HOME} -maxdepth 1 -name ".?*" ! \( -name .thumbnails \) -exec tar zcfv dotfiles_dotdirs_backup.tgz {} +
В этот архив попадут, конечно, не только конфиги, но и разнообразный мусор (типа кэша, файлов предпросмотра, временных файлов и т.п.), который из-под контроля git нужно будет исключить.

Начало работы с VCSH

Теперь можно приступить к работе непосредственно с VCSH — для начала — инициализировать новый репозиторий, расположенный в ${HOME} и содержащий в себе все файлы и каталоги с настройками, найденные в домашней директории:

$ cd    # переход в $HOME
# инициализация нового репозитория
# (название, конечно, стоит поменять на своё)
# опция -v указана для более подробного вывода
$ vcsh -v init dimio_ibm_dotfiles_all

verbose mode on
vcsh 1.20141026
vcsh: verbose: attempting to create ‘/home/dimio/.config/vcsh/repo.d’
vcsh: verbose: attempting to create ‘/home/dimio/.gitignore.d’
vcsh: verbose: init begin
Initialized empty shared Git repository in /home/dimio/.config/vcsh/repo.d/dimio_ibm_dotfiles_all.git/
vcsh: verbose: init end, exiting

Стоит сразу же настроить правила для невключения посторонних файлов в новый репозиторий — создать .gitinore для него: vcsh write-gitignore dimio_ibm_dotfiles_all и отредактировать (vim ~/.gitignore.d/dimio_ibm_dotfiles_all), внеся следующие изменения (исключенные с помощью .gitinore файлы и директории git обрабатывать не будет, проверять действие правил можно при помощи git status):

## Ignore all files/dirs
*
# but not dotfiles/dotdirs
!.*
!.*/**

## Programs
.wine/
.gnupg/
.python-eggs/
.tor/
# Ignore some vcsh dirs/files
.config/vcsh/**/objects/
.config/vcsh/**/info/
.config/vcsh/**/index
.config/vcsh/**/refs/
.config/vcsh/**/COMMIT_EDITMSG
# Ignore maildir
.Mail/
# Ignore chromium dirs
# but not settings, passwords, bookmarks etc
.config/chromium/*
!.config/chromium/Default/
.config/chromium/Default/*
!.config/chromium/Default/Bookmarks
!.config/chromium/Default/Login Data
.pki/
# same for elinks
.elinks/*
!.elinks/bookmarks
!.elinks/elinks.conf
# Ignore all vim files
.vim/*
.vim/view/*
# but not self made
!.vim/filetype.vim
!.vim/ftdetect/
!.vim/mojo.vim
!.vim/perl-support/codesnippets/
!.vim/sessions/
!.vim/syntax/conkyrc.vim

## Games
# Ignore all games dirs
# (see dimio_ibm_games repo)
.snes96_snapshots/
.wesnoth/
.freeciv*
.exult*
.abuse/
.gens/
.s9x/
.scummvm/

## Temporary, logs, auto backups etc
*.tmp
*.temp
t?mp/
tmp.*
*~
~*
*.bak
*.log
*.lock
*history
*cookie?
*.so
# Ignore "chache" files/dirs
**/*[Cc]ache
# Ignore lib, log etc dirs
**/lib
**/logs
**/packages
**/share

## Media
*.png
*.jpeg
*.jpg
*.ogg
*.mp[34]
*.mpeg
*.mpg
*.jpg
*.flv
*.ttf
**/[Ff]avicon*
**/icons
.gstreamer-*/
# Ignore all thumbnails dirs
?thumbnails/
# Ignore flash player dirs
.adobe/
.macromedia/

## Unnecessary files
.cabal/*
!.cabal/config
.config/enchant/
.config/menus/
.config/pulse/

Синтаксис .gitignore простой: # - комментарий, ! - инверсия правила (не игнорировать подпавшие под правило файлы/каталоги), * - 0 или больше любых символов, ** - любой уровень вложенности каталога (подробней тут).
После проверки репозитория на предмет попадания в него лишнего, правила игнорирования можно будет уточнить и дополнить.
Теперь нужно перейти в рабочий режим оболочки vcsh, который обеспечивает применение команд git непосредственно к «загруженному» в данный момент репозиторию, добавить в репозиторий нужные файлы/директории и сохранить их текущее состояние:

$ vcsh enter dimio_ibm_dotfiles_all
# добавить к отслеживанию всю рабочую область
# текущего репозитория
git add :/
# сделать начальный коммит
git commit -m 'Initial commit'

Для сброса внесенных изменений можно использовать git reset, также может быть полезным в работе сравнение режимов работы git add в разных сочетаниях и для разных версий git.
Выход из режима оболочки vcsh — по нажатию Ctrl+D или по команде exit.

Размещение репозитория с конфигами на удаленной машине

Копию репозитория имеет смысл разместить на удаленной машине, получив и резервирование, и возможность легко перенести настройки куда-то ещё. Основной репозиторий со всеми конфигами я решил разместить на BitBucket, так как он бесплатно предоставляет возможность использования приватного репозитория (напомню, что сам репозиторий для начала следует создать через веб-интерфейс BitBucket, а затем подставить его адрес в команду ниже; еще нужно не забыть добавить ключ для доступа к BitBucket при помощи ssh-add).

git remote add origin 'git@bitbucket.org:dimio/my_new_repo_name.git'
git push origin master

Однако, перед передачей файлов на удаленный сервер, было бы неплохо зашифровать их, так как репозиторий может содержать приватную информацию, например — настройки браузера (среди которых могут быть сохраненные пароли) или логи чатов pidgin и т.п. Да и сами ключи шифрования, если не исключить их через .gitignore специально, тоже попадут в репозиторий вместе с директорией ~/.gnupg/.

Шифрование файлов в git при помощи фильтров

Я для шифрования репозитория решил использовать gpg, создав специально под эту задачу новый ключ. Ключ нужно генерировать безпарольный (на локальной машине файлы всё равно хранятся в открытом виде), иначе автоматическая расшифровка при загрузке файлов из сетевой копии (команда git checkout) будет проблематичной.

# генерация gpg ключа
# все значения приняты по умолчанию,
# срок действия ключа не ограничен,
# пароль пустой, email: dimio@dimio.org
gpg --gen-key
# посмотреть информацию о ключе
gpg --fingerprint dimio@dimio.org
pub   1024R/1C9E9C65 2015-10-12
Отпечаток ключа = DBA7 327B 2049 05D2 928C  A1B0 8309 4115 1C9E 9C65
uid   Dmitry (GIT encrypt) "dimio @dimio.org"
sub   1024R/475149F7 2015-10-12

Теперь в .gitattributes нужного репозитория следует добавить фильтр для обработки (в данном случае — шифрования) нужных файлов (в случае с vcsh — сначала потребуется создать соответствующие каталог gitattributes.d и файл с атрибутами вручную, внимание — старые версии vcsh не поддерживают работу с отдельными файлами .gitattributes):

mkdir ~/.gitattributes.d
touch ~/.gitattributes.d/dimio_ibm_dotfiles_all
echo '* filter=gpg diff=gpg' > ~/.gitattributes.d/dimio_ibm_dotfiles_all

Здесь * — шаблон, под который должны подпадать названия файлов, требующих шифровки/расшифровки, т.е. обрабатываться будут все файлы.
Затем нужно прописать использование свежесозданного .gitattributes в нужном репозитории, для этого есть несколько путей:

  • Выполнить команду git config core.attributesfile ~/.gitattributes.d/dimio_ibm_dotfiles_all, находясь в режиме оболочки vcsh с загруженным репозиторием dimio_ibm_dotfiles_all;
  • Вручную внести информацию об используемом файле .gitattributes в настройки репозитория, отредактировав файл ~/.config/vcsh/repo.d/dimio_ibm_dotfiles_all.git/config и добавив в секцию [core] путь к .gitattributes:
    [core]
            attributesfile = .gitattributes.d/dimio_ibm_dotfiles_all
  • В новых версиях vcsh может сработать команда vcsh upgrade "repo_name", но в моей версии vcsh автоматическая обработка файла атрибутов отключена в коде программы (: ${VCSH_GITATTRIBUTES:=none}) и этот способ не работает.

Следующий шаг — создание фильтров, отвечающих за шифрование/дешифровку файлов. Они вносятся в файл конфигурации репозитория: ~/.config/vcsh/repo.d/dimio_ibm_dotfiles_all.git/config

[filter "gpg"]
    ;decrypt
    smudge = gpg -d -q --batch --no-tty
    ;encrypt
    clean = gpg -ea --batch --no-tty -r 475149F7
    ;filter must succeed in order to make
    ;the stored contents usable
    required
[diff "gpg"]
    ;replacement for standard diff
    textconv = git-gpg-decrypt

Где 475149F7 — идентификатор созданного ранее приватного ключа gpg (взамен можно указать e-mail, прописанный в информации о ключе). А git-gpg-decrypt — небольшой скрипт следующего содержания:

#!/bin/sh
gpg -d -q --batch --no-tty "$1" || cat "$1"

Путь к скрипту нужно внести в ${PATH}: у меня он лежит в директории ${HOME}/bin/, которая автоматически добавляется в ${PATH} путем загрузки bash_path-expand из bashrc. Теперь просмотр изменений (типа git log -p -1) будет работать корректно.
При желании, для шифрования репозиториев возможно применить специальную утилиту git-crypt, мне же подобное решение на данном этапе показалось избыточным.
А вот теперь можно вернуться к клонированию репозитория на сервер BitBucket (не забывая, что шифрование происходит на стадии подготовки к коммиту — при вызове команды git add).
После записи изменений (git push) в репоизторий на BitBucket — остается лишь убедиться, что фильтр сработал и шифрование прошло успешно. Для примера — вот так мой bashrc выглядит в репозитории BitBucket после совершения всего вышеописанного:
git+pgp шифрование
В заключение, для лучшего знакомства с git, могу смело порекомендовать отличную книгу ProGit, на материалы которой, среди прочего, я ссылался в этой заметке.



Category Рубрики: *NIX, Памятки, Полезности | Tag Метки: , , , , | Comments 3 комментария »

3 комментария

  1. GQ says:

    Слишком много телодвижений для решения задачи (особенно для развертывания на новом месте). После неудачного опыта использования, остановился на homesick

    • dimio says:

      Просмотрел бегло на гитхабе:
      — руби — мне не нужен и не установлен;
      — симлинки в домашнем — от них избавлялся как раз.

      Время ушло на составление и проверку правил gitignore, которые позволят полноценно мониторить через git status домашнюю директорию в нужном и достаточном объеме в целом (полагаю, homesick этот шаг никак не упростит). Отдельные частные репозитории, типа хранения настроек окружения или сохраненок от игр, таких затрат времени на разворачивание уже не потребуют.

      Что у homesick с шифрованием?

  2. Спасибо за полезную и интересную информацию!

Добавить комментарий