четверг, июня 19, 2008

Deployment и Git

Сперва - что такое deployment?

Буквальный перевод - развертывание. Речь идет о том, чтобы заставить код, написанный разработчиком в своей песочнице, заставить работать в реальных условиях на "боевых серверах". И вот во что это выливается даже в случае с одним разработчиком:

Мой нынешний проект я разрабатываю/тестирую на своем домашнем сервере (dev-сервер, это называется). А недавно выложил на хостинг - это, так сказать, production-сервер (ну, на самом деле, это пока что разновидность тестирования). И тут появляются некоторые ньюансы:

  • на dev- и production- серверах нужны разные настройки кода (например, разные пароли для коннекта к БД);

  • на dev-сервере я продолжаю разработку, добавляю новые фичи и пр. Хотелось бы, чтобы новые фичи и в production-варианте появлялись;

  • на production-сервере вылезают некоторые баги, которые по разным причинам на dev не вылезали, их приходится фиксить. Хотелось бы, чтобы эти же баги были пофиксены и в dev-версии;

  • Т.к. код еще не доведен "до кондиции", при переносе выясняется, что кое-где он написан неуниверсально (зависит от специфики того места, где работает). Для работы production-сервере его приходится после выкладывания обобщать. Конечно, нужно, чтобы и в dev-версии он был не менее общим;

  • Некоторые изменения, сделанные в коде production-версии, всё-таки специфичны именно для данного конкретного хостинга. Они в версии на dev-сервере мне совсем не нужны;

  • Кроме всего этого, я хочу держать актуальную версию кода в публичном месте, чтобы любой желающий мог его скачать.

Несложно догадаться, что при попытке выполнять все эти требования "вручную" - очень быстро запутаешься в трех соснах (то бишь, версиях). Для упрощения deployment-а существует довольно много всяких разных решений. Одно из возможных - использовать Git.

Предположим, код на dev-сервере уже под контролем git. Тогда для разворачивания проекта делаем:

user@production.server:/project$ git init
user@dev.server:~/project$ git push ssh://production.server/project master

Собственно, теперь на production.server в директории /project/ имеем копию кода с dev-сервера. Далее:

user@production.server:/project$ git branch production
user@production.server:/project$ git checkout production

Это мы создали новую ветвь репозитория и переключились в нее. Теперь изменяем настройки, тестируем, фиксим баги… не забываем после каждого логически завершенного изменения делать "git commit -a" - фиксировать изменения в репозитории.

При внесении изменений в код на dev-сервере их, конечно, тоже фиксируем. Когда захотим обновить версию на production, делаем:

user@dev.server:~/project$ git push
user@production.server:/project$ git merge master

— вливаем изменения в ветви master в production. Если нужно применить только последнее изменение в master (последний коммит), вместо git merge делаем git cherry-pick.

Чтобы применять нужные изменения, сделанные на production, к dev-версии, делаем:

user@dev.server:~/project$ git remote add prod ssh://production.server/project

— создаем ссылку на удаленный репозиторий,

user@dev.server:~/project$ git fetch prod/production

— получаем код из ветви production,

user@dev.server:~/project$ git cherry-pick prod/production

— это если нужно применить последнее изменение в production, или

user@dev.server:~/project$ git cherry-pick идентификатор-коммита

— если нужно применить произвольный коммит.

7 комментариев:

  1. хм. А чем от того же subversuion отличается?

    ОтветитьУдалить
  2. Проще сливать ветки. Ну и не нужен центральный репозиторий. А так да, многие афаик используют svn для деплоймента.

    ОтветитьУдалить
  3. Прикольно. Буду знать.

    ОтветитьУдалить
  4. а у меня при поытке запушить с дева в пустой репо прода - ошибка:

    remote: error: refusing to update checked out branch: refs/heads/master
    remote: error: By default, updating the current branch in a non-bare repository
    remote: error: is denied, because it will make the index and work tree inconsistent
    remote: error: with what you pushed, and will require 'git reset --hard' to match
    remote: error: the work tree to HEAD.
    remote: error:
    remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
    remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
    remote: error: its current branch; however, this is not recommended unless you
    remote: error: arranged to update its work tree to match what you pushed in some
    remote: error: other way.
    remote: error:
    remote: error: To squelch this message and still keep the default behaviour, set
    remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

    ОтветитьУдалить
  5. нашел решение здесь http://jenyay.net/Programming/Git

    ОтветитьУдалить
  6. Мой пример https://intsystem.org/server/gitolite-avtodeploj-dev-ili-kak-ya-rabotayu-s-git/

    ОтветитьУдалить