## page was renamed from Main/Python/2/Record
<<TableOfContents>>

= Репозитории =

{{{#!wiki quote
конфликты -- они в головах, а не в репозиториях

<<Signature(народная мудрость)>>
}}}

В прошлый раз мы работали в командной строке и я всячески пресекал попытки сохранять команды в файле, править файл и исполнять команды оттуда.

Я делал это затем, чтобы прежде, чем вы станете писать программы и сохранять их на диске, я хочу вас познакомить с понятием "репозиторий" и научить с ним работать.

== Что такое репозиторий и зачем он нужен ==

Репозиторий -- это хранилище файлов, в котором кроме самих файлов хранится ещё и всякая полезная всячина: прежние версии каждого файла, комментарии к каждому изменению и заметка, кто это изменение внёс. Кроме того, репозиторий отвечает за обмен свежими версиями между соавторами проекта.

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

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

Второй пример. Собрались вы в соавторстве с кем-нибудь писать работу. Разделили ответственность: я пишу первую половину, ты -- вторую. Написали, склеили -- плохо читается. Потом вам соавтор пишет (спутся два дня -- а вы как раз только обнаружили кучу опечаток и правите их), что он сделал всё хорошо -- и вот результирующий текст. Пристальный просмотр выявляет, что текст-то может и лучше, а всё те же опечатки во всё тех же местах остались. Ещё более пристальный просмотр выявляет, что вы таки не поняли, что же таки соавтор поправил и вы идёте с ним выянять, которые из 200 страниц вам надо перечитывать на тему улучшений.

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

== Работа в darcs ==

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

Все команды, которые я пишу на этом занятии -- команды UNIX (или Linux -- как хотите называйте). {{{$}}} в начале строки символизирует приглашение командной строки (у вас оно наверняка не совсем такое). Команды следует исполнять на kodomo через ssh (напр. !PuTTY) и не забывать о том, что домашняя директория в Linux у вас совпадает с диском H: в windows -- редактировать вам вероятнее всего удобнее будет в windows.

== Создание репозитория ==

Итак, создавать репозиторий можно двумя способами, создать пустой репозиторий:

{{{
$ mkdir project
$ cd project
$ darcs init
}}}

или присоединиться к чужому репозиторию:

{{{
$ darcs get .../project
Copying patches, to get lazy repository hit ctrl-C...
Finished getting.
$ cd project
}}}

внутри репозитория лежит папочка {{{_darcs}}}, в которой, собственно, и хранится вся история проекта, настройки, и прочая служебная-вспомогательная ерунда. Не трогайте эту папочку почём зря.

== Запись изменений ==

Теперь, предположим, мы хотим создать в репозитории новый текстовый файл. (Важное замечание: вообще, в репозитории лучше хранить именно текстовые файлы. К ним относятся что обычные тексты, набранные, например, в FAR, что исходные коды программ большинства языков программирования. А вот файлы word к ним не относятся -- их, конечно, тоже можно хранить в репозитории, но толку от этого будет уже не ощутимо больше, чем от того, чтобы просто хранить отдельными нумерованными файлами старые версии и приписывать к ним руками комментарии, что где поменялось).

{{{
$ редактируем hello.txt, пишем туда Hello, wnoderful world!
$ cat hello.txt
Hello, wnoderful world!
$ darcs add hello.txt
$ darcs record hello.txt
... [тут начинается диалог с darcs на тему того, что записывать, а что нет -- мы представляемся системе (только в первый раз), говорим записать всё, добавляем комментарий "added hello.txt with dummy message" и отказываемся писать длинное описание изменения] ...
}}}

Командочка {{{cat}}} к {{{darcs}}} не имеет никакого отношения. Она выводит на экран содержимое файла. Привожу я её здесь, чтобы показать, в каком состоянии находится проект в тот момент, когда мы начинаем работать с {{{darcs}}}.

Команда {{{darcs add hello.txt}}} говорит {{{darcs}}} о том, что отныне он должен следить за изменениями ещё и в файле {{{hello.txt}}}. При этом в истории изменений с точки зрения репозитория файл {{{hello.txt}}} ещё не появился.

Команда {{{darcs record hello.txt}}} (сокращается до {{{darcs rec}}}) говорит {{{darcs}}} записать некоторые из изменений, случившихся с файлом {{{hello.txt}}} в историю внутри репозитория. Вспоминаем, что одно из главных назначений репозитория -- вспомнить потом, где нужно искать нужный фрагмент текста, или же сообщить соавтору, что изменилось, чтобы он понимал, что с этим делать. При записи изменений нужно сопроводить изменение комментарием. Комментарий должен быть достаточно короткий, описывать суть изменения полностью, и быть достаточно специфичным ("очередная запись в репозиторий" -- это короткое и полное описание, но оно недостаточно специфично, из него нельзя понять, что же именно произошло)...

И тут мы заметили, что в содержимом у нас опечатка!

{{{
$ редактируем hello.txt, пишем туда Hello, wonderful world!
$ cat hello.txt
Hello, wonderful world!
$ darcs whatsnew
hunk ./hello.txt 1
-Hello, wnoderful world!
+Hello, wonderful world!
$ darcs rec
... [снова диалог с darcs, на сей раз изменение назовём "hello.txt: fixed typo"] ...
$ darcs changes
Sat Sep 19 17:55:11 MSD 2009  Danya Alexeyevsky <dendik@localhost>
  * hello.txt: fixed typo

Sat Sep 19 17:54:15 MSD 2009  Danya Alexeyevsky <dendik@localhost>
  * added hello.txt with dummy message
}}}

Очень полезная (на мой вкус) команда {{{darcs whatsnew}}} (сокращается до {{{darcs wh}}}) сообщает, что изменилось в рабочей директории по сравнению с последним записанным изменением.

Командочка {{{darcs changes}}} выдаёт то, как увидят ваши правки в первую очередь ваши соавторы. Да и вы, когда будете искать прежнюю версию, тоже будете смотреть именно сюда, чтобы выяснять, в какой именно версии затерялись полезные строчки. (Или просто ностальгии ради).

И так далее. Всё, что нужно для работы в репозитории в-одиночку -- это команда {{{darcs record}}} и изредка {{{darcs add}}}. Добавьте команд по чтению истории по вкусу, -- и вы получили ответ на первый вопрос -- как хранить хронологию изменений к чему-нибудь (тексту или программе).

== Обмен изменениями между репозиториями (и соавторами) ==

Наконец, третья группа команд -- обмен изменениями между репозиториями. Предположим, что вы создали репозиторий с помощью {{{darcs get}}} (тогда {{{darcs}}} уже знает, откуда он его получил, и ему не нужно подсказывать, куда отправлять ваши изменения).

{{{
$ darcs get .../project
...
$ cd project
$ ls
hello.txt
$ редактируем hello.txt, допишем несколько страниц об истории фразы "hello world"...
$ darcs rec
...
$ darcs push
...
}}}

Команда {{{darcs push}}} отправляет все записанные изменения туда же, откуда вы скачали репозиторий.

Спустя два дня:

{{{
$ darcs pull
$ редактируем hello.txt, обнаруживаем в нём новую главу -- об области применения фразы "hello world"
$ rm hello.txt
$ darcs rec
... [комментарий: "removed obsolete hello.txt"]
$ darcs push
}}}

Команда {{{darcs pull}}} вытягивает в локальный репозиторий изменения, которые сделал соавтор. Казалось бы, досадно удалять файл, на который вы с соавтором потратили два дня -- но помните, в каждом из вашего репозитория и репозитория соавтора хранится вся история его изменений, а значит, и, например, последнюю его версию вытащить из репозитория не проблема (как? читайте документацию!). {{{darcs record}}} увидит удаление файла как два изменения: сначала вы стёрли в файле каждую строку, и лишь потом сказали {{{darcs}}} удалить сам файл. Когда ваш коллега скажет {{{darcs pull}}}, файл {{{hello.txt}}} у него в рабочей директории исчезнет (а история и возможность отменить удаление файла останутся).

Тут всё было бы хорошо, если бы все соавторы работали по очереди. (Только тогда вопрос, а зачем и репозиторий то был бы нужен, так можно было бы и просто дисциплину между собой устроить и файлы пересылать с наказом "не думай (дабы не потерять умную мысль), пока к тебе не придёт последняя версия файла"). В жизни может так случиться, что два автора одновременно поправят в одном и том же файле одно и то же место. Такая ситуация называется "конфликт", и поступает в таком случае репозиторий следующим образом: тому, кто первым наткнётся на такое противоречие он сообщит, что случился конфликт, разметит, где случился конфликт, и предложит решить, что с этим делать.

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

Первый тип конфликтов хороший. Если он случился (а случиться он может только во время {{{darcs pull}}}), то {{{darcs}}} вам разметит в том файле, который вы вот сейчас прямо редактируете стрелочками и звёздочками фрагмент файла, в котором хранится версия вашего соавтора и соответствующий ему кусок в том же месте, который только что написали вы. {{{darcs whatsnew}}} очень полезна в этом случае, чтобы увидеть эти стрелочки и понять, где же именно находится конфликт. Чтобы его разрешить, нужно посмотреть на получившиеся две версии и собрать из них одну осмысленную -- тут совет один: полагаться на здравый смысл. Важно (/!\): {{{darcs record}}} этих самых стрелочек да чёрточек, которыми {{{darcs}}} разметил конфликт, увидеть не должен (это должно следовать очевидным образом из того же здравого смысла; если оно не следует из здравого смысла, подуймайте снова и выберите себе более подходящий здравый смысл для ситуации).

Второй тип конфликтов (если ими изрядно увлечься) может выцепить в теории, на которой строится {{{darcs}}}, слабое место. Тогда могут возникнуть проблемы с работоспособностью и производительностью {{{darcs}}}. Правду скажу: я всегда опасаюсь конфликтов второго типа и делаю всё, чтобы их не случилось. Впрочем, когда в ситуациях из реальной жизни они случаются, оказывается чаще, что их легко разрешить, точно так же, как и конфликты первого рода.

Как избегать второго типа конфликтов? Нужно придерживаться достаточно строгой дисциплины работы с репозиторием: всегда перед record и push делать pull, притом желательно тратить поменьше времени на record (дабы другой соавтор влезть не успел и всё попортить):

{{{
$ darcs pull -a && darcs rec -a -m "..." && darcs push -a
}}}

== Документация ==
В {{{darcs}}} встроена хорошая документация. Читайте {{{darcs help}}} или {{{darcs команда --help}}}.

Прекрасное руководство по {{{darcs}}} на английском языке обитает тут: http://darcs.net/manual (оно меняется вслед за версиями {{{darcs}}} -- сейчас оно соответствует той версии, которая установлена на {{{kodomo}}} и {{{kodomo-count}}}).

Судя по всему, русская документация, какая была, канула в лету с обновлением сайта darcs.net.

Если у вас не уложилось в голове, зачем нужен репозиторий и как им пользоваться, то это лечится всё-таки только практикой, а по мелочи подглядывать уж, я надеюсь, каждый из вас осилит и английскую документацию (не верю я, что среди вас есть люди, которые всегда заранее знают, что из плодов собственного труда можно стирать, а что лучше оставить -- и только такие люди могли бы говорить, что репозитории им не нужны). Если же вы всё-таки хотите что-то ещё про darcs прочитать по-русски, то в прошлом году я писал тексик, аналогичный этому, но с другими акцентами: [[Courses/Python/Notes/Darcs|как пользоваться darcs]].

== Полезные добавки ==

Полезные замечания для тех, кто ленится читать help или хотя бы контекстную помощь в диалогах с {{{darcs}}}:
 * Почти во всех диалогах с darcs есть варианты ответов y -- yes, n -- no, a -- yes to all
 * Команды {{{record}}}, {{{push}}}, {{{pull}}} и многие другие принимают флаг {{{-a}}}, который означает то же самое, что если бы вы сказали "{{{a}}}" (yes to all) в первом же диалоге команды
 * У команды {{{record}}} есть параметр {{{-m "change description"}}}. Если он указан, {{{record}}} не будет спрашивать описание изменения.
 * Большинству команд можно (например, {{{darcs whatsnew}}}) давать в качестве аргумента список файлов, тогда они будут делать то же, что и обычно, но ограничивать свой интерес только перечисленными файлами.

== Историческая демагогия (наверное, близкая к исторической справке) ==

Видимо, история репозиториев начинается с создания команд diff и patch (живых и активно используемых и поныне), первая из которых умела сравнивать два файла (старый и новый) и выдавать построчные различия между ними -- соучастник проекта правил какой-нибудь файл, делал diff между старой и новой версией и слал автору проекта с комментарием, что он исправил. Автор проекта использовал patch и менял старый файл так, чтобы он совпадал с тем, как оно было у соучастника. Командочки diff и patch возникли на заре UNIX (если не раньше) и им много больше лет, чем каждому из нас или вас.

Следующей возникла командочка rcs (Revision Control System), которая умела хранить историю изменений одного файла в соеднем файлике в виде последовательностей тех самых diff'ов с комментариями и датами.

Сильно позже и этой командочки стало не хватать, и возник монстр под названием CVS (Concurrent Versioning System), который являлся обвязкой к rcs, и был, в сущности полноценной системой контроля версий, в которую с каждым годом запихивали коленкой каждую новую идею, которая казалась авторам полезной.

Долгое время именно CVS являлся стандартом для совместной разработки программ, но у него было несколько неприятностей: он обязательно требовал наличия "администратора репозитория" в проекте, он был довольно сложен, и для некоторых задач его возможностей не хватало.

Где-то годах в 90-х оказалось довольно много способных программистов, которые видели эти недостатки и пытались их решать. Тогда появились проекты: SVN (subversion), GNU Arch (tla), darcs, mercury, bazaar, git и пр. Имя им легион.

Я рассказываю вам про darcs, как репозиторий, с которым проще всего (на мой субъективный вкус) работать. Darcs возник из курсовой, а затем аспирантской (точнее, ph.d.) работы физика David Roundy на тему "теория патчей".

С другой стороны, самый популярный среди программистов репозиторий сейчас git, который умеет всё то же, что и darcs (и много больше -- чем сторонники git хвастаются -- но нужно ли оно на самом деле?), но чтобы работать с git, нужно освоить существенно больше теории (о том, как git устроен). Впрочем, переходить с darcs на git, как правило, оказывается тоже довольно просто.

/*

== План ==
 * darcs
  * откуда оно?
   * "была хорошая мысль неделю назад, которую я написал и стёр"
    * как выглядел файл неделю назад -> что я изменил неделю назад
   * между программистами: обмен файлов -- медленно => обмен патчами
   * между программистами: ну хорошо, вот она твоя версия, а что изменилось? (changelog)
   * между программистами: ты поправил там, а я поправил тут, и как из этого сделать что-то, что работает?
  * как работать:
   * darcs init
   * darcs add, darcs record
   * darcs pull, darcs push
   * help
  * конфликты (!)
   * pull - rec - rec - rec - push