<?xml version='1.0' encoding='utf-8' ?>
<!--  If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/  -->
<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:media='http://search.yahoo.com/mrss/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>The Lost and The Found</title>
  <link>http://los-t.livejournal.com/</link>
  <description>The Lost and The Found - LiveJournal.com</description>
  <lastBuildDate>Wed, 16 Sep 2009 15:54:17 GMT</lastBuildDate>
  <generator>LiveJournal / LiveJournal.com</generator>
  <lj:journal>los_t</lj:journal>
  <lj:journalid>8498532</lj:journalid>
  <lj:journaltype>personal</lj:journaltype>
  <atom10:link rel='hub' href='http://pubsubhubbub.appspot.com/' />
  <image>
    <url>http://l-userpic.livejournal.com/83123324/8498532</url>
    <title>The Lost and The Found</title>
    <link>http://los-t.livejournal.com/</link>
    <width>100</width>
    <height>100</height>
  </image>

<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/22812.html</guid>
  <pubDate>Wed, 16 Sep 2009 15:54:17 GMT</pubDate>
  <title>Что означает &quot;Реальное время&quot;.</title>
  <link>http://los-t.livejournal.com/22812.html</link>
  <description>В последнее время приходится достаточно часто разговаривать и переписываться с людьми, которые часто употребляют термин &quot;реальное время&quot; и &quot;ОС реального времени&quot;. И, судя по контексту обсуждения, многие плохо себе представляют, что же это такое, как в таких ОС осуществляется планирование, как расставлять приоритеты задач в таких системах и т.д.&lt;br /&gt;&lt;br /&gt;Если и вы из таких людей, то возможно вам будет интересно то, что под катом... Но предупреждаю - букв Реально много.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Например, часто встречается мнение, что более важные для работы процессы должны получать больший приоритет, а менее важные - меньший. То есть решение о планировании таких процессов принимается исходя из каких-то априорных соображений типа &quot;ввод-вывод должен быть побыстрее, технологическая задача должна иметь средний приоритет, а уж связь с системами верхнего уровня должна быть самой низкоприоритетной&quot;.&lt;br /&gt;&lt;br /&gt;Звучит в общем-то разумно, не правда ли?&lt;br /&gt;&lt;br /&gt;Также бытует мнение, что ОСРВ работает &quot;быстрее&quot; и &quot;надежнее&quot;, и что если взять обычную систему, и перенести ее в РВ-окружение, то все магическим образом будет работать правильно.&lt;br /&gt;&lt;br /&gt;На вопрос &quot;а с чего должно быть быстрее&quot;, обычно отвечают - &quot;ну как же, это ж РЕАЛ-ТАЙМ! Он ГАРАНТИРУЕТ, что все выполнится в выставленные сроки!&quot;.&lt;br /&gt;&lt;br /&gt;Как правило, в качестве определения системы реального времени приводится некий &quot;отказ&quot;, если какая-то операция не укладывается в гарантированные рамки. По этому отказу могут проводиться какие-то контраварийные действия, например остановка производства, срабатывание систем противоаварийной защиты, все рабочие на производстве срочно натягивают строительные каски на головы и быстро покидают объект... Это жесткое (hard) Реальное Время. Звучит страшно, и внушает уважение к этому &quot;реальному жосткому времени для реальных жостких пацанов&quot;. &lt;br /&gt;&lt;br /&gt;В действительности же, в большинстве ситуаций, необходимости в такой обработке ситуации &quot;превышение временных рамок или дедлайна&quot; нет... Как правило, программист обрабатывает такую ситуацию, просто повторяя неудавшийся запрос. Такое &quot;ленивое&quot; реальное время еще называют &quot;мягким (soft)&quot;.&lt;br /&gt;&lt;br /&gt;Так что же такое - это самое Реальное Время? Чтобы понять это, представим систему, которая закручивает крышечки бутылок Nuka-Cola на заводе. Допустим, это большой конвейер, на который выставляются пустые бутылки, они подходят к аппарату, заполняющему их свежей ну-ка-колой, выходят с другой стороны и поступают к роботу, закручивающему крышечки.&lt;br /&gt;&lt;br /&gt;Для простоты представим, что конвейер движется со скоростью одна бутылка в секунду. То есть за одну секунду лента конвейера успевает подать новую бутылку, дождаться пока автоматы по всей линии конвейера сделают свои дела (заполнят бутылку, накрутит крышку, наклеят этикетку etc), и сдвинуть ленту дальше, чтобы подать следующую бутылку. Таким образом, на таком конвейере все передвижения ленты происходят с периодичностью в секунду. Эта величина называется периодом выполнения задачи (task period), обозначим ее как Т = 1000 мс.&lt;br /&gt;&lt;br /&gt;Далее, допустим что на запуск, протяжку и остановку ленты, тоже тратится некоторое время (из этой одной секунды), и работа всех механизмов во время протяжки ленты невозможна. Например, на протяжку тратится 200 мс из каждой секунды, так  что с момента остановки ленты до момента начала её движения остается 800 мс, и работа всех агрегатов конвейера должна быть завершена за это время. Это время называется дедлайном (deadline) задачи, обозначим его как D = 800 мс.&lt;br /&gt;&lt;br /&gt;Теперь рассмотрим только робота, закручивающего крышки. Допустим, что робот устанавливает и закручивает крышку за 200 мс. Эта величина называется временем исполнения (computation time), обозначим ее как C.&lt;br /&gt;&lt;br /&gt;Что же получилось в итоге? Каждую секунду к роботу подъезжает новая бутылка, он за 200 мс закручивает ее крышку, и остается еще 600 мс до того, как лента начнет двигаться, и 800 мс до подъезда следующей бутылки. Итого, робот работает только 20% (200 мс / 1000 мс * 100%), а остальное время ничего не делает. Величина, равная отношению времени исполнения к периоду исполнения, называется загруженностью (utilization) и обозначается как U. В такой системе робот всегда выполняет все свои задачи в срок, и это - система жесткого реального времени.&lt;br /&gt;&lt;br /&gt;Но для такого дорогого оборудования, 20% загрузка это слишком мало. И тут инженеру, изнывающему без премий, приходит в голову гениальная мысль! А что если поставить рядом две конвейерные ленты, а робота снабдить поворачивающимся основанием? Тогда он сможет закручивать крышки на двух лентах, периодически переключаясь между ними. Все довольны, руководство завода пропивает стоимость второго робота вмести с изобретательным инженером.&lt;br /&gt;&lt;br /&gt;Но возможно ли это сделать так, чтобы не приходилось останавливать конвейеры? То есть, можно ли сделать так, чтобы все задачи выполнялись до достижения дедлайна? Этот вопрос придётся решать бедняге инженеру, когда он проспится после грандиозной попойки и придёт программировать робота.&lt;br /&gt;&lt;br /&gt;Допустим, второй конвейер разливает не ну-ка-колу, а нано-колу. Она менее вязкая, в результате чего удалось поднять скорость второго конвейера до одной бутылки за 600мс. T&apos; = 600 мс.&lt;br /&gt;При этом лента его движется с той же скоростью, что и у первого. затрачивая те же 200 мс на протяжку. То есть время дедлайна равно D&apos; = 400 мс. Время закручивания крышки оставляем тем же - 200 мс (C&apos; = C = 200 мс).&lt;br /&gt;&lt;br /&gt;Также, требуется определенное время для переключения робота с одной ленты на другую. Допустим, что робот у нас поворачивается за 200 мс. Это время называется временем переключения контекста.&lt;br /&gt;&lt;br /&gt;Задача распределения робота между этими двумя лентами, так чтобы дедлайны не превышались - это и есть типичная задача планирования в системах реального времени. &lt;br /&gt;&lt;br /&gt;Начинается ее решение с того, что проверяется суммарная загрузка системы, не превышает ли она 100%. Если превышает - то задача в принципе не решаемая, какой-то из конвейеров придется тормозить. Эта величина складывается как сумма загруженностей отдельных лент.&lt;br /&gt;&lt;br /&gt;В нашем случае она равна U + U&apos; = C/T + C&apos;/T&apos; = 200/1000 + 200/800 = 0.45, то есть 45%. Это не так уж много. Теперь посмотрим, удастся ли найти такой алгоритм планирования, который бы не превышал дедлайны, с учетом времени переключений контекста. Для иллюстрации процесса очень полезно иметь при себе диаграмму процесса, подобную приведенной на рисунке 1.&lt;br /&gt;&lt;br /&gt;Верхняя линия - это более медленный конвейер, нижняя - более быстрый. Стрелочками показаны переключения  робота между линиями, звездочками - закручивание крышек. Закрашенными прямоугольниками показываются дедлайны, промежутки между ними - это протягивание линии. Серый прямоугольник - простой робота.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;img src=&quot;http://www.ljplus.ru/img4/l/o/los_t/realtime_1.png&quot; width=&quot;381&quot; height=&quot;61&quot; alt=&quot;Рисунок 1 4.25 КБ&quot;&gt;&lt;br&gt;Рисунок 1.&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Это диаграмма показывает планирование на протяжении 4 секунд. После окончания четырех секунд, робот находится в том же положении, что и был изначально, так что такое планирование можно &quot;зациклить&quot;. Как видно, задача планирования решена - все крышки закручены вовремя. Но какой ценой? Робот простаивал только 400 мс из всех четырех секунд, то есть реальная загрузка с учетом переключений составила 90%! В два раза больше расчетных 45% (без учета переключений контекста).&lt;br /&gt;&lt;br /&gt;В общем и целом, каждую конкретную систему так, вручную распланировать конечно не получится. В обычной промышленной системе таких задач могут быть десятки, и к одновременному старту могут быть готовы сразу несколько. Поэтому на помощь приходят алгоритмы планирования.&lt;br /&gt;&lt;br /&gt;Делятся они, в основном, на два типа - динамические и статические. Динамические планировщики оперируют в предположении, что каждая задача сообщает планировщику, какой у нее период, и каков дедлайн, а также время исполнения, так что планировщик в любой момент знает, когда нужно переключать процессы.&lt;br /&gt;В качестве примера динамического планирования можно привести алгоритм Ealiest Deadline First (EDF). Когда имеются две задачи, между которыми нужно выбирать, выбирай ту, у которой раньше всего истечет дедлайн. Такой планировщик требует наиболее точных знаний о системе, но зато, позволяет нагрузить все 100% ресурсов (система остается планируемой даже если суммарная загрузка равна 100%).&lt;br /&gt;&lt;br /&gt;Статические планировщики производят планирование по приоритетам. Каждой задаче назначается свой приоритет (в соответствии с алгоритмом планирования), и далее, планировщик всегда выбирает процесс с наибольшим приоритетом. Одним из примеров таких алгоритмов является Rate-monotonic Scheduling (RMS). В нем приоритеты назначаются согласно длительности цикла задачи - чем меньше T, тем больше приоритет. Для такой системы, чтобы оставаться планируемой, необходима загрузка меньше чем определенное число, обычно большее чем 69%.&lt;br /&gt;&lt;br /&gt;Вышеприведенные рассчеты с роботом подразумевают, что задачи могут работать совершенно независимо друг от друга, не имея никаких общих ресурсов кроме времени робота. Чаще всего это не так. Между процессами обычно происходят взаимодействия, синхронизации, так что один может заблокировать выполнение другого (например, семафором).&lt;br /&gt;&lt;br /&gt;Впрочем, об инверсии приоритетов, пожалуй, в следующий раз, если кому-нибудь это вообще интересно.&lt;br /&gt;</description>
  <comments>http://los-t.livejournal.com/22812.html</comments>
  <category>realtime</category>
  <lj:security>public</lj:security>
  <lj:reply-count>11</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/22775.html</guid>
  <pubDate>Tue, 28 Apr 2009 07:31:03 GMT</pubDate>
  <title>Посоветуйте новый телефон</title>
  <link>http://los-t.livejournal.com/22775.html</link>
  <description>В очередной раз сломалась гарнитура для K750i (стоимостью в 800 р), что повергло меня в уныние, потому что количество кровно заработанных рубликов, потраченных на проводные гарнитуры, уже вплотную подбирается к стоимости телефона, который у меня кстати уже три года.&lt;br /&gt;&lt;br /&gt;В связи с этим возникла необходимость сменить телефон на что-то более современное, с поддержкой высокоскоростного GPRS/EDGE, а то обычный тормозной GPRS в K750i уже достал.&lt;br /&gt;&lt;br /&gt;Также необходимы следующие штуки:&lt;br /&gt;1) Стандартный разъем для подключения к компу/подзарядки (предпочтительно mini-USB)&lt;br /&gt;2) Стандартный разъем для подключения наушников (предпочтительно mini-jack).&lt;br /&gt;3) Поддержка внешних карт памяти (предпочтительно SD)&lt;br /&gt;4) FM-радио, и MP3-плеер внутри&lt;br /&gt;5) Фотокамера с автофокусом, автоматическим балансом белого, разрешение не менее 2 мегапикселей.&lt;br /&gt;6) Bluetooth обязателен, Wi-Fi опционален.&lt;br /&gt;7) Поддержка в Linux в качестве GPRS модема.&lt;br /&gt;8) Громкий будильник&lt;br /&gt;&lt;br /&gt;Ну и чтоб не сдыхал после дня использования в качестве радио или плеера.&lt;br /&gt;&lt;br /&gt;Может кто-то может что-нибудь посоветовать? Иначе придется разоряться на новую гарнитуру и терпеть тормознейший GPRS.</description>
  <comments>http://los-t.livejournal.com/22775.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>9</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/22373.html</guid>
  <pubDate>Thu, 27 Nov 2008 08:43:02 GMT</pubDate>
  <title>National</title>
  <link>http://los-t.livejournal.com/22373.html</link>
  <description>Когда читаю российскую прессу (в частности, Компьютерру), глаз всегда спотыкается на расшифровках различных американских названий типа NASA, NBA, NPR, National Geographic и т.п. Везде &quot;National&quot; переводится как &quot;Национальный/ая/ое&quot;.&lt;br /&gt;&lt;br /&gt;Ну, для американцев, создающих эти названия для внутреннего пользования, слово &quot;National&quot; в общем-то понятно. У них там штаты - как отдельные государства, поэтому для обозначения &quot;общештатовских&quot; понятий используются прилагательные Федеральный и Национальный.&lt;br /&gt;&lt;br /&gt;Но для нас, иностранцев, считаю, правильнее переводить National как Американский. Мы ж не в дефолт-стране живем.&lt;br /&gt;&lt;br /&gt;Итого получается - &lt;br /&gt;NHL - Американская Хоккейная Лига&lt;br /&gt;NBA - Американская Ассоциация Баскетбола&lt;br /&gt;NPR - Американское Общественное Радио&lt;br /&gt;NASA - Американское Аэрокосмическое Агенство&lt;br /&gt;National Geographic - Американское Географическое Сообщество&lt;br /&gt;&lt;br /&gt;И т.п.&lt;br /&gt;&lt;br /&gt;Кстати, в отличие от Дефолт-страны, в Великобритании любят слово British. ;)</description>
  <comments>http://los-t.livejournal.com/22373.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>17</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/22270.html</guid>
  <pubDate>Tue, 25 Nov 2008 16:04:59 GMT</pubDate>
  <title>C++ FQA</title>
  <link>http://los-t.livejournal.com/22270.html</link>
  <description>[21.6] Is a Circle a kind-of an Ellipse?&lt;br /&gt;FAQ: Sometimes it is, most frequently it isn&apos;t.&lt;br /&gt;&lt;br /&gt;Q: But I have a Ph.D. in Mathematics, and I&apos;m sure a Circle is a kind of an Ellipse! Does this mean Marshall Cline is stupid? Or that C++ is stupid? Or that OO is stupid?&lt;br /&gt;&lt;br /&gt;FAQ:  It means a different thing: your intuition is wrong in the sense that it leads you to make wrong decisions about inheritance. The right way to think about &quot;kind-of&quot; is this: B is a kind of A if you can always substitute a B for an A. &lt;br /&gt;&lt;br /&gt;FQA: Instead of admitting that OO is not a natural language, and it doesn&apos;t have to map directly to a natural language, the FAQ actively tries to persuade you to change the way you use natural language words to make your thinking OO-compatible. Next, they&apos;ll ship patches you should apply to your DNA, and a sticker saying &quot;Designed for C++ Programming&quot; for your skull. &lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://yosefk.com/c++fqa/inheritance-proper.html&quot;&gt;http://yosefk.com/c++fqa/inheritance-proper.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Читаю уже неделю потихоньку, ржу в голос.</description>
  <comments>http://los-t.livejournal.com/22270.html</comments>
  <category>c++</category>
  <category>wtf</category>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/21958.html</guid>
  <pubDate>Sat, 15 Nov 2008 14:47:27 GMT</pubDate>
  <title>Еще один тест (стырено у icesik)</title>
  <link>http://los-t.livejournal.com/21958.html</link>
  <description>&lt;table border=&quot;0&quot; style=&quot;width: 400px; border: 1px solid #EEEEEE;&quot;&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center; margin: 0px; padding: 8px; background-color: #006680; color: #FFFFFF; font: 16px Arial&quot;&gt;есть люди  - Скалы&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;text-align: left; padding: 8px; background-color: #FFFFFF; color: #000000; font: 12px Arial&quot;&gt;С ними всегда можно быть уверенным, что ничего не случится и что всегда находишься под защитой. есть на кого опереться и положиться в трудной ситуации. Они тверды и решительны, и никогда не отступают от своих решений&lt;img src=&quot;http://i006.radikal.ru/0803/ab/ef4f1208d1ee.jpg&quot; align=&quot;left&quot; alt=&quot;image&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center; margin: 0px; padding: 8px; background-color: #006680; font: 12px Arial&quot;&gt;&lt;a href=&quot;http://aeterna.ru/test.php?link=tests:34757&quot; style=&quot;color: #FFFFFF&quot;&gt;Пройти тест&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Похоже.</description>
  <comments>http://los-t.livejournal.com/21958.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/21751.html</guid>
  <pubDate>Tue, 21 Oct 2008 17:42:34 GMT</pubDate>
  <title>git 1.6.0</title>
  <link>http://los-t.livejournal.com/21751.html</link>
  <description>В Сизиф приехал новый git. В нем принято решение убрать из PATH команды типа git-foo, оставив там только git. Итого для работы приходится использовать git foo вместо git-foo.&lt;br /&gt;&lt;br /&gt;Из этой ситуации есть два выхода. Первый - пройтись по всем своим самописным скриптам с sed -i &quot;s/git-/git /g&quot;. После чего приучать свои пальцы вместо минуса пробел рисовать.&lt;br /&gt;&lt;br /&gt;Второй способ легче - добавляете в PATH /usr/libexec/git-core.&lt;br /&gt;И живете как раньше.</description>
  <comments>http://los-t.livejournal.com/21751.html</comments>
  <category>alt linux</category>
  <category>sisyphus</category>
  <category>привычки</category>
  <category>git</category>
  <lj:security>public</lj:security>
  <lj:reply-count>4</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/21249.html</guid>
  <pubDate>Tue, 14 Oct 2008 12:43:23 GMT</pubDate>
  <title>Успехи прикладной лоботомии</title>
  <link>http://los-t.livejournal.com/21249.html</link>
  <description>&lt;a href=&quot;http://www.adme.ru/sberbank/2008/09/11/23801/&quot;&gt;http://www.adme.ru/sberbank/2008/09/11/23801/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Новые маскоты сбербанка - лоботомированные вкладчики без мозга, Сберик и Сберочка:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://www.adme.ru/files/comment/part_13/preview129091_1221075639.jpg&quot; alt=&quot;Сберик&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://www.adme.ru/img/news/23801/sn.jpg&quot; alt=&quot;Сберочка&quot;&gt;&lt;br /&gt;&lt;br /&gt;Дизайнерам - EPIC FLAIL.&lt;br /&gt;&lt;br /&gt;Это ожившие эмблемы Сбербанка, которые в свою очередь означают кошелек.</description>
  <comments>http://los-t.livejournal.com/21249.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>4</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/21031.html</guid>
  <pubDate>Tue, 30 Sep 2008 07:44:20 GMT</pubDate>
  <title>Преимущество Linux для образования</title>
  <link>http://los-t.livejournal.com/21031.html</link>
  <description>&lt;a href=&quot;http://sevik.ru/syslinux/&quot;&gt;http://sevik.ru/syslinux/&lt;/a&gt;&lt;br /&gt;.....&lt;br /&gt;   Несмотря на разнообразие посвященной ядру Linux литературы, единственным заведо-&lt;br /&gt;мо актуальным источником информации о ядре являются исходные тексты используемой&lt;br /&gt;версии ядра. Одной из причин этому является постоянное изменение внутренних струк-&lt;br /&gt;тур данных ядра и заголовков функций даже при смене номера минорной версий ядра. В&lt;br /&gt;силу этого исходный код, работоспособный в версии 2.6.9, в версии 2.6.25 обычно не про-&lt;br /&gt;ходит даже этап компиляции. Данная проблема значительно усложняет разработку сто-&lt;br /&gt;ронних драйверов. С другой стороны, она же приводит к определенным сложностям&lt;br /&gt;при сдаче прошлогодних курсовых проектов, что выглядит скорее как достоинство&lt;br /&gt;при использовании ядра Linux в учебных целях (замечание Крищенко В. А.).&lt;br /&gt;.....</description>
  <comments>http://los-t.livejournal.com/21031.html</comments>
  <category>linux</category>
  <lj:security>public</lj:security>
  <lj:reply-count>5</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/20921.html</guid>
  <pubDate>Fri, 12 Sep 2008 06:33:18 GMT</pubDate>
  <title>День программиста</title>
  <link>http://los-t.livejournal.com/20921.html</link>
  <description>Поздравляю всех программистов с нашим профессиональным праздником! Ура! Ура! Ура!</description>
  <comments>http://los-t.livejournal.com/20921.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>9</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/20687.html</guid>
  <pubDate>Thu, 21 Aug 2008 12:43:13 GMT</pubDate>
  <title>Выдержка из лога</title>
  <link>http://los-t.livejournal.com/20687.html</link>
  <description>Выдержка из лога&lt;br /&gt;&lt;br /&gt;xxx: Коли то, о чем ты просишь, не трудно, я готов.&lt;br /&gt;yyy: Что же, тебе кажется трудным отвечать на вопросы?&lt;br /&gt;xxx: Нет, не кажется.&lt;br /&gt;yyy: Так отвечай же.&lt;br /&gt;xxx: А ты спрашивай.&lt;br /&gt;yyy: Значит, я буду задавать тебе вопросы так, как если бы ты в самом деле замышлял то, о чем я сейчас говорил?&lt;br /&gt;xxx: Да, если тебе так угодно; хотел бы я знать, каковы будут твои вопросы.&lt;br /&gt;&lt;br /&gt;Кажется разговором двух интеллектуалов в аське, не так ли?&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Однако этому логу 2300 лет. Платон, Диалоги, Алкивиад I.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Контраст с башоргом налицо :)</description>
  <comments>http://los-t.livejournal.com/20687.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/20380.html</guid>
  <pubDate>Fri, 01 Aug 2008 16:53:25 GMT</pubDate>
  <title>Eclipse, Moscow</title>
  <link>http://los-t.livejournal.com/20380.html</link>
  <description>&lt;a href=&quot;http://s315.photobucket.com/albums/ll445/lost404/Solar%20Eclipse/?action=view&amp;amp;current=IMGA0016.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://i315.photobucket.com/albums/ll445/lost404/Solar%20Eclipse/IMGA0016.jpg&quot; border=&quot;0&quot; alt=&quot;Eclipse&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://s315.photobucket.com/albums/ll445/lost404/Solar%20Eclipse/?action=view&amp;amp;current=IMGA0010.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://i315.photobucket.com/albums/ll445/lost404/Solar%20Eclipse/IMGA0010.jpg&quot; border=&quot;0&quot; alt=&quot;Eclipse&quot;&gt;&lt;/a&gt;</description>
  <comments>http://los-t.livejournal.com/20380.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/20211.html</guid>
  <pubDate>Mon, 30 Jun 2008 11:59:20 GMT</pubDate>
  <link>http://los-t.livejournal.com/20211.html</link>
  <description>26 :)&lt;br /&gt;&lt;br /&gt;Edit: &lt;br /&gt;Большое спасибо всем поздравляющим - я очень ценю вашу поддержку!&lt;br /&gt;&lt;br /&gt;Edit2:&lt;br /&gt;Ну чтож, пожалуй это был лучший мой день рождения за последние 10 лет :) Столько неожиданных сюрпризов :) Праздник действительно получился :)</description>
  <comments>http://los-t.livejournal.com/20211.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>13</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/19945.html</guid>
  <pubDate>Thu, 12 Jun 2008 12:55:57 GMT</pubDate>
  <title>Тесты, которые проходят нас :)</title>
  <link>http://los-t.livejournal.com/19945.html</link>
  <description>&lt;table style=&quot;text-align: justify; width: 510px; background:#FFE493 none repeat scroll 0%; font-size: 11pt;&quot;&gt;&lt;tr&gt;&lt;td&gt;Я проверил свои знания русского языка и получил пятерку.&lt;br&gt;&lt;br&gt;&lt;img align=&quot;center&quot; width=&quot;500&quot; height=&quot;164&quot; src=&quot;http://www.rb.ru/poll/7/img/5.gif&quot;&gt; &lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;a href=&quot;http://www.rb.ru/poll/7/&quot;&gt;Сходи, проверься?&lt;/a&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description>
  <comments>http://los-t.livejournal.com/19945.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/19574.html</guid>
  <pubDate>Sun, 06 Apr 2008 15:43:21 GMT</pubDate>
  <title>Git Guts (part 7)</title>
  <link>http://los-t.livejournal.com/19574.html</link>
  <description>Ветки в git - как ветки деревьев, постоянно обновляются и растут. Одно и то же символьное имя ветки (refs/heads/foo) может указывать на разные коммиты в разные моменты времени. В отличие от веток, теги (tags) - специально созданы для неизменяющихся по времени ссылок.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Символьные имена для тегов лежат в .git/refs/tags. Каждому имени тега может соответствовать один объект в базе git. Это может быть любой из ранее перечисленных типов объектов - блобы, деревья, коммиты.&lt;br /&gt;Символьное имя, указывающее на блоб, дерево или коммит, в терминологии git называется легковесным (lightweight) тегом. Легковесный он потому что кроме SHA1-имени, никакой другой информации не записывается.&lt;br /&gt;&lt;br /&gt;Такие легковесные теги можно создавать путем записи SHA1-имени объекта в файл в директории .git/refs/tags/&amp;lt;имя тега&amp;gt;.&lt;br /&gt;&lt;br /&gt;Настоящие теги - тяжеловесные или аннотированные (annotated), состоят из двух частей. Первая часть - это объект базы git специального типа (tag). В этот объект записываются следующие данные:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;SHA1 объекта, на который указывает аннотированный тег.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Тип этого объекта (blob, tree, commit или tag) (да, бывают теги указывающие на теги!)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Символьное имя тега&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Дата и время создания тега&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Имя и e-mail создателя тега (в таком же формате как имя автора коммита)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Кусок произвольных данных на усмотрение создателя тега&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;После чего объект-тег записывается в базу git, и в .git/refs/tags/&amp;lt;имя тега&amp;gt; пишется SHA1 объекта-тега.&lt;br /&gt;&lt;br /&gt;В тот самый кусок произвольных данных могут быть записано сообщение тега (по смыслу аналогичное сообщению коммита), а также в него можно внедрить GPG-подпись объекта. Такой тег будет называться подписанным (tag).&lt;br /&gt;&lt;br /&gt;Вот тут и проявляется магия git - создавая подписанный тег на определенный коммит, на самом деле  подписывается и сам коммит, и вся его история, и все деревья, составляющие историю, и все блобы, &quot;висящие на ветках этих деревьев&quot;. То есть все, на что можно &quot;дотянуться&quot; по ссылкам от коммита.&lt;br /&gt;&lt;br /&gt;Ладно, хватит теории, давайте перейдем к практике.&lt;br /&gt;&lt;br /&gt;Обычные, легковесные теги, как я уже говорил раньше, можно создавать просто записывая SHA1-имя объекта в файл в директории refs/tags/.&lt;br /&gt;&lt;br /&gt;Однако правильней создавать их через утилиту git-tag &amp;lt;имя тега&amp;gt; [&amp;lt;имя объекта&amp;gt;]&lt;br /&gt;&lt;br /&gt;Если имя объекта не указывать, то по умолчанию тег будет указывать на тот же коммит, на который указывает ссылка HEAD.&lt;br /&gt;&lt;br /&gt;Сначала создадим объект на который будет указывать тег. Для иллюстрации я создаю простейший blob, хотя обычно теги указывают на объекты-коммиты.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitguts7
$ cd ~/tmp/gitguts7
$ git-init
$ export GIT_AUTHOR_NAME=&quot;Git Guts&quot;
$ export GIT_AUTHOR_EMAIL=&quot;gitguts@localhost&quot;
$ export GIT_COMMITTER_NAME=&quot;$GIT_AUTHOR_NAME&quot;
$ export GIT_COMMITTER_EMAIL=&quot;$GIT_AUTHOR_EMAIL&quot;
$ echo &quot;Testing blobs&quot; &amp;gt; blobtest
$ git-hash-object -w blobtest
717c935c292fee3dca4c2e5f335f27b657895368
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Теперь создаем легковесный тег&lt;br /&gt;&lt;pre&gt;
$ git-tag lighttag 717c935c292fee3dca4c2e5f335f27b657895368
$ cat .git/refs/tags/lighttag
717c935c292fee3dca4c2e5f335f27b657895368
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно, по содержанию легковесные теги ничем не отличаются от бранчей - это обычные файлы с SHA1 объекта внутри.&lt;br /&gt;Кстати, команда git-tag без параметров (или git-tag -l) выведет список тегов.&lt;br /&gt;&lt;br /&gt;Теперь создадим аннотированный тег (с помощью git-tag -a). Для создания аннотированного тега необходимо указывать практически то же, что и для создания коммита - то есть имя автора тега, дату создания и сообщение. Ну и чтобы получилось одно и то же время, я опять воспользуюсь программой faketime. В отличие от git-commit-tree, команда git-tag более высокоуровневая, и сообщение для тега можно задавать прямо в командной строке, используя параметр -m.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ faketime -t 200001010000 git-tag -m &apos;Test annotated tag&apos; -a annotated_tag lighttag
&lt;/pre&gt;&lt;br /&gt;Заметьте, вместо использования SHA1 blob-а, я использовал ранее заданное имя lighttag, которое указывало на этот blob. В этом и весь смысл тегов - давать символьные имена объектам из базы.&lt;br /&gt;&lt;br /&gt;Теперь давайте посмотрим, что же получилось в итоге&lt;br /&gt;&lt;pre&gt;
$ git-rev-parse annotated_tag
40f93cdf3db19ab20109c81f113a7ccb8b921827
$ git-cat-file tag annotated_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag annotated_tag
tagger Git Guts &amp;lt;gitguts@localhost&amp;gt; 946674000 +0300

Test annotated tag
&lt;/pre&gt;&lt;br /&gt;Первая команда (git-rev-parse), позволяет посмотреть, каков SHA1 самого объекта-тега. Вторая команда распечатывает содержимое объекта-тега. В нем можно увидеть SHA1 блоба (первая строчка), тип объекта (вторая строчка), символьное имя (третья строчка), информация об авторе и времени создания тега (четвертая строчка), а ниже - сообщение тега.&lt;br /&gt;&lt;br /&gt;Команда создания подписанного тега очень похожа на команду создания обычного тега, просто вместо параметра -a надо передать параметр -s. К сожалению именно эта часть не будет воспроизводиться у читателей, так как у каждого должен быть свой собственный GPG-ключ для подписи. Приведу лишь результаты выполнения команды:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ faketime -t 200001010000 git-tag -m &apos;Test annotated tag&apos; -s signed_tag lighttag
$ git-cat-file tag signed_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag signed_tag
tagger Git Guts &amp;lt;gitguts@localhost&amp;gt; 946674000 +0300

Test annotated tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEABECAAYFAkf47VMACgkQ8SRmhxtswwQ53wCdHIGaU1ulxud4cUxWVp2pjU1d
358AnAu0Xlti6ZhCSfp9/YToFd//ipcS
=BQ9s
-----END PGP SIGNATURE-----
&lt;/pre&gt;&lt;br /&gt;Как видно, тут к сообщению добавилась подпись, созданная при помощи моего ключа.&lt;br /&gt;&lt;br /&gt;Проверить, каким ключом был подписан коммит, можно с помощью git-tag -v&lt;br /&gt;&lt;pre&gt;
$ git-tag -v signed_tag
object 717c935c292fee3dca4c2e5f335f27b657895368
type blob
tag signed_tag
tagger Git Guts &amp;lt;gitguts@localhost&amp;gt; 946674000 +0300

Test annotated tag
gpg: Подпись создана Вск 06 Апр 2008 19:33:39 MSD ключом DSA с ID 1B6CC304
gpg: Действительная подпись от &quot;Damir Shayhutdinov &amp;lt;damir@altlinux.ru&amp;gt;&quot;
&lt;/pre&gt;&lt;br /&gt;Вот так!&lt;br /&gt;&lt;br /&gt;Удалять теги можно с помощью git-tag -d, это я оставляю на самостоятельную работу.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Что-то я сам не ожидал что получится так много, поэтому описание синтаксиса ссылок git-rev-parse оставлю на потом.</description>
  <comments>http://los-t.livejournal.com/19574.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>16</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/19421.html</guid>
  <pubDate>Fri, 04 Apr 2008 07:39:30 GMT</pubDate>
  <title>Мысли вслух</title>
  <link>http://los-t.livejournal.com/19421.html</link>
  <description>Основная проблема проприетарного софта - что там к партнерам по бизнесу относятся как к покупателям. &quot;Все что угодно за ваши деньги&quot;.&lt;br /&gt;&lt;br /&gt;Основная проблема открытого софта - что там к покупателям относятся как к партнерам по бизнесу. &quot;Тебе надо - ты и делай&quot;.</description>
  <comments>http://los-t.livejournal.com/19421.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/19106.html</guid>
  <pubDate>Wed, 19 Mar 2008 20:08:48 GMT</pubDate>
  <title>Git Guts (part 6)</title>
  <link>http://los-t.livejournal.com/19106.html</link>
  <description>SHA1-имена объектов как уникальные идентификаторы - это конечно удобно. Для роботов. Люди как-то привыкли называть друг друга по коротким именам, а не по кодам ДНК.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Символьные имена объектов в git называются ссылка (references), и хранятся в каталоге .git/refs.&lt;br /&gt;&lt;br /&gt;Делятся они на три типа:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Теги (tags)  - символьные имена любых объектов из базы, которые не меняются со временем. Расположены в .git/refs/tags/&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ветки (heads, branches) - символьные имена объектов-коммитов, которые меняются при добавлении нового коммита в цепочку. Расположены в .git/refs/heads/&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Удаленные ветки (remotes) - ветки специального вида, которые предназначены для слежения за ветками (heads) в других репозитариях. Лежат в .git/refs/remotes/&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Кроме этого, есть несколько специальных ссылок, которые по историческим соображениям лежат вне каталога .git/refs и их названия пишутся В РЕГИСТРЕ БЛОНДИНОК. Из всех БЛОНДИНОЧНЫХ ссылок для пользователей наиболее важными являются HEAD, ORIG_HEAD и MERGE_HEAD.&lt;br /&gt;&lt;br /&gt;HEAD - это особая ссылка, она показывает на коммит, который соответствует рабочей копии. Если быть точным, это не просто ссылка на коммит, это ссылка на &quot;текущую ветку&quot;.&lt;br /&gt;&lt;br /&gt;Хватит теории, пора иллюстрировать. Создаем простой репозитарий и попробуем те самые высокоуровневые инструменты, которыми раньше не пользовались.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitguts6
$ cd ~/tmp/gitguts6
$ git-init
Initialized empty Git repository in .git/
$ git-mktree &amp;lt;/dev/null
4b825dc642cb6eb9a060e54bf8d69288fbee4904
$ TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
$ export GIT_AUTHOR_NAME=&quot;Git Guts&quot;
$ export GIT_AUTHOR_EMAIL=&quot;gitguts@localhost&quot;
$ export GIT_COMMITTER_NAME=&quot;$GIT_AUTHOR_NAME&quot;
$ export GIT_COMMITTER_EMAIL=&quot;$GIT_AUTHOR_EMAIL&quot;
$ echo &quot;Первый коммит&quot; | iconv -t utf-8 | faketime -t 200001010000 git-commit-tree $TREE
e678a27ffe7b84211f09b0e397b1c6e287aee392
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Итак, был создан новый коммит с пустым деревом. Теперь создадим символьное имя для этого коммита  - пусть это будет имя &quot;refs/heads/master&quot;. Для этого надо лишь создать обычный файл .git/refs/heads/master и записать в него SHA1-имя коммита. Примерно так:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo e678a27ffe7b84211f09b0e397b1c6e287aee392 &amp;gt; .git/refs/heads/master
$ ln -sf refs/heads/master .git/HEAD
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно из примера, я создал ссылку-ветку refs/heads/master, после чего сделал интересную операцию - символическую ссылку .git/HEAD на эту ветку.&lt;br /&gt;&lt;br /&gt;Новую созданную ветку может показать команда git-branch:&lt;br /&gt;&lt;pre&gt;
$ git-branch
* master
&lt;/pre&gt;&lt;br /&gt;Звездочка около master означает что сейчас ссылка HEAD указывает именно на эту ветку.&lt;br /&gt;&lt;br /&gt;Чтобы увидеть, как сменой ссылки HEAD git может &quot;переключаться&quot; между ветками, создадим вторую ветку, указывающую на тот же коммит:&lt;br /&gt;&lt;pre&gt;
$ echo e678a27ffe7b84211f09b0e397b1c6e287aee392 &amp;gt; .git/refs/heads/other
$ git-branch
* master
  other
$ ln -sf refs/heads/other .git/HEAD
$ git-branch
  master
* other
&lt;/pre&gt;&lt;br /&gt;Мы видим как простым переставлением символьной ссылки .git/HEAD выбирается &quot;текущая&quot; ветка.&lt;br /&gt;&lt;br /&gt;После того, как было создано символьное имя объекта, можно получить по нему SHA1-имя с помощью команды git-rev-parse:&lt;br /&gt;&lt;pre&gt;
$ git-rev-parse refs/heads/master
e678a27ffe7b84211f09b0e397b1c6e287aee392
$ git-rev-parse refs/heads/other
e678a27ffe7b84211f09b0e397b1c6e287aee392
&lt;/pre&gt;&lt;br /&gt;Вместо refs/heads/master можно использовать heads/master или master. Также работают БЛОНДИНИСТЫЕ ссылки типа HEAD:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-rev-parse HEAD
e678a27ffe7b84211f09b0e397b1c6e287aee392
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Используя git-rev-parse и задание ссылок, можно произвести и простую операцию &quot;коммит в ветку&quot;, с которой обычно начинается знакомство с git. Вот эта операция, пошагово:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ PARENT=`git-rev-parse HEAD` # SHA1 текущего коммита
$ echo &quot;Коммит в ветку other&quot; | iconv -t utf-8 | faketime -t 200001010100 git-commit-tree $TREE -p $PARENT # создаем новый коммит, используя в качестве родителя коммит HEAD
283f22289f768361b854a78f1764dc7f1bd9b822
$ echo 283f22289f768361b854a78f1764dc7f1bd9b822 &amp;gt; .git/HEAD # переставляем ссылку HEAD на новый коммит
$ git-branch # смотрим, по прежнему ли мы на ветке other?
  master
* other
&lt;/pre&gt;&lt;br /&gt;Заметили магию? Из-за того, что .git/HEAD - символическая ссылка на .git/refs/heads/other, запись SHA1 нового коммита в .git/HEAD на самом деле записывает новый коммит в refs/heads/other, затирая предыдущее значение. Теперь ссылка refs/heads/other указывает на новый коммит.&lt;br /&gt;&lt;br /&gt;Вот схема:&lt;br /&gt;&lt;pre&gt;
Было:
HEAD -&amp;gt; refs/heads/other -&amp;gt; старый коммит
Стало:
HEAD -&amp;gt; refs/heads/other -&amp;gt; новый коммит -&amp;gt; старый коммит
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;То, что раньше пришлось делать вручную - теперь делается через механизм веток и HEAD! Для того, чтобы добавить новый коммит в ветку - надо просто повторить вышеуказанную процедуру. Можно даже сделать это в одну строчку, и при этом совсем избежать указаний SHA1. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo &quot;Еще один коммит в ветку other&quot; | iconv -t utf-8 | faketime -t 200001010200 git-commit-tree $TREE -p `git-rev-parse HEAD` &amp;gt; .git/HEAD # магическая строчка, коммитящая в ветку
$ PAGER=cat git-log --pretty=oneline # git-log без указания коммита показывает историю HEAD
afd309cb9fe66dc314ed54c272a2d26a1b7a01be Еще один коммит в ветку other
283f22289f768361b854a78f1764dc7f1bd9b822 Коммит в ветку other
e678a27ffe7b84211f09b0e397b1c6e287aee392 Первый коммит
&lt;/pre&gt;&lt;br /&gt;Вот так - в ветке other теперь было создано уже три коммита.&lt;br /&gt;&lt;br /&gt;Если же теперь переставить ссылку HEAD на refs/heads/master, точно такой же процедурой можно добавлять коммиты в ветку master:&lt;br /&gt;&lt;pre&gt;
$ ln -sf refs/heads/master .git/HEAD
$ git-branch
* master
  other
$ echo &quot;Теперь коммит в ветку master&quot; | iconv -t utf-8 | faketime -t 200001010300 git-commit-tree $TREE -p `git-rev-parse HEAD` &amp;gt; .git/HEAD
$ PAGER=cat git-log --pretty=oneline
22339820c0dd6758be9cd940db0306d4020f7c9f Теперь коммит в ветку master
e678a27ffe7b84211f09b0e397b1c6e287aee392 Первый коммит
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ну и под занавес - посмотрите как эти ветки выглядят в gitk.&lt;br /&gt;&lt;pre&gt;
$ gitk --all
&lt;/pre&gt;&lt;br /&gt;Параметр --all говорит gitk показывать все символьные ссылки, а не только те, которые доступны из HEAD. Поэтому мы увидим все две ветки, которые были созданы:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://www.ljplus.ru/img4/l/o/los_t/gitguts6_1_web.png&quot; width=&quot;791&quot; height=&quot;215&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;В следующем выпуске я расскажу про тэги, а также про продвинутые возможности программы git-rev-parse, которые позволяют &quot;ходить по ссылкам&quot;.</description>
  <comments>http://los-t.livejournal.com/19106.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>11</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/18880.html</guid>
  <pubDate>Tue, 18 Mar 2008 13:05:02 GMT</pubDate>
  <link>http://los-t.livejournal.com/18880.html</link>
  <description>Очередной дятел убил сибя апстену (чувствительным людям не смотреть)&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://icanhascheezburger.com/2008/03/17/funny-pictures-fail/&quot;&gt;&lt;img src=&quot;http://icanhascheezburger.wordpress.com/files/2008/03/funny-pictures-bird-window-fail.jpg&quot; width=&quot;480&quot; height=&quot;640&quot; alt=&quot;Humorous Pictures&quot; border=&quot;1&quot; /&gt;&lt;/a&gt;&lt;br /&gt;see more &lt;a href=&quot;http://icanhascheezburger.com&quot;&gt;crazy cat pics&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;via &lt;a href=&quot;http://icanhascheezburger.com/&quot;&gt;http://icanhascheezburger.com/&lt;/a&gt;</description>
  <comments>http://los-t.livejournal.com/18880.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/18395.html</guid>
  <pubDate>Tue, 04 Mar 2008 20:54:11 GMT</pubDate>
  <title>distrsync</title>
  <link>http://los-t.livejournal.com/18395.html</link>
  <description>Сегодня в разговоре на канале #altlinux в голове наконец-то оформилась идея, как можно организовать пиринговое (p2p) распространение репозитариев Linux вообще, и репозитариев ALT Linux в частности. Пока рабочее название для этого протокола взаимодействия - distrsync.&lt;br /&gt;&lt;br /&gt;Я буду потихоньку выкладывать, как будет время, свои мысли по поводу этого протокола.&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Условия и цель разработки протокола&lt;/h2&gt;&lt;br /&gt;Ни для кого не секрет, что обилие достаточно дешевых и высокоскоростных каналов связи сделало пиринговые сети чрезвычайно популярными в мире. Если обычная архитектура централизованных сетей при повышении количества клиентов начинает испытывать затруднения, то распределенная структура пиринга позволяет сети масштабироваться в чрезвычайно больших пределах. В связи с этим любые централизованные каналы распространения популярной информации целесообразно дополнять или заменять децентрализованными.&lt;br /&gt;&lt;br /&gt;Протокол distrsync предполагается для дополнения/замены протокола rsync, который прекрасно зарекомендовал себя в качестве средства синхронизации больших объемов изменяющихся данных по сети. К сожалению, протокол rsync является централизованным, и обладает всеми недостатками централизованных систем:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Скорость синхронизации зависит от пропускной способности канала сервера, и делится между всеми клиентами протокола.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Протокол rsync также создает сильную загрузку подсистемы ввода-вывода как клиента, так и сервера (активная работа требуется для определения, что именно надо передавать). Эта скорость  ввода-вывода также делится между всеми клиентами протокола.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Создание системы периодически синхронизируемых зеркал помогает частично бороться с этими недостатками, путем искусственного балансирования нагрузки по нескольким серверам. В такой системе задача балансировки решается на стороне клиента (как правило, выбирается ближайшее географически зеркало с неизвестным режимом синхронизации с основным). Поэтому часть зеркал остаются недогруженными, а часть - перегруженными.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Система зеркал может быть несинхронизованной, на каких-то зеркалах может быть устаревшая информация. Для проверки устаревания информации используют либо полное сканирование синхронизируемой области, либо какие-то внепротокольные решения, например файлы с  датой последнего обновления зеркала. Задача поддержки этого файла в актуальном состоянии ложится на администратора зеркала.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Надежность централизованной системы зависит от надежности зеркал. Перегруженные зеркала обладают пониженной надежностью, а так как обычно на этих зеркалах лежит самая свежая информация, отказ зеркала приводит к невозможности клиентов получить свежие данные.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Протокол distrsync задумывается для следующих масштабов задач синхронизации:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; Общий объем синхронизируемых данных - порядка десятков гигабайт.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Количество синхронизируемых файлов - порядка нескольких тысяч.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Количество одновременно синхронизирующих клиентов - порядка десятков тысяч.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Скорость устаревания информации - порядка 5-10% в день.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Отказоустойчивость системы - система должна функционировать при отказе 50% центральных узлов, координирующих обмен данными &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Также протокол может должен поддерживать следующие возможности:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;контроль целостности синхронизируемых данных и невозможность фальсификации данных со стороны клиентов или центральных узлов&lt;/li&gt;&lt;br /&gt;&lt;li&gt;возможность выборочных синхронизации данных по заданным клиентом критериям&lt;/li&gt;&lt;br /&gt;&lt;li&gt;обмен данными между несинхронизованными клиентами (или частично синхронизованными, aka &quot;докачка&quot;)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;возобновление синхронизации при временном отказе сети без потери уже принятой информации&lt;/li&gt;&lt;br /&gt;&lt;li&gt;поддержка IPv6&lt;/li&gt;&lt;br /&gt;&lt;li&gt;принципиальная кроссплатформенность (по крайней мере POSIX-системы и Windows) &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;В целях удобства использования протокол также может поддерживать:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;возможность предпочтения источников данных (клиентов и центральных узлов) по географическим, сетевым или другим признакам&lt;/li&gt;&lt;br /&gt;&lt;li&gt;стимулирование обмена данных между клиентами после завершения синхронизации (например, используя систему распределенных рейтингов)&lt;/li&gt;&lt;br /&gt;&lt;li&gt; противодействие попыткам намеренной фальсификации передаваемых данных&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;При проектировании не делалось никаких попыток гарантировать:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; анонимность при передаче данных &lt;/li&gt;&lt;br /&gt;&lt;li&gt; совместимость с существующими технологиями децентрализованного обмена данными &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Обзор существующих решений&lt;/h2&gt;&lt;br /&gt;Узкое место существующих централизованных решений - количество одновременно синхронизирующих клиентов. Я не знаю протоколов, которые бы могли масштабироваться в  указанных пределах (кроме разве что кластерной Samba).&lt;br /&gt;&lt;br /&gt;Рассмотрим теперь существующие и активно применяемые пиринговые решения:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; BitTorrent&lt;br /&gt;Протокол BitTorrent хорошо масштабируется по общему объему передаваемых (зеркалируемых) данных (возможны раздачи размером в десятки гигабайт), и поддерживает десятки тысяч одновременно синхронизирующих клиентов. Также BitTorrent за счет &quot;склеивания&quot; всех передаваемых файлов в один общий массив информации обеспечивает равномерность закачивания и поддержку большого количества зеркалируемых файлов. Размер метафайла, содержащего информацию для скачивания, растет пропорционально количеству файлов, но не очень сильно, позволяя держать размер всего метафайла в пределах 1Mb.&lt;br /&gt;&lt;br /&gt;К сожалению, протокол не поддерживает обновление синхронизирующейся информации. Изменение даже одного байта информации ведет к несовпадению контрольной суммы одного блока информации, и как следствие, к несовпадению контрольной  суммы всего метафайла. Именно по этой  контрольной сумме производится поиск клиентов для координации обмена между ними. Следовательно, клиенты, синхронизирующие обновленные данные, не смогут использовать информацию от клиентов, синхронизирующих старые данные.&lt;br /&gt;&lt;br /&gt;Таким образом, в задачах распространения изменяемых данных (например, обновляемых репозитариев Linux), протокол BitTorrent эффективно использоваться не может. Для неизменяемых данных (образов дисков, необновляемых репозитариев), использование BitTorrent может быть предпочтительнее других каналов распространения из-за популярности и развитости технологии.&lt;br /&gt;&lt;br /&gt;Система BitTorrent также страдает от централизованности компонента, координирующего обмен (трекера, tracker). При отказе трекера эффективный обмен данными невозможен. Частично эту проблему решает поддержка DHT (Distributed Hash Table), а также добавление нескольких трекеров (поиск трекеров остается задачей клиентов).&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Direct Connect (DC++)&lt;br /&gt;Если верить википедии, этот протокол испытывает трудности при масштабировании по количеству клиентов, за счет включения широковещательных функций (например, чат). Поэтому хабы сети (hubs) могут быть перегруженными и отказывать, оставляя клиентов без возможности координирования.&lt;br /&gt;&lt;br /&gt;Для задач синхронизации функции чата не нужны, так что требуется более пристальное изучение возможностей масштабирования. Закрытость оригинального протокола DC уменьшает привлекательность протокола.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Другие сети пока не рассматривал, подскажите куда стоит посмотреть&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;</description>
  <comments>http://los-t.livejournal.com/18395.html</comments>
  <category>distrsync</category>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/18097.html</guid>
  <pubDate>Tue, 22 Jan 2008 14:29:09 GMT</pubDate>
  <title>Сизиф и море^Wкошки</title>
  <link>http://los-t.livejournal.com/18097.html</link>
  <description>&lt;a href=&quot;http://icanhascheezburger.com/2008/01/22/funny-pictures-sisyphus-cat-tries-again/&quot;&gt;&lt;img src=&quot;http://icanhascheezburger.wordpress.com/files/2008/01/funny-pictures-sisyphus-cat-watermelon-water.jpg&quot; alt=&quot;funny pictures&quot; /&gt;&lt;/a&gt;&lt;br /&gt;moar &lt;a href=&quot;http://icanhascheezburger.com&quot;&gt;funny pictures&lt;/a&gt;</description>
  <comments>http://los-t.livejournal.com/18097.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/17872.html</guid>
  <pubDate>Sun, 20 Jan 2008 18:41:39 GMT</pubDate>
  <title>Git Guts (Part 5)</title>
  <link>http://los-t.livejournal.com/17872.html</link>
  <description>Для тех, кто раньше работал только с CVS или CVS++ (ну то есть Subversion), концепция коммитов-слияний (merge) может оказаться не очень понятной. Так что я решил обратиться к классике для иллюстрации слияний.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Помните, Николай Васильевич Гоголь, &quot;Женитьба&quot;... Если кто позабыл, я напомню монолог Агафьи Тихоновны (полный текст см. тут: &lt;a href=&quot;http://az.lib.ru/g/gogolx_n_w/text_0080.shtml&quot;&gt;http://az.lib.ru/g/gogolx_n_w/text_0080.shtml&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Право,  такое затруднение -- выбор! Если  бы еще один,&lt;br /&gt;два человека, а  то  четыре.  Как  хочешь, так и выбирай.  Никанор  Иванович&lt;br /&gt;недурен, хотя, конечно, худощав; Иван Кузьмич тоже недурен. Да если  сказать&lt;br /&gt;правду. Иван Павлович тоже хоть и толст, а  ведь очень видный мужчина. Прошу&lt;br /&gt;покорно, как тут быть? Балтазар Балтазарыч опять мужчина с достоинствами. Уж&lt;br /&gt;как трудно решиться, так просто рассказать нельзя, как  трудно! &lt;b&gt;Если бы губы&lt;br /&gt;Никанора   Ивановича  да  приставить  к  носу  Ивана  Кузьмича,   да   взять&lt;br /&gt;сколько-нибудь  развязности,  какая  у  Балтазара Балтазарыча,  да, пожалуй,&lt;br /&gt;прибавить к  этому  еще дородности Ивана Павловича  -- я бы тогда  тотчас  же&lt;br /&gt;решилась.&lt;/b&gt; А теперь  поди подумай! просто голова даже стала  болеть.&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;Бедная Агафья Тихоновна. Ведь в то доисторическое время еще не было современных систем контроля версий, разве что CVS, который был придуман еще во времена динозавров. А ведь задача создания идеального жениха из лучших качеств четырех претендентов - типичная задача слияния!&lt;br /&gt;&lt;br /&gt;В нижеприведенном примере я намеренно не буду использовать встроенные в git автоматические системы слияния, чтобы показать внутреннюю кухню. В жизни все будет гораздо проще.&lt;br /&gt;&lt;br /&gt;Итак, начнем с создания репозитория и инициализации переменных окружения:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitguts5
$ cd ~/tmp/gitguts5
$ git init-init
Initialized empty Git repository in .git/

$ export GIT_AUTHOR_NAME=&quot;Git Guts&quot;
$ export GIT_AUTHOR_EMAIL=&quot;gitguts@localhost&quot;
$ export GIT_COMMITTER_NAME=&quot;$GIT_AUTHOR_NAME&quot;
$ export GIT_COMMITTER_EMAIL=&quot;$GIT_AUTHOR_EMAIL&quot;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Теперь создадим файл-заготовку, который мы будем использовать для заполнения наших деревьев - перечень человеческих достоинств, которые ценит Агафья Тихоновна:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo -e &quot;Губы\nНос\nРазвязность\nДородность&quot; &amp;gt; virtues-template
$ cat virtues-template
Губы
Нос
Развязность
Дородность
&lt;/pre&gt;&lt;br /&gt;Обращаю внимание что текст в файле virtues-template записан в системной кодировке. Для того, чтобы была воспроизводимость всех проделанных действий, перед занесением в git я буду переводить текст из системной кодировки в utf-8. На самом деле git не предъявляет никаких требований к кодировке, но тем не менее я бы рекомендовал держать коммиты либо в ASCII (то есть писать их по английски), либо в utf-8, если вы хотите чтобы ваши коммиты читал кто-нибудь вне России.&lt;br /&gt;&lt;br /&gt;Итак, следующим этапом будет создание начального коммита. Его дерево будет состоять из одного файла - virtues, который будет аналогичен файлу virtues-template, только переведен в utf-8 для воспроизводимости. Почему начальный коммит должен быть именно таким - я объясню позже.&lt;br /&gt;&lt;br /&gt;Итак, создание начального коммита (ничего нового для тех, кто внимательно читал предыдущие выпуски):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ iconv -t utf-8 &amp;lt; virtues-template &amp;gt; virtues
$ git-hash-object -w virtues
&lt;font color=&quot;blue&quot;&gt;111f008f40b32148b325098b0b3ad1fe46df0aef&lt;/font&gt;

$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;111f008f40b32148b325098b0b3ad1fe46df0aef&lt;/font&gt;\tvirtues&quot; | git-mktree
&lt;font color=&quot;green&quot;&gt;f387e3ef43d001f614ef1a5a8c6ac4a0996c7c3c&lt;/font&gt;

$ echo &quot;Обычный человек&quot; | iconv -t utf-8 | faketime -t 200001010000 git-commit-tree &lt;font color=&quot;green&quot;&gt;f387e3ef43d001f614ef1a5a8c6ac4a0996c7c3c&lt;/font&gt;
&lt;b&gt;&lt;font color=&quot;red&quot;&gt;6173ad1924d1221b82fe940e96eca4ec914b4b6c&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Итак, у нас есть начальный коммит (без предков), с сообщением &quot;Обычный человек&quot;. Зачем? Потому что именно так работает автоматическое слияние. Ему нужен &quot;общий предок&quot; всех сливаемых коммитов, чтобы понять, что у них общее, а что - различается.&lt;br /&gt;&lt;br /&gt;Теперь давайте создадим коммиты, соответствующие женихам Агафьи Тихоновны: Никанор Иваныч, Иван Кузьмич, Балтазар Балтазарыч и Иван Павлович. Отличаться эти коммиты будут тем, что вместо &lt;br /&gt;&lt;pre&gt;
Губы
Нос
Развязность
Дородность
&lt;/pre&gt;&lt;br /&gt;будет &lt;br /&gt;&lt;pre&gt;
Губы Никанора Иваныча
Нос Никанора Иваныча
Развязность Никанора Иваныча
Дородность Никанора Иваныча
&lt;/pre&gt;&lt;br /&gt;Ну, вы надеюсь поняли. Добавлять &quot;Никанора Иваныча&quot; в конце каждой строчки мы будем с помощью простейшего скрипта на sed, вот иллюстрация:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ sed &apos;s/$/ Никанора Иваныча/&apos; virtues-template
Губы Никанора Иваныча
Нос Никанора Иваныча
Развязность Никанора Иваныча
Дородность Никанора Иваныча
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Итак, создадим эти четыре коммита:&lt;br /&gt;&lt;br /&gt;Никанор Иваныч:&lt;br /&gt;&lt;pre&gt;
$ PARENT=&quot;6173ad1924d1221b82fe940e96eca4ec914b4b6c&quot;
$ sed &apos;s/$/ Никанора Иваныча/&apos; virtues-template | iconv -t utf-8 &amp;gt; virtues-NI
$ git-hash-object -w virtues-NI
&lt;font color=&quot;blue&quot;&gt;929db472b24b02eb991257c26376609e4da6966b&lt;/font&gt;

$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;929db472b24b02eb991257c26376609e4da6966b&lt;/font&gt;\tvirtues&quot; | git-mktree
&lt;font color=&quot;green&quot;&gt;0ade4416fb17c0eb8037265a2e0405db102164eb&lt;/font&gt;
$ echo &quot;Никанор Иваныч&quot; | iconv -t utf-8 | faketime -t 200001010100 git-commit-tree &lt;font color=&quot;green&quot;&gt;0ade4416fb17c0eb8037265a2e0405db102164eb&lt;/font&gt; -p $PARENT
&lt;b&gt;&lt;font color=&quot;red&quot;&gt;f683f1e38e0339885c5ff31ed3efa6f5060c57b3&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;Иван Кузьмич:&lt;br /&gt;&lt;pre&gt;
$ sed &apos;s/$/ Ивана Кузьмича/&apos; virtues-template | iconv -t utf-8 &amp;gt; virtues-IK
$ git-hash-object -w virtues-IK
&lt;font color=&quot;blue&quot;&gt;b4bd4d3eae566ac8d58a5a4dc8dccf06a8a8602c&lt;/font&gt;

$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;b4bd4d3eae566ac8d58a5a4dc8dccf06a8a8602c&lt;/font&gt;\tvirtues&quot; | git-mktree
&lt;font color=&quot;green&quot;&gt;f7509f166ee816355654e1fd8b21bfa616272d38&lt;/font&gt;

$ echo &quot;Иван Кузьмич&quot; | iconv -t utf-8 | faketime -t 200001010100 git-commit-tree &lt;font color=&quot;green&quot;&gt;f7509f166ee816355654e1fd8b21bfa616272d38&lt;/font&gt; -p $PARENT
&lt;b&gt;&lt;font color=&quot;red&quot;&gt;ff7a5afbdf16e8ade231e1adec6e9a44838c44d0&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;Балтазар Балтазарыч:&lt;br /&gt;&lt;pre&gt;
$ sed &apos;s/$/ Балтазар Балтазарыча/&apos; virtues-template | iconv -t utf-8 &amp;gt; virtues-BB
$ git-hash-object -w virtues-BB
&lt;font color=&quot;blue&quot;&gt;66d2a243ba12d21ba95ce44e757681a4d4e05428&lt;/font&gt;

$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;66d2a243ba12d21ba95ce44e757681a4d4e05428&lt;/font&gt;\tvirtues&quot; | git-mktree
&lt;font color=&quot;green&quot;&gt;f56b93f223725f10602f0c404114671ed04ad743&lt;/font&gt;

$ echo &quot;Балтазар Балтазарыч&quot; | iconv -t utf-8 | faketime -t 200001010100 git-commit-tree &lt;font color=&quot;green&quot;&gt;f56b93f223725f10602f0c404114671ed04ad743&lt;/font&gt; -p $PARENT
&lt;b&gt;&lt;font color=&quot;red&quot;&gt;c89d03e1e07c2a2fdb52bc85615bed628b4de202&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;Иван Павлович:&lt;br /&gt;&lt;pre&gt;
$ sed &apos;s/$/ Ивана Павловича/&apos; virtues-template | iconv -t utf-8 &amp;gt; virtues-IP
$ git-hash-object -w virtues-IP
&lt;font color=&quot;blue&quot;&gt;9c9c6c6f479e13ce061e82863c17e3bc03ce8960&lt;/font&gt;
$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;9c9c6c6f479e13ce061e82863c17e3bc03ce8960&lt;/font&gt;\tvirtues&quot; | git-mktree
&lt;font color=&quot;green&quot;&gt;3d2459538e8ff3809d557758649a5a9c9393c124&lt;/font&gt;
$ echo &quot;Иван Павлович&quot; | iconv -t utf-8 | faketime -t 200001010100 git-commit-tree &lt;font color=&quot;green&quot;&gt;3d2459538e8ff3809d557758649a5a9c9393c124&lt;/font&gt; -p $PARENT
&lt;b&gt;&lt;font color=&quot;red&quot;&gt;2762e87bf446e3f886996d8e984b69a6204b4305&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Дерево этих коммитов будет выглядеть в gitk примерно так:&lt;br /&gt;&lt;pre&gt;
gitk 2762e87bf446e3f886996d8e984b69a6204b4305\
    c89d03e1e07c2a2fdb52bc85615bed628b4de202\
    ff7a5afbdf16e8ade231e1adec6e9a44838c44d0\
    f683f1e38e0339885c5ff31ed3efa6f5060c57b3
&lt;/pre&gt;&lt;br /&gt;&lt;img src=&quot;http://www.ljplus.ru/img4/l/o/los_t/gitguts5_1_web.png&quot; width=&quot;493&quot; height=&quot;217&quot; alt=&quot;27,19 КБ&quot;&gt;&lt;br /&gt;&lt;br /&gt;Каждый из женихов отличается от общего предка - &quot;Обычного человека&quot; персонализированным набором качеств.&lt;br /&gt;&lt;br /&gt;Агафья Тихоновна хотела бы создать идеального жениха, скомбинировав эти персонализированные отличия. В этом нам поможет слияние. &lt;br /&gt;&lt;br /&gt;В классическом случае операция слияния - это&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Формирование нового дерева, которое каким-то образом включает в себя изменения, произошедшие в сливаемых ветках со времени их общего предка.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Формирование нового коммита с этим деревом, в качестве предков которого указаны все сливаемые коммиты&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Автоматическая система слияния git в многих случаях может сама &quot;слить&quot; ветки, без участия пользователя. Например, если изменения в сливаемых ветках затрагивают разные файлы, или один и тот же файл, но изменяемые строчки не пересекаются. Новое дерево в таком случае формируется автоматически.&lt;br /&gt;&lt;br /&gt;В нашем же запущенном случае в каждом коммите-женихе все строчки изначального &quot;Обычного человека&quot; заменены - поэтому при слиянии получается конфликт. Например, чьи губы должны быть у результата слияния - Никанора Иваныча или Балтазара Балтазарыча? Или может Ивана Павловича?&lt;br /&gt;&lt;br /&gt;В таких ситуациях единственное решение принять должен человек. В нашем случае - Агафья Тихоновна. Благодаря Гоголю Агафья уже разрешила все конфликты слияния, постановив, что у идеального жениха должно быть:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Губы Никанора Иваныча&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Нос Ивана Кузьмича&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Развязность Балтазара Балтазарыча&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Дородность Ивана Павловича&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Вот с таким вот идеальным деревом мы и создадим коммит-слияние:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo &quot;Губы Никанора Иваныча&quot; &amp;gt; ideal-template
$ echo &quot;Нос Ивана Кузьмича&quot; &amp;gt;&amp;gt; ideal-template
$ echo &quot;Развязность Балтазара Балтазарыча&quot; &amp;gt;&amp;gt; ideal-template
$ echo &quot;Дородность Ивана Павловича&quot; &amp;gt;&amp;gt; ideal-template
$ cat ideal-template
Губы Никанора Иваныча
Нос Ивана Кузьмича
Развязность Балтазара Балтазарыча
Дородность Ивана Павловича

$ iconv -t utf-8 &amp;lt;ideal-template &amp;gt;ideal
$ git-hash-object -w ideal
&lt;font color=&quot;blue&quot;&gt;aaad89b8229eab40cde73cd3afe05cfb689f8a85&lt;/font&gt;
$ echo -e &quot;100644 blob &lt;font color=&quot;blue&quot;&gt;aaad89b8229eab40cde73cd3afe05cfb689f8a85&lt;/font&gt;\tvirtues&quot; | git-mktree 
&lt;font color=&quot;green&quot;&gt;3bb4ea25e93d5962d6a568330aea334161d55009&lt;/font&gt;
$ echo &quot;Идеальный жених Агафьи Тихоновны&quot; | iconv -t utf-8 | faketime -t 200001010200 git-commit-tree &lt;font color=&quot;green&quot;&gt;3bb4ea25e93d5962d6a568330aea334161d55009&lt;/font&gt;\
    -p &lt;b&gt;&lt;font color=&quot;red&quot;&gt;2762e87bf446e3f886996d8e984b69a6204b4305&lt;/font&gt;&lt;/b&gt;\
    -p &lt;b&gt;&lt;font color=&quot;red&quot;&gt;c89d03e1e07c2a2fdb52bc85615bed628b4de202&lt;/font&gt;&lt;/b&gt;\
    -p &lt;b&gt;&lt;font color=&quot;red&quot;&gt;ff7a5afbdf16e8ade231e1adec6e9a44838c44d0&lt;/font&gt;&lt;/b&gt;\
    -p &lt;b&gt;&lt;font color=&quot;red&quot;&gt;f683f1e38e0339885c5ff31ed3efa6f5060c57b3&lt;/font&gt;&lt;/b&gt;
&lt;b&gt;&lt;font color=&quot;black&quot;&gt;31e839af8dbd1315ceaa9dbbcc2c2c71ff91d797&lt;/font&gt;&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;Как видно, от обычных коммитов с одним предком, коммит-слияние отличается лишь тем, что у него несколько предков, каждый указан как -p &amp;lt;SHA1&amp;gt;&lt;br /&gt;&lt;br /&gt;Посмотрим же на результат в gitk:&lt;br /&gt;&lt;pre&gt;
gitk &lt;b&gt;31e839af8dbd1315ceaa9dbbcc2c2c71ff91d797&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;&lt;img src=&quot;http://www.ljplus.ru/img4/l/o/los_t/gitguts5_2_web.png&quot; width=&quot;645&quot; height=&quot;226&quot; alt=&quot;34,36 КБ&quot;&gt;&lt;br /&gt;&lt;br /&gt;Как видно, коммит-слияние в gitk графически отображается как соединение всех веток в одну точку. В классическом случае (без использования всяческих хаков или низкоуровневых команд), когда git видит коммит-слияние, он считает что все изменения, которые были в сливаемых ветках, в точке слияния были согласованы, и все конфликты поправлены. &lt;br /&gt;&lt;br /&gt;Если в дальнейшем сливаемые ветки будут развиваться дальше по отдельности, то при очередном слиянии git будет считать коммит-слияние общим предком, и конфликтовать будут только изменения, произошедшие после коммита-слияния.&lt;br /&gt;&lt;br /&gt;Итак, подведем итоги:&lt;br /&gt;Коммит-слияние с технической точки зрения ненамного сложнее обычного коммита. Главной проблемой при слияниях является &quot;Право,  такое затруднение -- выбор!&quot;, говоря словами Агафьи Тихоновны. Во многих случаях этот выбор может сделать сам git, предоставляя несколько стратегий автоматического слияния. Но в сложных случаях без помощи человека в решении конфликтов не обойтись.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Обзор стратегий автоматического слияния я пожалуй оставлю на потом, а в следующем выпуске расскажу о текстовых ссылках (refs), которые значительно облегчают работу с git. Именно они, а не SHA1 имена объектов, используются для повседневной работы в git. Stay tuned!</description>
  <comments>http://los-t.livejournal.com/17872.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>27</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/17586.html</guid>
  <pubDate>Mon, 12 Nov 2007 19:12:24 GMT</pubDate>
  <title>Git Gems</title>
  <link>http://los-t.livejournal.com/17586.html</link>
  <description>Это ни в коем случае не заменитель очередного выпуска Git Guts, просто хочется поделиться одним на мой взгляд изящным применением git-remote.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Предположим, что вы работает в своем git-репозитории. Напатчили несколько веток, и вдруг - решили все переделать. Вернуть как было.&lt;br /&gt;&lt;br /&gt;Можно конечно воспользоваться reflog-ом&lt;br /&gt;например, вернуть ветку master на значение, которое было 3 часа назад, можно через&lt;br /&gt;&lt;pre&gt;
git-checkout master
git-reset --hard &apos;master@{3 hours ago}&apos;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;И так для всех веток. Это в том случае если вы помните, что начали патчить 3 часа назад.&lt;br /&gt;&lt;br /&gt;Если же вы, как и я, сильно увлекаетесь и забываете о времени - это вряд ли подойдет.&lt;br /&gt;&lt;br /&gt;На этот случай можно сделать хитрый ход конем. Через git-remote создается &quot;удаленный репозиторий&quot;, который на самом деле совпадает с текущим репозиторием. Вот как это делается.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
git-remote add backup `pwd`
git-fetch -f backup
&lt;/pre&gt;&lt;br /&gt;После выполнения git-fetch -f backup все существующие ветки будут сохранены в refs/remotes/backup/&amp;lt;имя ветки&amp;gt;&lt;br /&gt;&lt;br /&gt;И &quot;восстановить&quot; бранч master из бэкапа можно командой&lt;br /&gt;&lt;pre&gt;
git-checkout master
git-reset --hard backup/master
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Еще раз: бэкап делается через git-fetch -f backup, а восстановление веток делается путем git-reset --hard backup/branch.&lt;br /&gt;&lt;br /&gt;Этот метод можно развивать, создавая несколько бэкапов. Каждый такой &quot;псевдо-удаленный&quot; репозиторий представляет собой мгновенный слепок всех веток на момент git-fetch -f.&lt;br /&gt;&lt;br /&gt;В дополнение к бэкапам можно использовать и &quot;корзины&quot;. Например, перед откатом на бэкап вам возможно захочется сохранить текущие наработки во всех ветках, на всякий случай - вдруг пригодятся. Не проблема - создаете псевдоудаленный репозиторий &quot;recyclebin&quot;, делаете git-fetch -f recyclebin - и все ваши наработки сохраняются в удаленных ветках этого репозитория. В дальнейшем их можно вернуть, сделать cherry-pick полезных патчей оттуда и т.п.&lt;br /&gt;&lt;br /&gt;Также как и бэкапов, корзин можно сделать сколько угодно.&lt;br /&gt;</description>
  <comments>http://los-t.livejournal.com/17586.html</comments>
  <category>git gems</category>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/17156.html</guid>
  <pubDate>Mon, 22 Oct 2007 19:41:49 GMT</pubDate>
  <title>Git Guts (Part 4)</title>
  <link>http://los-t.livejournal.com/17156.html</link>
  <description>Git не был бы системой контроля версий, если бы не позволял хранить историю изменений деревьев.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Для хранения истории в git используются специальные объекты-commit&apos;ы. Каждому коммиту соответствует ровно одно дерево. Коммиты также хранят информацию о &quot;предках&quot; этого дерева - то есть ссылки на т.н. родительские коммиты. Можно считать, что коммит указывает, из каких деревьев (их может быть несколько) произошло текущее дерево, а также кто в этом виноват (автор коммита) и по какой причине (сообщение коммита).&lt;br /&gt;&lt;br /&gt;У самого первого коммита в репозитории не может быть предков. Он считается начальным коммитом, и считается что до него ничего не было. В репозитории git обычно бывает только один начальный коммит, а все остальные происходят из него. Можно считать начальный коммит Адамом и Евой :) У большинства коммитов предок всего один, поэтому часто история коммитов линейна. Авраам родил Исаака, Исаак родил Иакова, Иаков родил Иуду и т.д. :)&lt;br /&gt;&lt;br /&gt;Бывает, что несколько коммитов происходят от одного предка. В этом месте в истории появляется &quot;развилка&quot; - история начинает делиться на ветви (&quot;колена&quot;, если продолжать аналогию с Библией).&lt;br /&gt;&lt;br /&gt;Но бывают еще коммиты, у которых несколько родителей. Это т.н. коммиты-слияния (merges), и в общем-то, количество родителей у коммита не ограничено. Это действие противоположно вышеописанной &quot;развилке&quot;, и объединяет ранее разделенные ветви. Так, породнились бы Капулетти и Монтекки, если бы Вильяму Шекспиру захотелось бы устроить в &quot;Ромео и Джульетте&quot; хэппи-энд.&lt;br /&gt;&lt;br /&gt;Но довольно лирики. Если говорить формально, то сам объект-коммит - это простой текст в строго определенном формате. У каждого коммита есть соответствующее дерево (первая строчка), далее перечисляются родители (каждый родитель на отдельной строчке), а дальше указываются &quot;автор&quot; коммита и время создания коммита.&lt;br /&gt;После этого указывается т.н. &quot;committer&quot; - человек, который записал коммит в историю репозитория. Вместе с committer записывается и время, когда коммит был записан в историю. После чего оставшиеся строки занимает сообщение о коммите - произвольный текст, который указал автор при создании коммита.&lt;br /&gt;&lt;br /&gt;Обычно поля committer и author совпадают, если автор сразу же после создания коммита записывает его в репозиторий. Но бывает и другая ситуация, когда один человек создает коммит, а другой применяет этот коммит к своему репозиторию. Тогда author и committer  будут совершенно разными людьми. И committer и author указываются в формате Имя &amp;lt;email&amp;gt;, который считается стандартным форматом для задания адреса электронной почты.&lt;br /&gt;&lt;br /&gt;Создать объект-коммит можно с помощью команды git-commit-tree.&lt;br /&gt;&lt;br /&gt;У этой команды один обязательный параметр - SHA1 объекта-дерева, соответствующего коммиту. Также может быть несколько необязательных параметров, перечисляющих родителей коммита.&lt;br /&gt;&lt;br /&gt;На вход (stdin) этой команде надо подать сообщение коммита. Остальные поля (author и commiter) команда заполняет сама. Если определенным образом не сконфигурировать git, по умолчанию в качестве имени автора будет использоваться имя текущего пользователя, а в качестве адреса электронной почты - &amp;lt;login текущего=&quot;текущего&quot; пользователя@имя=&quot;пользователя@имя&quot; хоста=&quot;хоста&quot;&amp;gt;. Также в качестве даты создания коммита и записи его в историю, будет использоваться текущая дата.&lt;br /&gt;&lt;br /&gt;Ну что долго объяснять, вот вам пример:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitguts4
$ cd ~/tmp/gitguts4
$ git-init
Initialized empty Git repository in .git/

$ echo &quot;file1&quot; &amp;gt; file1
$ echo &quot;file2&quot; &amp;gt; file2

$ git-hash-object -w file1
e2129701f1a4d54dc44f03c93bca0a2aec7c5449

$ git-hash-object -w file2
6c493ff740f9380390d5c9ddef4af18697ac9375

$ echo -e &quot;10644 blob e2129701f1a4d54dc44f03c93bca0a2aec7c5449\tfile1
10644 blob 6c493ff740f9380390d5c9ddef4af18697ac9375\tfile2&quot; | git-mktree

eaa27839f1ccaa6e087202ec96c479ee2c93b71e

$ export GIT_AUTHOR_NAME=&quot;Git Guts&quot;
$ export GIT_AUTHOR_EMAIL=&quot;gitguts@localhost&quot;
$ export GIT_COMMITTER_NAME=&quot;$GIT_AUTHOR_NAME&quot;
$ export GIT_COMMITTER_EMAIL=&quot;$GIT_AUTHOR_EMAIL&quot;

$ echo &quot;Initial commit&quot; | faketime -t 200001010000 git-commit-tree  eaa27839f1ccaa6e087202ec96c479ee2c93b71e

a215c9607c843ff00bc1490fb51271b6211070a2
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Обратите внимание - я использовал задание автора и коммитера через переменные окружения, а также использовал faketime для того, чтобы задать время создания коммита и время сохранения его в репозитории. Дело в том, что если вы попытаетесь повторить мои действия, и не будете использовать переменные окружения и faketime, то в коммите будет другое время, и другие авторы/коммитеры,  и вы не сможете полностью воспроизвести последующие действия, так как у коммитов будут другие имена и другое содержимое.&lt;br /&gt;&lt;br /&gt;Посмотреть содержимое созданного объекта можно, используюя утилиту git-cat-file&lt;br /&gt;&lt;pre&gt;
$ git-cat-file commit a215c9607c843ff00bc1490fb51271b6211070a2
tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e
author Git Guts &amp;lt;gitguts@localhost&amp;gt; 946674000 +0300
committer Git Guts &amp;lt;gitguts@localhost&amp;gt; 946674000 +0300

Initial commit
&lt;/pre&gt;&lt;br /&gt;Ну, думаю не стоит объяснять, где что находится в этом объекта - все и так очевидно. Созданный коммит не имеет предков - то есть является сиротой. :) Давайте создадим ему потомков, чтобы было веселее. Для того, чтобы указать родителя коммита, в параметры git-commit-tree надо добавить -p &amp;lt;sha1 родителя&amp;gt;, ну например как показано в следующем примере:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo &quot;Abraham&quot; | faketime -t 200001010100 git-commit-tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e -p a215c9607c843ff00bc1490fb51271b6211070a2

09e01781c4c8245acd0728184d7cb8d9c7579901

$ git-cat-file commit 09e01781c4c8245acd0728184d7cb8d9c7579901
tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e
parent a215c9607c843ff00bc1490fb51271b6211070a2
author Git Guts &amp;lt;gitguts@localhost&amp;gt; 946677600 +0300
committer Git Guts &amp;lt;gitguts@localhost&amp;gt; 946677600 +0300

Abraham
&lt;/pre&gt;&lt;br /&gt;Итак, Авраам рожден :) Видите, в коммите добавилось поле parent, с указанием родительского коммита. Добавим же Исаака - сына его :) (для этого укажем в поле &quot;родитель&quot; SHA1 Авраама).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo &quot;Isaac&quot; | faketime -t 200001010200 git-commit-tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e -p 09e01781c4c8245acd0728184d7cb8d9c7579901

420a3454070a1767c3fe7107f9dc753d8ff3722c

$ git-cat-file commit 420a3454070a1767c3fe7107f9dc753d8ff3722c
tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e
parent 09e01781c4c8245acd0728184d7cb8d9c7579901
author Git Guts &amp;lt;gitguts@localhost&amp;gt; 946681200 +0300
committer Git Guts &amp;lt;gitguts@localhost&amp;gt; 946681200 +0300

Isaac
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Для простоты для всех создаваемых коммитов я указываю одно и то же дерево. В большинстве реальных случаев деревья таки будут чем-то отличаться.&lt;br /&gt;&lt;br /&gt;Давайте теперь посмотрим на историю вновь созданного Исаака. Просмотром истории в git занимается программа-историк git-log. &lt;br /&gt;&lt;pre&gt;
$ PAGER=cat git-log 420a3454070a1767c3fe7107f9dc753d8ff3722c 
commit 420a3454070a1767c3fe7107f9dc753d8ff3722c
Author: Git Guts &amp;lt;gitguts@localhost&amp;gt;
Date:   Sat Jan 1 02:00:00 2000 +0300

    Isaac

commit 09e01781c4c8245acd0728184d7cb8d9c7579901
Author: Git Guts &amp;lt;gitguts@localhost&amp;gt;
Date:   Sat Jan 1 01:00:00 2000 +0300

    Abraham

commit a215c9607c843ff00bc1490fb51271b6211070a2
Author: Git Guts &amp;lt;gitguts@localhost&amp;gt;
Date:   Sat Jan 1 00:00:00 2000 +0300

    Initial commit

&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Я использовал PAGER=cat, чтобы git-log не запускал для просмотра истории команду less (ну или что там у вас поставлено вместо $PAGER), а просто тупо вываливал информацию в терминал.&lt;br /&gt;&lt;br /&gt;Итак, по выводу истории видно, что от начального коммита произошел Авраам, а от Авраама - Исаак :)&lt;br /&gt;&lt;br /&gt;Продолжим наши уроки Ветхого завета и продемонстрируем &quot;развилку&quot;. У Исаака, как известно, было два сына - Исав и Иаков. Исав - старший брат, Иаков - младший. Продемонстрируем это в терминах git.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo &quot;Esau&quot; | faketime -t 200001010300 git-commit-tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e -p 420a3454070a1767c3fe7107f9dc753d8ff3722c
de10f1828d215892dcebd00c4f7738141bfd0df7

$ echo &quot;Jakob&quot; | faketime -t 200001010400 git-commit-tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e -p 420a3454070a1767c3fe7107f9dc753d8ff3722c
f77f5c2466a3f8674d3ec8785b13a910d32e5a75
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Вот, таким вот макаром были рождены эти два брата. Для того, чтобы отобразить их отношения, обычного текстового формата недостаточно. Поэтому будем использовать графическую программу gitk. В качестве параметров я перечислил SHA1-имена братьев.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ gitk de10f1828d215892dcebd00c4f7738141bfd0df7 f77f5c2466a3f8674d3ec8785b13a910d32e5a75
&lt;/pre&gt;&lt;br /&gt;Результат работы можно увидеть вот тут:&lt;br /&gt;&lt;img src=&quot;http://www.ljplus.ru/img4/l/o/los_t/gitguts4.png&quot; width=&quot;558&quot; height=&quot;180&quot; alt=&quot;Исав и Иаков&quot;&gt;&lt;br /&gt;&lt;br /&gt;Как видно, налицо развилочка. В дальнейшем каждая ветвь может получить отдельное развитие.&lt;br /&gt;&lt;br /&gt;Ну, в общем, хватит на сегодня.&lt;br /&gt;&lt;br /&gt;О таких захватывающих вещах как коммиты-слияния (merges) я, пожалуй, расскажу в следующий раз.</description>
  <comments>http://los-t.livejournal.com/17156.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/17092.html</guid>
  <pubDate>Tue, 14 Aug 2007 11:19:01 GMT</pubDate>
  <title>Git Guts (Part 3)</title>
  <link>http://los-t.livejournal.com/17092.html</link>
  <description>В первой части я уже упоминал, что репозиторий git представляет собой картотеку объектов, объединенных ссылками друг на друга. &lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Из четырех типов объектов в git (blob, tree, commit, tag) только blob-ы не могут содержать ссылки. Все остальные объекты, по сути, являются просто ссылками либо на blob-ы, либо на другие ссылки.&lt;br /&gt;&lt;br /&gt;Мы уже знаем, что blob-ы включают в себя только содержание файла, но не его имя, или режимы доступа. Вся информация об именах содержится в объектах-деревьях (tree). Фактически, деревья аналогичны понятию &quot;каталог&quot; в файловой системе, так же как blob-ы аналогичны понятию inode.&lt;br /&gt;&lt;br /&gt;Объекты-деревья могут хранить внутри себя как ссылки на blob-ы, так и ссылки на другие объекты-деревья. В результате можно построить иерархию деревьев, аналогичную иерархии каталогов и файлов.&lt;br /&gt;&lt;br /&gt;Объект-дерево представляет собой список элементов, состоящих из четырех полей:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; mode (режим доступа) - представляет собой права UNIX на объект-ссылку, плюс несколько дополнительных битов, позволяющих хранить в гите символические ссылки. Записывается в виде шести цифр, из которых первые три описывают тип объекта, а оставшиеся - права UNIX. Правда мне ни разу не удалось увидеть, чтобы значение третьей цифры было отлично от нуля, так что я не знаю что она означает.&lt;br /&gt;Первая цифра - 1 для файлов и символических, 0 для директорий.&lt;br /&gt;Вторая цифра - 0 для файлов, 2 для символических ссылок, 4 - для директорий&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Тип объекта, на который ссылается элемент списка. Может быть blob или tree.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; SHA1 хеш объекта. Собственно, это и является ссылкой, так как однозначно определяет объект в репозитории git. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt; имя объекта. Имя файла для blob-ов, имя директории для tree.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Объект-дерево после создания получает свое имя-хеш, и может быть после этого включен в другие деревья.&lt;br /&gt;&lt;br /&gt;Создать новый объект-дерево можно с нуля, используя команду git-mktree. Ей на вход (stdin) надо передать текстовый список, в котором каждая строчка описывает один элемент. Первые три поля должны быть разделены пробелами, а последнее - имя объекта - должно быть отделено табом.&lt;br /&gt;&lt;br /&gt;Вот пример:&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitgut3
$ cd ~/tmp/gitgut3
$ git-init
Initialized empty Git repository in .git/

$ echo &quot;File1&quot; &amp;gt; file1
$ echo &quot;File2&quot; &amp;gt; file2

$ git-hash-object -w file1
03f128cf48cb203d938805e9f3e13b808d1773e9
$ git-hash-object -w file2
b973e639605e63466ea5ba09b04a545f16946ca8

$ echo -e &quot;100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9\tfile1
100640 blob b973e639605e63466ea5ba09b04a545f16946ca8\tfile2&quot; | git-mktree

b2efb2a7e48025c4d185080412a6ba1121ee6c59
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно из примера, команде git-mktree нужно подать на стандартный вход содержимое создавамого объекта-дерева, что я и сделал командой echo.&lt;br /&gt;Полученный объект-дерево теперь присутствует в базе:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ ls .git/objects/b2/efb2a7e48025c4d185080412a6ba1121ee6c59 
.git/objects/b2/efb2a7e48025c4d185080412a6ba1121ee6c59
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Его содержимое можно посмотреть, используя команду git-ls-tree&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-ls-tree b2efb2a7e48025c4d185080412a6ba1121ee6c59     
100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9    file1
100640 blob b973e639605e63466ea5ba09b04a545f16946ca8    file2
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Чтобы далеко не уходить, покажу, чем же полезно, что деревья являются именно объектами, с именами-хешами.&lt;br /&gt;&lt;br /&gt;Например, если у двух объектов-деревьев одинаковое имя-хеш, что это означает? Что внутренности этих деревьев совпадают! А так как внутренности деревьев - это ссылки на объекты, то это означает что два дерева ссылаются на одни и те же объекты. Которые в свою очередь тоже могут быть деревьями или блобами. Таким образом имя-хеш дерева на самом деле идентифицирует не только &quot;файлы в директории&quot;, но и все файлы во всех поддиректориях этой директории - одно имя для всех иерархии!&lt;br /&gt;&lt;br /&gt;Это свойство позволяет git-у очень быстро производить сравнение деревьев со сколь угодно сложной иерархией, уровнями вложенности и т.д. без чтения собственно содержимого - blob-ов или tree.&lt;br /&gt;&lt;br /&gt;Например, я создаю новое дерево, которое отличается от старого дерева b2efb2a7e4... тем, что в содержимое file2 была добавлена дополнительная строчка, а файл file1 переименован в file3.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ echo Secondline &amp;gt;&amp;gt; file2
$ git-hash-object -w file2
&lt;b&gt;4dd2746869211aedfec0f07afb12a879c09569e7&lt;/b&gt;

$ echo -e &quot;100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9\t&lt;b&gt;file3&lt;/b&gt;
100640 blob &lt;b&gt;4dd2746869211aedfec0f07afb12a879c09569e7&lt;/b&gt;\tfile2&quot; | git-mktree

493a5292de0b743e77aa190921da56d33599b59e

$ git-ls-tree 493a5292de0b743e77aa190921da56d33599b59e

100640 blob 4dd2746869211aedfec0f07afb12a879c09569e7    file2
100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9    file3
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Давайте посмотрим, как git может легко вычислить разницу между этими деревьями. используя только объекты-деревья.&lt;br /&gt;Для этого сохраним выводы git-ls-tree для каждого дерева в отдельный файл и натравим на них команду diff -u.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-ls-tree b2efb2a7e48025c4d185080412a6ba1121ee6c59 &amp;gt; tree1
$ git-ls-tree 493a5292de0b743e77aa190921da56d33599b59e &amp;gt; tree2
$ diff -u tree1 tree2
--- tree1       2007-08-14 14:55:06 +0400
+++ tree2       2007-08-14 14:55:30 +0400
@@ -1,2 +1,2 @@
&lt;font color=&quot;red&quot;&gt;-100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9   file1
-100640 blob b973e639605e63466ea5ba09b04a545f16946ca8   file2&lt;/font&gt;
&lt;font color=&quot;green&quot;&gt;+100640 blob 4dd2746869211aedfec0f07afb12a879c09569e7   file2
+100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9   file3&lt;/font&gt;
&lt;/pre&gt;&lt;br /&gt;Итак, видно, что по сравнению с деревом 1 в дереве два исчез file1, у file2 изменился SHA1 хеш, и добавился новый file3.&lt;br /&gt;Также можно заметить, что у удаленного файла file1 и добавленного файла file3 одинаковый SHA1 хеш - отсюда можно сделать вывод, что было произведено переименование из file1 в file3 без изменения содержимого.&lt;br /&gt;&lt;br /&gt;Точно такую же работу производит и git, точнее его команда git-diff-tree. Она выводит разницу между двумя деревьями в читабельном для человека виде.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-diff-tree b2efb2a7e48025c4d185080412a6ba1121ee6c59 493a5292de0b743e77aa190921da56d33599b59e
:100644 000000 03f128cf48cb203d938805e9f3e13b808d1773e9 0000000000000000000000000000000000000000 D      file1
:100644 100644 b973e639605e63466ea5ba09b04a545f16946ca8 4dd2746869211aedfec0f07afb12a879c09569e7 M      file2
:000000 100644 0000000000000000000000000000000000000000 03f128cf48cb203d938805e9f3e13b808d1773e9 A      file3
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Если git-diff-tree вызывать с ключом -p, то она сгенерирует патч, который будучи применен к tree1, приведет его к tree2.&lt;br /&gt;&lt;pre&gt;
git-diff-tree -p b2efb2a7e48025c4d185080412a6ba1121ee6c59 493a5292de0b743e77aa190921da56d33599b59e
diff --git a/file1 b/file1
deleted file mode 100644
index 03f128c..0000000
--- a/file1
+++ /dev/null
@@ -1 +0,0 @@
-File1
diff --git a/file2 b/file2
index b973e63..4dd2746 100644
--- a/file2
+++ b/file2
@@ -1 +1,2 @@
 File2
+Secondline
diff --git a/file3 b/file3
new file mode 100644
index 0000000..03f128c
--- /dev/null
+++ b/file3
@@ -0,0 +1 @@
+File1
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно по патчу, git-diff-tree не учел, что файл file1 был переименован в file3, и сгенерировал патч так, как будто file1 удалили, и file3 добавили заново.&lt;br /&gt;&lt;br /&gt;Но как мы знаем, blob-ы у file1 и file3 совпадают - поэтому можно точно сказать что было переименование. Для того, чтобы git-diff-tree стал обращать на это внимание, ему надо передать ключик -M (detect renames).&lt;br /&gt;&lt;br /&gt;Тогда он сгенерирует особый патч-переименование. К сожалению, стандартная команда patch не может прикладывать такие патчи-переименования, так что потребуется прикладывать этот патч к дереву с помощью команды git-apply.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-diff-tree -M -p b2efb2a7e48025c4d185080412a6ba1121ee6c59 493a5292de0b743e77aa190921da56d33599b59e
diff --git a/file2 b/file2
index b973e63..4dd2746 100644
--- a/file2
+++ b/file2
@@ -1 +1,2 @@
 File2
+Secondline
&lt;b&gt;diff --git a/file1 b/file3
similarity index 100%
rename from file1
rename to file3&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Итак, объекты-деревья служат для объединения blob-ов и других деревьев в иерархию, аналогичную файловой системе. Деревья хранят биты доступа, хеши содержимого и имена объектов, поэтому между двумя деревьями может быть разница только по этим параметрам. &lt;br /&gt;&lt;br /&gt;Такие параметры как времена создания, изменения и доступа файла, а также создатель или владелец файла, в деревьях не записываются. Некоторое подобие такой информации хранят объекты-commit&apos;ы, о которых я расскажу в следующий раз.&lt;br /&gt;&lt;br /&gt;А пока вам домашнее задание: создайте пустое объект-дерево (вообще без файлов) и запостите сюда его SHA1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Продолжение следует.</description>
  <comments>http://los-t.livejournal.com/17092.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>9</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/16702.html</guid>
  <pubDate>Mon, 13 Aug 2007 17:32:23 GMT</pubDate>
  <title>Git Guts (Part 2)</title>
  <link>http://los-t.livejournal.com/16702.html</link>
  <description>Чтож, если ваш мозг не был зохаван Ктулху во время чтения предыдущего поста, то вы уже знаете, что репозиторий git представляет собой картотеку различных объектов, разложенную по именам-хешам. Объекты бывают четырех типов - blob, tree, commit, tag.&lt;br /&gt;&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;Объекты типа blob(Binary Large Object) - это основа репозитория. Это маленькие безымянные герои. Безымянные в прямом смысле - это просто содержимое, без имени. Если вы добавляете в git файл tutorial.txt с содержимым &quot;Hello, world!&quot;, то это результирующий blob-объект будет содержать строчку &quot;Hello, world!&quot; и ни слова о tutorial.txt. Это очень похоже на иноды (inodes), используемые в файловых системах, если вы понимаете о чем я.&lt;br /&gt;&lt;br /&gt;Новый blob-объект создается из содержимого файла с помощью команды git-hash-object.&lt;br /&gt;&lt;br /&gt;Если вызывать ее без параметров, только с именем файла - то она выведет SHA1 хеш blob-объекта, который будет создан из этого файла. Если же вызвать ее с параметром -w, то соответствующий blob-объект будет записан в базу под именем, соответствующим этому хешу.&lt;br /&gt;&lt;br /&gt;Если объект с таким именем уже существует в базе - то он не будет перезаписан. Вспомните, что имя является &quot;отпечатком пальца&quot; объекта, достаточно уникальным. Значит, если у двух объектов одинаковые имена, то у них одинаковые содержимые. Поэтому git не будет перезаписывать blob.&lt;br /&gt;&lt;br /&gt;Например, если в гит положить десять абсолютно одинаковых файлов весом 6 мегабайт, то реально в базе будет занято только 6 мегабайт, а не 60. Это из-за того что blob-объекты не содержат никакой информации об именах файлов, из которых они сделаны, поэтому они идентичны.&lt;br /&gt;&lt;br /&gt;Вот пример создания blob-объекта:&lt;br /&gt;&lt;pre&gt;
$ mkdir ~/tmp/gitguts
$ cd ~/tmp/gitguts
$ git-init
Initialized empty Git repository in .git/

$ echo &quot;Hello, World\!&quot; &amp;gt; tutorial.txt
$ git-hash-object -w tutorial.txt 
8ab686eafeb1f44702738c8b0f24f2567c36da6d

$ find .git/objects -type f
.git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видно, вызов git-hash-object с параметром -w действительно создал и сохранил в базе новый объект типа blob, содержащий строчку &quot;Hello, world!&quot;&lt;br /&gt;&lt;br /&gt;Посмотреть, что внутри объекта-blob можно с помощью команды git-cat-file&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-cat-file blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d
Hello, World!
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Этот новосозданный объект пролежит в базе до тех пор, пока не будет вызван &quot;уборщик мусора&quot; (git-prune или git-gc --prune). Этот трудяга проверяет &quot;прописку&quot; всех объектов, и если на объект не имеется никаких ссылок, то он удаляется из базы. На этот объект мы еще не сделали никаких ссылок, так что при сборке мусора он просто исчезает из базы.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
$ git-prune
$ find .git/objects -type f
.git/objects/info/packs
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Сами объекты-blob не могут иметь никаких ссылок. Вместо этого, на них ссылается другой объект - дерево(tree). О них мы поговорим в следующий раз.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Продолжение следует. Stay tuned!</description>
  <comments>http://los-t.livejournal.com/16702.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://los-t.livejournal.com/16400.html</guid>
  <pubDate>Mon, 13 Aug 2007 13:30:14 GMT</pubDate>
  <title>Git Guts (part 1)</title>
  <link>http://los-t.livejournal.com/16400.html</link>
  <description>Где-то около месяца назад я полностью прочитал man git, и немножко поэкспериментировал с внутренностями git, чтобы понять, как же там все устроено внутри. &lt;br /&gt;&lt;br /&gt;Оказалось, внутренне все сделано просто и элегантно.&lt;br /&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;br /&gt;В отличие от сложно-бинарных репозиториев subversion или недорепозиториев CVS, в git все кристалльно просто, и доступно даже на самом низком уровне.&lt;br /&gt;&lt;br /&gt;Репозиторий git - это просто коллекция т.н. объектов, объединенных ссылками друг на друга. Каждый объект - это некий файл специального формата. У каждого объекта есть &quot;имя&quot;, которое вычисляется как SHA1 хеш содержимого объекта и записываемся как шестнадцатеричное представление этого хеша. Длина хеша равна 20 байтам, так что шестнадцатеричное представление содержит 40 букв и цифр.&lt;br /&gt;&lt;br /&gt;Для тех, кто не знает что такое хеш и зачем он нужен - поясняю буквально на пальцах.&lt;br /&gt;&lt;br /&gt;Давайте отвлечемся от компьютеров и посмотрим на современную криминалистику. Как известно, преступники часто оставляют на месте преступления свои отпечатки пальцев. Эти отпечатки пальцев представляют собой комбинацию углов, завитков, спиралей и т.д. Эксперт, имея схему отпечатков, может просмотреть картотеку накопленных полицией/милицией отпечатков пальцев преступников, и найти совпадение. Существенное в этом методе то, что по минимальной информации - отпечаткам пальцев, удается (или не удается) найти преступника среди миллионов остальных людей.&lt;br /&gt;&lt;br /&gt;У отпечатков пальцев есть три интересных свойства, которые и помогают провести опознание. Первое - что у одного и того же человека отпечатки пальцев в течение жизни практически не меняются. Второе - у разных людей&lt;br /&gt;отпечатки пальцев разные (даже у неразличимых близнецов). Третье - их очень легко получить и найти - нужно всего лишь чернила и бумагу.&lt;br /&gt;&lt;br /&gt;Вернемся к нашим баранам. Хеш-функция - это своеобразный &quot;отпечаток пальца&quot; файла и обладает всеми вышеперечисленными свойствами: &lt;br /&gt;1. Если содержимое двух файлов совпадает - то их хеши тоже совпадают.&lt;br /&gt;2. Если содержимое двух файлов различны - то их хеши тоже различны (за исключением случаев коллизий, о которых я расскажу ниже).&lt;br /&gt;3. Вычислить хеш-функцию SHA1 можно очень быстро (фактически, современный процессор при этом не нагружается, узкое место тут - чтение файла с диска).&lt;br /&gt;&lt;br /&gt;Возможны случаи, когда у двух разных файлов хеш-функция одинаковая.&lt;br /&gt;Такие случаи называются коллизиями. Количество коллизий у любой хеш-функции бесконечно - ведь она позволяет любое количество информации преобразовать в фиксированное, конечное количество байт. Если бы людей было бы бесконечное количество - то среди них бы тоже бы наблюдались коллизии по отпечаткам пальцев или по любым другим методам опознания.&lt;br /&gt;&lt;br /&gt;Поэтому различные хеш-функции отличаются сложностью возникновения коллизий (или их целенаправленного подбора). Хеш-функция SHA1 считается достаточно сложной для подбора или случайного возникновения коллизии, так как пока неизвестно алгоритма подбора коллизии, кроме как методом перебора, а криптологические особенности алгоритма уменьшают вероятность случайного возникновения коллизий.&lt;br /&gt;&lt;br /&gt;Кстати, вычислить эту сумму для прозвольного файла в системе может специальаная утилита sha1sum, входящая в coreutils.&lt;br /&gt;&lt;br /&gt;Коллекция объектов git - это &quot;картотека&quot;, куда заносятся все объекты. Они упорядочены по именам, которые являются также SHA1 отпечатками объектов. Это имя позволяет быстро и однозначно идентифицировать объект, а также проверить его целостность - если объект повредился, его хеш не совпадет с именем.&lt;br /&gt;&lt;br /&gt;Расположены все объекты в каталоге .git/objects. Для того чтобы не сваливать все объекты в одну директорию, git отделяет первые два символа имени объекта и создает поддиректорию с таким именем в .git/objects.&lt;br /&gt;&lt;br /&gt;Вот например, содержимое базы некоторого git-репозитория&lt;br /&gt;&lt;pre&gt;
.git/objects/a4/b7fce097055c3cbd6879db9625f9a3890cc409
.git/objects/8c/3c7fbcd903744b20fd7567a1fcefa99133b5bc
.git/objects/e9/65047ad7c57865823c7d992b1d046ea66edf78
&lt;/pre&gt;&lt;br /&gt;То есть в ней хранятся три объекта: &lt;br /&gt;&lt;br /&gt;1. a4b7fce097055c3cbd6879db9625f9a3890cc409&lt;br /&gt;2. 8c3c7fbcd903744b20fd7567a1fcefa99133b5bc&lt;br /&gt;3. e965047ad7c57865823c7d992b1d046ea66edf78&lt;br /&gt;&lt;br /&gt;Сделано это для ускорения поиска объекта по его имени. Несложно догадаться, что такой нехитрый прием ускоряет поиск в 256 раз.&lt;br /&gt;&lt;br /&gt;Добавлю напоследок, что объекты в git бывают четырех типов - blob, tree, commit и tag. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Продолжение следует. Если есть какие-то вопросы или комментарии - милости прошу.</description>
  <comments>http://los-t.livejournal.com/16400.html</comments>
  <category>git guts</category>
  <lj:security>public</lj:security>
  <lj:reply-count>9</lj:reply-count>
</item>
</channel>
</rss>
