Содержание
Репозитории
конфликты – они в головах, а не в репозиториях
— народная мудрость
В прошлый раз мы работали в командной строке и я всячески пресекал попытки сохранять команды в файле, править файл и исполнять команды оттуда.
Я делал это затем, чтобы прежде, чем вы станете писать программы и сохранять их на диске, я хочу вас познакомить с понятием "репозиторий" и научить с ним работать.
Что такое репозиторий и зачем он нужен
Репозиторий – это хранилище файлов, в котором кроме самих файлов хранится ещё и всякая полезная всячина: прежние версии каждого файла, комментарии к каждому изменению и заметка, кто это изменение внёс. Кроме того, репозиторий отвечает за обмен свежими версиями между соавторами проекта.
Зачем он может понадобиться вам? (За исключением того, что я буду требовать, чтобы все плоды вашего труда в рамках моего курса хранились в репозиториях)
Пример. Вы пишете курсовую работу. Вы написали две трети, пришёл научный руководитель, и сказал: "что за ерунда? всё переписать!". Вы переписали снова две трети, пришёл научный руководитель, и сказал: "а в прошлой-то версии 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 прочитать по-русски, то в прошлом году я писал тексик, аналогичный этому, но с другими акцентами: как пользоваться 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, как правило, оказывается тоже довольно просто.