12 июня 2013 г.

Хранение конфигурационных файлов (RCS & Git)

Когда-то давным давно, я впервые познакомился с системами контроля версий. Наверное это была CVS. Git'а тогда еще в планах думаю не было. Возникла у меня примерно в то далекое время логичная идея хранить все настройки в какой-нибудь подобной системе. Так совпало, что тогда же я активно изучал Emacs. И наткнулся тагда я на Version Control расширение. Именно оттуда я узнал о более древней системе: RCS. Как ни странно, именно в эту систему Emacs предлагает добавить файлы по умолчанию (C-x v v).

Так вот, с тех давних пор у меня все хранилось в RCS. Вообще говоря это достаточно удобно, если единственная задача: хранить историю изменений на одной машине. Все управление через Emacs. Я даже не особо знаю ключи команд ci и co.

Теперь же у меня фактически 4 компьютера, на которых я хотел бы иметь одинаковые, хотя бы, пользовательские настройки. Например, для bash или того же git. Для этого я задумал поместить все необходимые файлы из домашней директории в git репозиторий. Но положить в git всю или часть домашней директории похоже нехорошая идея. Однозначно будут глюки с git prompt. Если не добавить все файлы в .gitignore, то git prompt просто подвесит консоль: сканирование всей домашней директории не быстрое дело. Думаю это не единственная проблема.

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

Еще одна проблема: специфичные настройки определенных машин. Например, PATH в Linux и OS X местами различаются (избыточности не хочется). В .gitconfig у меня даже различие есть. Для решения этого вопроса я создал для каждой машины, которой необходимы какие-то особенности, специальную ветку. Общие настройки хранятся на master ветке. Неудобство этой схемы связанно с тем, что надо постоянно сливать изменения с master'а в специфичные ветки. Может есть какое-то более простое и элегантное решение?

Ну а системные настройки (/etc/) я так и продолжаю хранить в RCS. Если будет задача настройки нескольких одинаковых машин, то можно будет подумать на тему синхронизации через git. Пока это не нужно. RCS хранит историю и этого достаточно. Насколько знаю portage в gentoo можно настроить для сохранения истории в RCS (см. /etc/dispatch-conf.conf). Но сам я этой возможностью не пользуюсь. Что-то там не состыковывается с моими привычками.

4 июня 2013 г.

Gems и другие пакетные менеджеры

Только недавно столкнулся и попробовал использовать rubygems. Ранее все устанавливал через portage. Но частенько стали попадаться статьи, в которых пишут нечто вроде следующего:

gem install git-up
gem install bundle

Это добро у меня вызывало, некоторое недоумение (что еще за левые пакетные менеджеры???) и я бежал искать аналоги в portage. Частенько этого не находилось даже в различных overlay'ях. И вот в один из таких моментов, решив сэкономить время на поиск ebuild'ов, я все-таки выполнил указанную команду. И получил необходимое приложение в ~/.gem/ruby/1.9.1/bin.

Но тут пользователи gentoo столкнуться с некоторым затруднением. Этот дистрибутив не очень дружелюбен для ruby. То, что установится, не будет доступно в PATH. В других используемых мной системах аналогичной проблемы замечено не было. В OS X и Windows (Cygwin) PATH сам без дополнительных движений обновляется.

На bugs.gentoo.org нашел следующее универсальное решение. Создаем в папке /etc/profile файл следующего содержания:

if [[ -L "/usr/bin/ruby" ]]; then
    RUBY=$(readlink /usr/bin/ruby 2> /dev/null)

    case "${RUBY}" in
        *18) VERSION="1.8" ;;
        *19) VERSION="1.9.1" ;;
          *) VERSION="${RUBY##*/}" ;;
    esac

    export PATH="${HOME}/.gem/ruby/${VERSION}/bin:${PATH}"
fi

После этого все будет доступно как надо.

Похоже использовать gem намного удобнее, чем стандартный пакетный менеджер. Тем более на своей локальной машине с фактически одним пользователем (root не считается). Конечно можно добавлять себе постоянно новые overlay и писать новые ebuild. Но как показала моя практика это занимает существенно больше времени. Да и кроме того написание однотипных ebuild не особо интересное занятие. Генератора нету случаем? Не знаю как дело обстоит в других дистрибутивах, но думаю как-то также.

Еще в последнее время натолкнулся на pip для python и npm для node.js. Идея общественных хранилищ для программ, написанных на определенном языке как никак популярна сейчас. И это реально удобно.

3 июня 2013 г.

Личный Firefox Sync

Для синхронизации браузерной информации я использую Firefox Sync. Но совсем недавно замучили проблемы синхронизации. Постоянно появлялась ошибка, что сервер не доступен, хотя на сайте mozilla не было сообщений о каких-то ошибках и неполадках в работе сервиса. Сейчас кстати есть:

The Firefox Sync service is undergoing some load issues, if you are experiencing problems please wait and try again soon. We are working on it presently.

Помучившись так недельку, я решил поднять личный Firefox Sync сервер на своем псевдо сервере. Быстренько нашел ebuild'ы для gentoo. И, вуа-ля, у меня рабочий сервер для синхронизации. Еще я написал init скрипты и выложил свой overlay на github. Если кому-то нужно — пользуйтесь на здоровье.

Плюсы которые обнаружил во время использования личного Firefox Sync сервера:

  • Нет проблем с доступом, точнее их я могу решить сам. Более того, так как я единственный пользователь своего сервера, то нет проблем с загруженностью. А вот доступной поддержки для Firefox Sync не нашел. Признаюсь не сильно и искал.
  • Фактически нет ограничения на размер хранимых данных. Стандартный 5-ти мегабайтный предел я умудрился превысить.

1 июня 2013 г.

Git: Объединение merge коммитов

Возникла у меня на работе необходимость объединить два merge в один. Делал большое и несколько конфликтное слияние. А во время этого в Gerrit на мою ветку успели залить что-то новое, вызвавшее новые конфликты с моим merge. Соответственно необходимо было слить эти изменения тоже. На тот момент я видел следующие варианты:

  • Самый простой способ: сделать еще один merge. В итоге получаем еще один дополнительный commit и разветвленную историю.
  • Сделать полный merge заново. Повторять уже сделанное не хочется.

Я решил найти вариант, позволяющий в результате первого простого способа получить один коммит. Оказалось эта операция не совсем очевидна. Как всегда в последнее время, нашел решение на stackoverflow. Опишу весь процесс с начала до конца с историей тестового репозитория (git log --oneline --graph --decorate):

  • Итак, мы сделали какой-то абстрактный merge master в feature ветку с исправлением всех конфликтов:
$ git checkout feature
$ git merge origin/master
*   b8c37f7 (HEAD, feature) c'
|\
| * 7020561 (origin/master) b
* | 2a55e67 (origin/feature) b'
|/
* b888f61 a
  • Далее кто-то добавил что-то новое на feature ветку:
* 3820f07 (origin/feature) c'
| *   b8c37f7 (HEAD, feature) c'
| |\
|/ /
| * 7020561 (origin/master) b
* | 2a55e67 b'
|/
* b888f61 a
  • Делаем дополнительный merge и видим не особо приятную историю:
$ git merge origin/feature
*   781dea7 (HEAD, feature) d'
|\
| * 3820f07 (origin/feature) c'
* |   b8c37f7 c'
|\ \
| |/
|/|
| * 7020561 (origin/master) b
* | 2a55e67 b'
|/
* b888f61 a
  • А теперь собственно решение с выправлением истории. Делаем reset на коммит, с которого надо делать merge:
$ git reset --soft origin/feature
* 3820f07 (HEAD, origin/feature, feature) c'
* 2a55e67 b'
| * 7020561 (origin/master) b
|/
* b888f61 a
  • Далее симулируем merge с origin/master и делаем commit:
$ git rev-parse origin/master > .git/MERGE_HEAD
$ git commit
*   3b01bf0 (HEAD, feature) d'
|\
| * 7020561 (origin/master) b
* | 3820f07 (origin/feature) c'
* | 2a55e67 b'
|/
* b888f61 a

Как видим в итоге получилась аккуратная история с необходимым полным слиянием веток. Теперь можно делать push. Данный способ можно использовать для объединения любого количества merge коммитов.

По идее надо запрещать людям добавлять новые изменения во время крупных слияний. Так будет возникать меньше затруднительных ситуаций.