Использование Git для управления конфигурационными файлами






Если вы достаточно длительное время используете UNIX/Linux, то у вас уже вероятно имеются хорошо «заточенные» файлы конфигурации Bash, Vim, Emacs и других приложений. Копирование вручную этих файлов между всеми системами, с которыми вы работаете, может быть весьма утомительным процессом. Git может существенно облегчить ваши мучения из-за копирования ваших конфигурационных файлов на новые компьютеры.


Обычно в своей работе я пользуюсь Dropbox, однако как быть с конфиг-файлами, хранящимися в /etc и в домашнем каталоге? Можно, конечно, придумать какое-нибудь извращение и приспособить Dropbox для хранения этих файлов, однако здесь возникает ещё одна проблема: как заставить Dropbox закачивать на новую систему только определённые файлы, а не все сразу?

Ещё одним решением может быть использование rsync, Duplicity или Unison, однако они не позволяют сохранять версионность файлов, и хранят лишь одну-единственную копию файла с самыми последними изменениями. Короче, Git (или другая система контроля версий) в моём случае подходит лучше всего, а может быть отлично сгодится и для вас.

Другой причиной, по которой мой выбор пал на Git, стало то, что я уже имею некоторый положительный опыт работы с ним и мне хотелось бы ещё попрактиковаться, используя Git в своей повседневной жизни. Конечно, опытные пользователи Git располагают гораздо большим набором знаний и вероятно могут гораздо эффективнее меня решить поставленные задачи. Я же попытался изучив лишь основные моменты работы с Git, создать инструкцию, которой бы могли свободно воспользоваться люди, не знакомые с ним вообще. Если у вас есть идеи, как лучше организовать процесс работы с файлами — пишите в комментариях, я всегда рад новым идеям.

Вкратце опишем перечень шагов, которые нам предстоит сделать в процессе изучения данного материала:

  • создать ключи SSH, чтобы не приходилось авторизоваться паролем;
  • установить Git на всех системах где будем его использовать;
  • создать «голый» (bare) репозиторий на удалённой системе;
  • создать репозиторий в локальной системе, файлы с которой будем синхронизировать;
  • добавить файлы в локальный репозиторий;
  • сделать слепок (commit) добавленных файлов;
  • отправить (push) изменения в удалённый репозиторий;
  • сделать изменения в локальных файлах и сделать слепок изменений;
  • клонировать репозиторий на другую систему.

Начнём

Первое, что нам понадобится — это система, которая будет хранить наш Git-репозиторий. У вас должна быть возможность подключаться к ней по SSH. Это может быть как компьютер в вашей локальной сети, так и система, расположенная в Интернет. Вы даже можете использовать онлайн-сервис GitHub, если у вас нет подходящего компьютера.

Первым делом вам необходимо создать пару SSH-ключей и настроить аутентификацию на удалённой системе. Чтобы каждый раз не вводить пароль, вы можете сгенерировать закрытый ключ без пароля, однако не забывайте о том, что если кто-то сможет заполучить ваш закрытый ключ, то он сможет авторизоваться по SSH на удалённой системе. Процесс генерации ключей на моей системе выглядел так:

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/ashep/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ashep/.ssh/id_dsa.
Your public key has been saved in /home/ashep/.ssh/id_dsa.pub.
The key fingerprint is:
f0:59:19:5d:69:c7:4c:62:d0:c1:38:fe:f1:2b:2d:2c ashep@adesktop
The key's randomart image is:
+--[ DSA 1024]----+
|          ...*=*.|
|           o+.=.+|
|      .   o. o . |
|       o o  . .  |
|        S    . o |
|              . .|
|            . . .|
|           E + o |
|            . o  |
+-----------------+

После того, как пара ключей создана, закрытый ключ будет размещён в в ~/.ssh/id_dsa, а открытый — в ~/.ssh/id_dsa.pub. Теперь, чтобы удалённая система аутентифицировала  вас на основе ключа, а не пароля, необходимо скопировать содержимое локального файла ~/.ssh/id_dsa.pub в файл ~/.ssh/authorized_keys на удалённой системе. В Debian/Ubuntu для этих целей есть специальный shell-скрипт ssh-copy-id, им и воспользуемся:

$ ssh-copy-id ashep@aserver
ashep@aserver's password:
Now try logging into the machine, with "ssh 'ashep@aserver'", and check in:

  .ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.

Пользователи же других систем, в которых ssh-copy-id отсутствует, могут воспользоваться старой-доброй scp:

$ scp /home/ashep/.ssh/id_dsa.pub ashep@aserver:/home/ashep/.ssh/authorized_keys

Будьте внимательны и если в ~/.ssh/authorized_keys на удалённой системе у вас уже имеются какие-то ключи, то добавьте вручную открытый ключ к существующим, поскольку приведённая выше команда затрёт существующий файл.

Ну и, само-собой разумеется, в ваших системах, которые будут участвовать в работе, должен быть установлен Git. На сегодняшний день Git присутствует в репозиториях всех современных дистрибутивов, а также в коллекции портов FreeBSD, так что у вас не должно возникнуть сложностей с его установкой. Я использую Ubuntu и в ней Git установился «лёгким движением руки»:

$ sudo apt-get install git-core

Создание репозиториев

Пришло время создавать репозитории. Начнём с создания репозитория на удалённой системе, затем создадим локальный, в который и добавим файлы. Подключитесь к удалённой системе по SSH:

$ ssh ashep@aserver

создайте каталог для хранения репозитория:

$ mkdir project

и создайте в это каталоге «голый» Git-репозиторий:

$ cd project && git init --bare
Initialized empty Git repository in /home/ashep/project/

Просто, не так ли? Теперь в вашей локальной системе необходимо создать репозиторий для хранения отслеживаемых файлов. Обычно, если вы работаете над каким-то проектом, каталог репозитория .git хранится в каталоге проекта. В нашем же случае необходимо будет хранить файлы из разных мест, поэтому лучшим вариантом будет создать репозиторий в корне домашнего каталога:

$ cd ~/ && git init
Initialized empty Git repository in /home/ashep/.git/

Репозиторий успешно создан и прежде, чем мы продолжим работу, давайте минимально настроим Git, а точнее определим имя и email, которые будут упоминаться к истории коммитов (слепков):

$ git config --global user.name "Alexander Shepetko"
$ git config --global user.email "ashep@ashep.org"

Теперь добавим что-нибудь в репозиторий, указывая Git отслеживать изменения:

$ git add .vim
$ git add .vimrc

И сделаем слепок состояния добавленных файлов, указав при помощи опции -m комментарии к слепку:

$ git commit -m 'Первый слепок'
[master (root-commit) f4c5dcf] Первый слепок
 4 files changed, 90 insertions(+), 0 deletions(-)
 create mode 100644 .vim/.netrwhist
 create mode 100644 .vim/spell/ru.utf-8.spl
 create mode 100644 .vim/spell/ru.utf-8.sug
 create mode 100644 .vimrc

Отлично, файлы и каталог успешно добавлены, теперь можно «слить» локальный репозиторий в удалённый. Для начала необходимо в локальном репозитории определить один или несколько  удалённых, с которыми Git сможет производить синхронизацию. Добавим ранее созданный удалённый репозиторий project на удалённой системе aserver, доступ к которой у нас настроен от имени пользователя ashep:

$ git remote add origin ashep@aserver:project

И отправим изменения из локального репозитория:

$ git push origin master
Counting objects: 8, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 2.37 MiB | 462 KiB/s, done.
Total 8 (delta 0), reused 0 (delta 0)
To ashep@aserver:project
 * [new branch]      master -> master

Отслеживание изменений

После того, как вы сделали свой  первый слепок и отправили изменения в удалённый репозиторий, самое время разобраться с тем, как отслеживать изменения в файлах. Сделайте какое-нибудь незначительное изменение, например, в файле .vimrc и сделайте после этого слепок состояния всех отслеживаемых файлов:

$ git commit -a -m 'Изменён .vimrc'
[master 0d6096f] Изменён .vimrc
 1 files changed, 0 insertions(+), 1 deletions(-)

Теперь вы можете отправить изменения в удалённый репозиторий:

$ git push origin master
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 317 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ashep@aserver:project
   f4c5dcf..0d6096f  master -> master

Копирование файлов на другие системы

Пришло время «размножить» наши конфигурационные файлы на тех системах, где это нам нужно. Авторизуйтесь в нужной системе и создайте в своём домашнем каталоге новый  Git-репозиторий, как это мы делали ранее:

$ cd ~/ && git init
Initialized empty Git repository in /home/ashep/.git/

И теперь скопируйте файлы удалённого репозитория на диск:

$ git pull ashep@aserver:project
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 11 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (11/11), done.
From aserver:project
 * branch            HEAD       -> FETCH_HEAD

На это всё! Если вы сделаете изменения в каком-то из отслеживаемых файлов на любой системе, просто воспользуйтесь командами git commit и git push, как это было показано выше и изменения будут доставлены в удалённый репозиторий, после чего вы сможете из загрузить во все локальные репозитории систем, в которых эти версии файлов вам необходимы, при помощи команды git pull.

Обратите внимание на то, что мы используем git pull, а не git clone, поскольку нам нужно получать именно изменения в файлах, а не весь репозиторий целиком.

Управление версиями

По ходу работы вы можете добавлять в репозиторий новые файлы для отслеживания при помощи команд git add и удалять ненужные при помощи git rm. Если вам необходмо узнать, какие файлы находятся в состоянии «отслеживаемых», воспользуйтесь командой git ls-files:

$ git ls-files
.vim/.netrwhist
.vim/spell/ru.utf-8.spl
.vim/spell/ru.utf-8.sug
.vimrc

Что делать, если вы сделали ненужные изменения в локальном файле и хотите восстановить версию, находящуюся в последнем слепке? Для этого существует команда git checkout. Например, следующая команда восстановит последнюю версию файла .vimrc:

$ git checkout .vimrc

Просмотреть историю слепков можно при помощи команды git log:

$ git log
commit 0d6096f96c647e8b1bdfb6a217cbae967b16a5cd
Author: Alexander Shepetko
Date:   Fri Apr 22 02:46:15 2011 +0300

    Изменён .vimrc

commit f4c5dcf1f5c55ab8b495c6e16afb1eee73b8380a
Author: Alexander Shepetko
Date:   Fri Apr 22 01:54:14 2011 +0300
    Первый слепок

Обратите внимание на 40-битное значение хэша слепка. Оно уникально идентифицирует каждый коммит, так что вы можете обращаться к нему. В частности иногда бывает полезно восстановить не отдельный файл а весь слепок целиком. Для этого достаточно команде git revert передать хэш-значение нужного слепка:

$ git revert 0d6096f96c647e8b1bdfb6a217cbae967b16a5cd
Finished one revert.
[master 933c16f] Revert "Изменён .vimrc"
 1 files changed, 1 insertions(+), 0 deletions(-)

Резюме

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

По мотивам linux.com




Использование Git для управления конфигурационными файлами: 3 комментария

  1. Давно пользуюсь подобной схемой. В ubuntu есть еще полезный пакет etckeeper (вырезка мана:

    ETCKEEPER (8)

    NAME

    etckeeper — store /etc in git, mercurial, bazaar, or darcs ...

    )

    Приспособил его для синхронизации каталога /etc между рабочими компьютерами.

  2. Зачем ты это сказал? теперь я знаю эту команду — не знал бы никогда бы не ввёл (хотя в баше автодополнение есть)

Комментарии запрещены.