Давайте снова поговорим про системы версионирования. Записал в нашей вики 3 мифа о Git.
Myth 1 — Git magically supports moves, renames, copies and everything will be just fine - Igor Sereda
Myth 2 — git mv will take care of everything (that relates to renames/moves) - Igor Sereda
Myth 3 — Git is consistent in how it handles change history - Igor Sereda
Ну и в качестве обеспечения работы Git в режиме “летописи” (спасибо @9000 за меткий термин), пробую внедрить методику “separate commit for renames”. Отдельный коммит - только переименования и копирования, без каких-либо изменений, отдельный коммит c остальными изменениями. - Igor Sereda
(Это, конечно, ужасно неудобно, я аж фичу запостил для IDEA - https://youtrack.jetbrains.com/issue... - там же подробная мотивация.) - Igor Sereda
Кто-нибудь вообще так делает? И какие еще есть мифы о Git? - Igor Sereda
разделять содержательные и несодержательные изменения кода по коммитам -- это, как мне до сих пор казалось, достаточно очевидная гигиеническая практика - Evelynne
@mlivshin не очень понятно, что именно очевидно; у меня за пару часов рефакторинга может накопиться много изменений, в т.ч. переименований и переносов файлов; все эти изменения содержательны в равной мере - Igor Sereda
эээ, ну понятно что в реальной жизни всё сложнее :) - Evelynne
ну окей, это мифы — а реальность-то какова? - псы в рапиде
define "magically", "just fine", "take care of everything", "consistent", "handles" :) - псы в рапиде
В любой системе контроля версий люблю комитить отдельно любое маленькое изменение. Но не все команды это любят. Тогда приходится приспосабливаться. - Джуник
@junique тут проблема в том, что даже самое маленькое изменение - например, переименование класса, чтобы исправить в имени опечатку - приходится делать в *два* коммита, если хочется 100% сохранения истории - Igor Sereda
@squadette Реальность такова, что например параллельные rename и edit могут смержиться, а могут и не смержиться. Что касается определений, мифы написаны поэтическим языком и в определениях не нуждаются ;) , но я немного более подробно расписал проблему в фичареквесте для Идеи, ссылка выше. Если я что-то упускаю, или есть более простой способ решить проблему - буду рад разоблачениям, так как собираюсь внедрять двойной коммит в команде. - Igor Sereda
я сразу скажу, что двойной коммит "сработает" только если смотреть на диффы между соседними коммитами. если сделать дифф между двумя коммитами, между которыми есть rename-commit, то Git опять "забудет" историю. на самом деле он ее никогда и не помнил. реально в гите просто каждый раз срабатывает rename detection между любыми двумя коммитами. - псы в рапиде
Linus, конечно же, считает что это фича — типа это позволяет сделать генерилку диффов сколь угодно интеллектуальной. Вопрос в том что никто ее пока не сделал — но если есть "заказ", то ничто не мешает заняться этим вопросом. - псы в рапиде
Мне кажется, что изложенный кейс — "переименовали и потом поменяли 99 строк, и при этом гит не определил что сотая строка — из первого файла" — этот кейс безумен, и я не ожидал бы такого поведения. если мы готовы идти по этой дорожке — то давайте тогда включать в редакторе трекинг cut-and-paste, чтобы понимать, что вот этот код переехал из одного класса в другой с исправлениями. - псы в рапиде
Собственно, FAQ: https://git.wiki.kernel.org/index... в котором есть ссылка на письмо Линуса. он умный человек, к нему стоит прислушаться. - псы в рапиде
Ага... если это так (rename detection не рекурсивный), тогда конечно это все не имеет смысла. Спасибо, надо проверить. Изложенный кейс конечно не жизненный, но демонстрирует inconsistency. Жизненных кейсов я уже набрал прилично за сравнительно недолгий срок работы с гитом, все они начинаются с момента wtf did just happen и дальше идет раскапывание, ну или потерянная история, когда мне blame на четырехлетний код выдает что это свежак от Васи недельной давности. - Igor Sereda
К слову, blame очень важная вещь - не для обвинений, разумеется, а чтобы понять контекст "откуда взялась эта строчка, что было в коммит логе, и какие еще там были изменения" - Igor Sereda
Может тебе будет лучше с hg? - зона пингвинов
Линус умный человек безусловно и прислушаться стоит. Но воспринимать как догму все что он говорит я не готов. Надо еще раз перечитать, но по-моему, вполне очевидно, что информация теряется. Возможно, Линус не считает эту информацию важной, а я считаю. - Igor Sereda
^^ а что hg, у него нет таких проблем? В любом случае, tooling не сравнить и мы плотно сели на stash - Igor Sereda
от git blame надо читать документацию. чтобы он например не обращал внимания на whitespace, а также чтобы он тоже обрабатывал moved and copied lines. - псы в рапиде
эх, я хотел добавить "конечно это не означает, что Линус безусловно и всегда прав во всем", но подумал что это типа очевидно. но нет! все же этот disclaimer нужен. а потом люди над юристами смеются. :( - псы в рапиде
также на всякий случай хочу напомнить про команды git diff -B, -M, -C, --find-copies-harder - псы в рапиде
^^ ну, ведь так же очевидно, что Линус умный, и к нему стоит прислушаться :) - Igor Sereda
^^ да, спасибо, про опции эти в курсе, но они а) не находят существенно измененные копии, harder or not harder (ну или находят ерунду если указать -M05, например), б) не решают вопрос системно, так как их надо не забывать указывать каждому участнику процесса, и возможны вариации - один так указал, другой эдак - Igor Sereda
Если про blame то читать вот http://jfire.io/blog... - голос в темноте
Разве (в Git'е) renames / moves обнаружение работает на разном sha1 контента? Насколько мне известно - нет - Maxim
не понимаю этот вопрос. а зачем нужно обнаружение renames/moves, если sha1 не поменялся? :) конечно работает. - псы в рапиде
по мне так с гитом everything will be just fine. нет такой жопы, из которой нельзя выбраться. с svn и tfs периодически код просирался и все, ничего не сделаешь - urquan
Вот да, в случае git потерять ничего практически нельзя, но иногда можно оказаться в положении, когда не-потерявшееся внезапно расположено чёрт знает где, и гадать, как оно туда попало. Часто такие случаи можно предупредить грубой силой, сказав -X ours, но не всегда. - 9000
@9000 смотря как определить "потерять"; получить такое состояние, когда основная ветка вдруг *незаметно* оказывается без изменений, которые вносил один из разработчиков - done; потерять историю изменений конкретного кода из-за переименований - done уже много раз - Igor Sereda
@berkus спасибо за ссылку на статью, но она нисколько не помогает, если blame -M/-C не сможет найти rename, потому что файл существенно поменялся (ключевое слово "существенно", что не является предсказуемой характеристикой с точки зрения программиста, меняющего код) - Igor Sereda
@urquan хочется минимизировать вероятность жопы, путем ее четкого обозначения и придумывания формализуемых привычек, позволяющих ее избегать - Igor Sereda
@squadette Вот черт, все куда больше запущено, чем я думал! Действительно, если у нас есть коммиты a--b--c, и мы делаем diff a c, git вообще не смотрит на b. Ну ладно, c diff понятно, но то же самое происходит и при merge - хотя при 3-way merge есть четкие пути изменений. "With the strategies that use 3-way merge (including the default, recursive), if a change is made on both branches, but later reverted on one of the branches, that change will be present in the merged result; some people find this behavior confusing. It occurs because only the heads and the merge base are considered when performing a merge, not the individual commits." - Igor Sereda
Ну вот же ж шит. То есть double commit не поможет с merge никак :( При этом blame ведет себя лучше - показывает историю строчек и до переименований. - Igor Sereda
ух ты! а вот про это я не знал. Надо подумать об этом. - псы в рапиде
Я бы кстати предложил попробовать вместо стандартных мерджей сделать rebase. По дороге может получиться конфликт, но конфликтов бояться не надо. А история будет более понятной (потому что линейной). - псы в рапиде
да, в этом свете rebase приобретает новый смысл... но Stash не поддерживает всасывание pull request'ов через rebase - Igor Sereda
О, придумал - при мерже из A в B надо перебирать все коммиты от merge-base(A,B) до A, и последовательно накатывать их патчи (черрипикать?) на рабочий каталог, а потом закоммитить это как merge commit. И таки это будет то, как работает svn. >:-\ - Igor Sereda
Ну а какая разница? Один pull request можно и сырым гитом обработать. Я не верю что у вас в абсолютно всех пулл-реквестах встречается эта проблема. - псы в рапиде
ну или пусть хозяин pull-реквеста сделает rebase относительно свежего мастера, и перепошлет его, и результат уже мерджить. - псы в рапиде
тогда это и будет фактически "при мерже из A в B надо перебирать все коммиты от merge-base(A,B) до A, и последовательно накатывать их патчи (черрипикать?) на рабочий каталог, а потом закоммитить это как merge commit." - псы в рапиде
P.S.: а, я понял логику про "if a change is made on both branches, but later reverted on one of the branches". интересно! - псы в рапиде