Merge branch 'multiplayer-es' of https://github.com/irtusb/gitmagic
[gitmagic/gitmagic.git] / ru / history.txt
blob221371e6f9d432a08f3bfb7f3f95aee4aa84d6db
1 == Уроки истории ==\r
2 \r
3 Вследствие распределенной природы Git, историю изменений можно легко редактировать. Однако, если вы вмешиваетесь в прошлое, будьте осторожны: изменяйте только ту часть истории, которой владеете вы и только вы. И также как государства бесконечно выясняют, кто же именно совершил и какие бесчинства, так и у вас будут проблемы с примирением после взаимодействия деревьев истории.\r
4 \r
5 Конечно, если вы также контролируете и все остальные деревья, то нет никаких проблем поскольку вы можете переписать их.\r
6 \r
7 Некоторые разработчики убеждены, что история должна быть неизменна со всеми огрехами и прочим.  \r
8 Другие считают, что деревья должны быть презентабельными, до того как они выпустят их в публичный доступ.\r
9 Git учитывает оба мнения. Также как клонирование, ветвление и слияние, переписывание истории - это просто еще одна возможность, которую дает вам Git. Разумное ее использование зависит только от вас.\r
11 === Оставаясь корректным ===\r
13 Только что сделали коммит и уже хотите изменить запись в журнале? Запустите:\r
15  $ git commit --amend\r
17 чтобы изменить последнее сообщение коммита. Осознали, что забыли добавить файл? Запустите *git add*, чтобы это сделать и выполните вышеуказанную команду.\r
19 Захотелось добавить еще немного изменений в последний коммит? Так сделайте их и запустите:\r
21  $ git commit --amend -a\r
23 === ...И кое-что еще ===\r
25 Давайте представим себе, что предыдущая проблема на самом деле в десять раз хуже. После длительной работы вы сделали ряд фиксаций, но вы не очень-то довольны тем, как они организованы и кое-какие записи в журнале (commit messages) надо бы слегка переформулировать. В этом случае запустите:\r
27  $ git rebase -i HEAD~10\r
29 и записи в журнале от последних 10-ти фиксаций появятся в вашем любимом редаторе (задается переменной окружения  $EDITOR). Вот кусок примера:\r
31     pick 5c6eb73 Добавил ссылку repo.or.cz\r
32     pick a311a64 Сменил порядок в "Работай как хочешь"\r
33     pick 100834f Добавил цель для push в Makefile\r
35 После чего:\r
37 - Убираем коммиты, удаляя строки.\r
38 - Меняем порядок коммитов, меняя порядок строк.\r
39 - Заменяем "pick" на "edit", если требуется внести изменения в коммиты.\r
40 - Заменяем "pick" на "squash" для слияния коммита с предыдущим.\r
42 Если вы отметили коммит для исправлений, запустите:\r
44  $ git commit --amend\r
46 Если нет, запустите:\r
48  $ git rebase --continue\r
50 В общем, делайте коммиты как можно раньше и как можно чаще - всегда потом сможете за собой подчистить при помощи rebase.\r
52 === Локальные изменения сохраняются ===\r
54 Предположим, вы работаете над активным проектом. За какое-то время были проведены несколько коммитов, после чего синхронизируетесь с официальным деревом через слияние. Цикл повторяется несколько раз до тех пор, пока вы не готовы отправить (push) изменения в центральное дерево.\r
56 Однако теперь история изменений в локальном клоне Git представляет собой кашу из ваших и официальных изменений. Вам бы хотелось видеть все  изменения непрерывной секцией даже после слияния с официальными.\r
58 Это работа для команды *git rebase* в виде, описанном выше. Зачастую, имеет смысл использовать флаг *--onto*, чтобы не использовать интерактивный режим. \r
60 Также стоит взглянуть на вывод команды *git help rebase* для получения подробных примеров использования этой замечательной команды. Вы можете объединять фиксации, вы можете даже перестраивать ветки.\r
62 === Переписывая историю ===\r
64 Время от времени вам может понадобиться эквивалент "замазывания" людей на официальных фотографиях, только  для систем контроля версий, как бы стирая их из истории в духе сталинизма. Например, предположим, что мы уже собираемся выпустить релиз проекта, но он содержит файл, который не должен стать достоянием общественности по каким-то причинам. Может я сохранил номер своей кредитки в текстовый файл и случайно добавил этот файл к файлам проекта? Просто стирать файл бесполезно - из-за контроля версий всегда можно вытащить такую из старых версий, где этот документ еще есть. Нам надо удалить файл из всех версий когда-либо существовавших. Для этого:\r
66  $ git filter-branch --tree-filter 'rm top/secret/file' HEAD\r
68 Стоит посмотреть вывод команды *git help filter-branch*, где обсуждается этот пример и даже предлагается  более быстрый метод решения. Короче говоря, *filter-branch* позволяет изменять существенные части истории при помощи одной-единственной команды.\r
70 В результате директория +.git/refs/original+ будет описывать состояние дел до выполнения операции. Убедитесь, что команда filter-branch проделала все, что вы хотели, и, если хотите опять использовать команду, удалите эту директорию.\r
72 И, наконец, замените клоны вашего проекта обновленной версией, если собираетесь в дальнейшем с ними иметь дело.\r
74 === Создавая Историю ===\r
76 [[makinghistory]]\r
77 Хотите перевести проект под управление Git? Если сейчас он находится под управлением какой-либо из хорошо известных систем контроля версий, то весьма велики шансы на то, что кто-нибудь уже позаботился и написал необходимые скрипты для экспорта всей истории проекта в Git.\r
79 А если все-таки нет? Тогда смотрите в сторону команды *git fast-import*, которая считывает текстовый ввод в специальном формате для создания истории Git "с нуля".\r
81 Обычно скрипт, использующий эту команду - это наспех состряпанное нечто, \r
82 предназначенное для однократного использования, чтоб "перетащить" проект за один раз.\r
84 В качестве примера, вставьте следующий листинг в какой-нибудь файл, типа '/tmp/history':\r
86 ----------------------------------\r
87 commit refs/heads/master\r
88 committer Alice <alice@example.com> Thu, 01 Jan 1970 00:00:00 +0000\r
89 data <<EOT\r
90 Стартовый коммит.\r
91 EOT\r
93 M 100644 inline hello.c\r
94 data <<EOT \r
95 #include <stdio.h>\r
97 int main() {\r
98   printf("Hello, world!\n");\r
99   return 0;\r
101 EOT\r
103 commit refs/heads/master\r
104 committer Bob <bob@example.com> Tue, 14 Mar 2000 01:59:26 -0800\r
105 data <<EOT\r
106 Заменен printf() на write()\r
107 EOT\r
109 M 100644 inline hello.c\r
110 data <<EOT \r
111 #include <unistd.h>\r
113 int main() {\r
114   write(1, "Hello, world!\n", 14);\r
115   return 0;\r
117 EOT\r
119 ----------------------------------\r
121 Затем создайте репозиторий Git из этого временного файла при помощи команд:\r
123 $ mkdir project; cd project; git init\r
124 $ git fast-import < /tmp/history\r
126 Вы можете извлечь (checkout) последнюю версию проекта при помощи команды:\r
128  $ git checkout master .\r
130 Команда *git fast-export* преобразует любой репозиторий Git в формат, понимаемый командой *git fast-import*. То есть, ее выход может быть использован как образец для тех кто пишет скрипты-преобразователи и для того, чтобы переносить репозитории в формате, хоть как-то пригодном для чтения человеком. Естественно, при помощи этих команд можно пересылать репозитории текстовых файлов через каналы передачи текста.\r
132 === Когда же все пошло не так? ===\r
134 Вы только что обнаружили, что кое-какой функционал вашей программы не работает, но вы совершенно отчетливо помните, что он работал всего несколько месяцев назад. Ну вот, блин! Откуда же взялась ошибка? Вы же это проверяли сразу как разработали.\r
136 В любом случае, уже поздно сожалеть. Однако, если вам хватило ума фиксировать свои изменения часто, то Git сможет сильно помочь точно определить проблему.\r
138  $ git bisect start\r
139  $ git bisect bad SHA1_OF_BAD_VERSION\r
140  $ git bisect good SHA1_OF_GOOD_VERSION\r
142 Git извлечет состояние ровно посередине. Проверьте работает ли то, что сломалось, и если все еще нет, то введите:\r
144  $ git bisect bad\r
146 Если же работает, то замените "bad" на "good" в предыдущей команде. Git снова переместит вас в состояние посередине между "хорошей" и "плохой" ревизиями, при этом сузив круг подозреваемых ревизий вдвое.\r
148 После нескольких итераций, этот бинарный поиск приведет вас к тому коммиту, на котором все и сломалось. После окончания выяснения, вернуть исходное состояние можно командой:\r
150  $ git bisect reset\r
152 Вместо того, чтоб вручную тестировать каждое изменение - автоматизируйте этот процесс при помощи команды:\r
154  $ git bisect run COMMAND\r
156 Git использует возвращаемое значение заданной команды, обычно "одноразового" скрипта, чтоб определить "хорошее" это было изменение или "плохое". Скрипт должен вернуть 0, если "хорошее", 125 если изменение надо пропустить и любое число от 1 до 127 если "плохое". Отрицательное возвращаемое значение прерывает бинарный поиск.\r
158 На самом деле возможностей еще больше! На странице помощи объясняется как визуализировать бинарный поиск, проанализировать или даже воспроизвести журнал поиска, исключить изменения в которых точно все в порядке для ускорения поиска.\r
160 === Из-за кого все пошло наперекосяк? ===\r
162 Как и многие другие системы конроля версий, Git поддерживает команду blame:\r
164  $ git blame FILE\r
166 которая показывает кто и когда изменил каждую строку выбранного файла. В отличие же от многих других систем контроля версий эта операция происходит оффлайн, то есть данные берутся с локального диска.\r
168 === Личный опыт ===\r
170 В централизованных системах контроля версий, изменения истории - достаточно сложная операция и для ее проведения необходимо привлечение администраторов. Процедуры клонирования, ветвления и слияния невозможно осуществить без сетевого соединения. Также обстоят дела и с такими базовыми операциями как просмотр журнала изменений или фиксация изменений. В некоторых системах сетевое соединение требуется даже для просмотра собственных изменений или открытия файла для редактирования.\r
172 Централизованные системы исключают возможность работать оффлайн и требуют более дорогой сетевой инфраструктуры, особенно с увеличением количества разработчиков. Еще более важно, из-за того все операции происходят медленнее, пользователи избегают пользоваться "продвинутыми" командами до тех пор пока не "припечет как следует". В особо "запущенных" случаях это касается и большинства базовых команд тоже. Продуктивность страдает из-за остановок в работе, когда пользователи вынуждены запускать "долгоиграющие"  команды.\r
174 Я испытал этот феномен на себе. Git был моей первой системой контроля версий. Я быстро привык нему и стал относится к его возможностям как к должному. Я предположил, что и другие системы похожи на него: выбор системы контроля версий не должен отличаться от выбора текстового редактора или браузера.\r
176 Когда, немного позже, я был вынужден использовать централизованную систему контроля версий, я был шокирован. При использовании Git, мое, зачастую капризное, интернет-соединение не имело большого значения, но теперь разработка стала невыносимой когда от него потребовалась надежность как у жесткого диска. Плюс к этому, я обнаружил, что стал избегать использовать некоторые команды из-за получающихся в результате их выполнения задержек, а без них оказалось невозможным следовать моему стилю разработки.\r
178 Когда мне было нужно запустить "медленную" команду, нарушение хода цепочки моих мыслей оказывало несоизмеримый ущерб разработке. Ожидая окончания связи с сервером, я должен был заниматься чем-то другим, чтоб скоротать время, например, чтением почты или написанием документации. Через некоторое время я возвращался к первоначальной задаче, но приходилось тратить уйму времени, чтоб вспомнить на чем же я остановился и что хотел делать дальше. Все-таки люди не очень приспособлены для многозадачности.\r
180 Есть еще один интересный эффект, так называемая, трагедия общин: предвидя будущую загрузку сети, некоторые люди начинают использовать более "широкие" каналы чем им реально требуются для текущих операций в попытке предотвратить будущие задержки. Суммарная активность увеличивает загрузку сети, поощряя людей задействовать еще более высокоскоростные каналы в следующий раз, чтоб избежать еще больших задержек.\r