вторник, 23 марта 2010 г.

Mercurial и Git

Про них наверное только ленивый не писал, вот и я решил тоже отметиться.

В свое время активно использовал на работе cvs, для контроля изменений на сайте.
На следующей работе использовал perforce и clearcase. На другой работе использовал subversion, затем mercurial, в уме держу git. Надеюсь понятно, что взгляд на системы контроля версий вполне широкий. Да и с утилитами diff, patch очень хорошо знаком.

Во первых, всегда удивляет, что пытаются сравнивать обе системы с svn, cvs, clearcase, но не между собой, когда только между собой их и можно сравнивать. С другими системами просто идеологически нельзя сравнивать. Все остальные не являются распределенными и не зависимыми от сервера. Разве что в плане функциональности сравнивать, где слияние удобнее или еще какие фишки (например, файл конфигурации в clearcase).

Как только вы теряете контакт с сервером вы никто, даже зафиксировать свои изменения не сможете, но в Mercurial и Git можете. И это главное преимущество этих двух систем Mercurial и Git перед всеми остальными.

Пока вы сидите в офисе друг напротив друга, сервачок жужит где-то рядом, все отлично работает в subversion или clearcase, слияние и ответвление, красивые графики в trac, что откуда и куда влилось и вылилось (не без напильника конечно).

Но все это идеально работает до вашей первой командировки в составе команды, когда вечером всей команде срочно требуется править код, так сказать в зависимости от суровых реалий. Когда нет не то что связи с центральным сервером, но даже некогда разбираться с wifi и bluetooth между ноутбуками, а самое верное средство обмена по прежнему флешка.

Причем subversion очень любит запоминать ip адрес сервера и даже простое вливание дампа репозитория сервера на новое место(ноутбук) не поможет, пока не зальете исходники с нового сервера(который встал на ноутбук). В результате, только какой нить merge по локальным файлам и помогает. А по приезду обратно, все начинают мучительно вливать килотонны своих изменений в subversion попутно вспоминая, что же за неделю было сделано и зачем.

Вот после пары, тройки таких командировок стал интересоваться Mercurial, но использовать стал много позже.

Во вторых, Mercurial на момент нашего интереса был более развит под windows, чем Git, сейчас у Git с этим тоже уже нет проблем. Но хочется отметить отличия. Mercurial в основном написан на Python с мелкими вкраплениями на C. В отличие от Git, который целиком написан на с и имеет много зависимостей с архитектурой linux, иначе бы не отвязывали так долго. Соответственно установить mercurial на хостинге с существующим python проще. Но Git в хороших традициях linux/unix состоит из набора консольных программ, чтобы их можно было легко использовать в скриптах на bash, tcl/tk. Соответственно, с Mercurial интереснее взаимодействовать через python, а с Git через обычный ввод/вывод.

В третьих, собственно интерес к Git был однажды снова подогрет после прочтения презентации про Git Линусом Торвальдсом и сравнения двух этих систем на code.google.com.

В качестве фишки, которой меня манил Git, был индекс похожести (similarity index). Дело все в том, что Git ведет не историю отдельных файлов, а сразу историю всех изменений в файловой системе в целом. Если вы переименуете один файл в другой, то Git это легко найдет, так как хэш sha1 двух файлов будет один и тот же, только изменится название файла. Это весьма важная вещь, знать откуда у тебя на самом деле взялся файл, особенно, если он был копией другого уже существующего файла (это конечно можно сделать административно :D).

Но как известно хотелось большего. Цитирую из презентации: "Одно из особенных свойств git — отслеживание изменений всего содержимого, и это отличает git даже от Mercurial, несмотря на то, что они очень похожи. "

В общем, в тайне надеялся, что в Git реализовано отслеживание перемещения кусков кода из одного файла в другой или их размножение путем копирования в рамках одного файла. То есть, увидеть, что какой-то кусок кода был взят из другого проекта, и потом немного исправлен. Я понимаю, несколько утопично, особенно если представить, что for копируется везде где только можно, с легкими изменениями в рамках одной строки :D.

Но увы моя мечта не сбылась, все что удалось добиться сейчас от Git, так это то, что Git может показать, что файл с такой-то вероятностью является копией другого файла, так как его после копирования изменили до неузнаваемости. Да и то для этого надо передать серию волшебных ключиков.
git diff --find-copies-harder --pickaxe-all --color HEAD~2
diff --git a/6.txt b/10.txt
similarity index 80%
copy from 6.txt
copy to 10.txt
index f8e89fb..cf9ebe7 100644
--- a/6.txt
+++ b/10.txt
@@ -1,3 +1,4 @@
+888
 111
 222
 333
@@ -5,4 +6,3 @@
 555
 666
 777
-888
diff --git a/7.txt b/7.txt
new file mode 100644
index 0000000..1bfd9c2
--- /dev/null
+++ b/7.txt
@@ -0,0 +1,5 @@
+111
+222
+333
+444
+
diff --git a/8.txt b/8.txt
new file mode 100644
index 0000000..92263e5
--- /dev/null
+++ b/8.txt
@@ -0,0 +1,5 @@
+444
+555
+666
+777
+888
diff --git a/6.txt b/9.txt
similarity index 80%
copy from 6.txt
copy to 9.txt
index f8e89fb..cf9ebe7 100644
--- a/6.txt
+++ b/9.txt
@@ -1,3 +1,4 @@
+888
 111
 222
 333
@@ -5,4 +6,3 @@
 555
 666
 777
-888

Это максимум что удалось добиться. Кстати, чтобы git легко находил копии файлов рекомендуется на каждый чих делать фиксацию изменений, иначе копию можно изменить до не узнаваемости :D на момент фиксации.

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

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

В последних, хотелось бы обратить внимание на то, что Mercurial больше подходит для не больших проектов, к тому же он в самом деле проще в освоении, чем Git в котором только для того, чтобы научиться просмотреть изменения, мне понадобилось перечитать кучу документации и потратить уйму времени, не менее часа. Но Git предоставляет достаточно много опций и утилит облегчающих контроль большого проекта.

Например, способ с помощью которого легко найти проблемный commit, который испортил сборку всего проекта не проверяя каждый commit в отделььности, а лишь только сообщая какой из тысячи commit-ов после теста оказался проблемным или не проблемным. Не простая задача, и таких мелочей в Git много.

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