## 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