Комментарии 49
Саш, я помню, что раздел про history simplification в мане про git-log был ещё лет 5 назад… Впрочем, может быть, ты прав, что он был только в rev-list.
Я напарывался на похожие проблемы, когда для системы переводов пытался надежно определить последний коммит, в котором менялся файл, и, на удивление, не смог, именно из-за сложностей обработки merge-коммитов, и в итоге на эту идею плюнул :).
Ещё в целом прикольные подводные камни возникают, когда в прямо merge-коммите что-то дополнительно добавляют или убирают, а не просто разрешают конфликты. В таких случаях раньше git show -p
для такого коммита ничего не показывал, а git log <filename>
по-моему не показывает merge-коммиты по умолчанию :).
web.archive.org/web/20200103050848/https://git-scm.com/docs/git-log
В январе этого года (почти год назад) этот раздел уже был. Более старое затрудняюсь посмотреть, вебархив сбоит сильно. Болеет видимо :-(
Намного позже, когда писал статью, решил что не просто не заметил этого куска, а его не было. Конкретно из-за этого коммита: в нем в документацию git-log добавилось
include::rev-list-description.txt[]
а вот
include::rev-list-options.txt[]
уже там было (похоже где-то лет 10 как). Простите, немного человеческой невнимательности :)
Искренне считаю, что самый крутой вариант — это когда в merge добавляют что-нибудь, даже если никакого конфликта не было :)
Спасибо за интересную историю.
О, это может никак не помочь отвлечь мозг от недоисследованной проблемы. Такие цепляют и хочется понять "да как оно так то?! и как избежать/починить в будущем?"(иногда добавляется "так, а как оно раньше то работать вообще умудрялось!?").
И порой проще действительно вот как тут закопаться и докопаться — и пойти дальше по таскам.
Вообще, находить причину проблемы обычно помогает ее исправить и не допустить в будущем, что обычно хорошо, как минимум для компании.
Обычно да, но иногда это вступает в противоречие с сиюминутными приоритетами. Например при дедлайне перед выставкой какой или выпуском версии. И вот тут нежелание мозга отпустить на время проблему может мешать.
В таком случае, после окончания события все равно лучше разобраться, что произошло. Конечно, ситуации бывают разные и этот подход не всегда оправдан, но, как мне кажется, для важных вещей вроде системы релиза это как раз хороший подход, и если у вас "нет времени" на это, то, кажется, дальше таких проблем будет становиться только больше.
c merge-ами хотя бы можно разобраться что к чему было, кто, когда и зачем
Как раз таки при merge такие проблемы чаще всего и остаются незаметными, т.к. большая пачка изменений conflict resolution идёт в итоговый merge commit. При rebase удаление кода из мастера было бы частью непосредственно коммита, который добавляет новую версию кода — и сразу привлекало бы внимание как при ревью кода, так и при просмотре истории.
А вообще лучше всего использовать rebase и merge одновременно (с пустыми merge commit), и получать преимущества обоих вариантов!
(del)
Понять не могу: как получится этот коммит afea493a?
Если я мержу changekiller в master, то появляется конфликт и 2 варианта:
- решаем конфликт в пользу changekiller — мерж-коммит не пустой (видно изменение)
- решаем конфликт в пользу master — мерж-коммит пустой, но и в master ожидаемое 3, а не 4
Буду признателен если кто-нибудь распишет последовательность действий.
Причём я тоже натыкался на подобное. Происходит от непонимания работы git со стороны разработчика. Если я правильно понял, то механизм примерно такой:
- Разработчик ответвляется от master в feature ветку. Пока всё ОК.
- Фигачит код, коммитит, пушит к себе в ветку. Пока всё почти ОК, кроме того, что если приходится атомарные изменения делать несколько дней, то это "симптомчик" про сложность кода.
- master (логично) убегает вперёд. Разработчик подмёрживает к себе изменения master. А там конфликт, чтобы не греть голову чувак оставил только свои изменения. Вот это и есть основная засада (ниже перечислю что не так).
- Потом еще что-то коммитит в свою ветку.
- Потом замержил с master (уже как будто "без конфликтов").
Что не так:
- Неаккуратный мерж к себе.
- По хорошему всю ветку надо либо аккуратно ребейзить в хвост мастера, либо делать squash своих изменений в один коммит (если он атомарен). Ключевое слово "аккуратно". Заодно история станет прозрачнее.
- В гите в истории нет понятия "коммит был в такой-то ветке". Обе сливающиеся ветки (или все N веток) равноправны. И поэтому делая мерж от master к себе каждый разработчик отвечает за этот мержевый коммит. Поэтому публикуя пулл/мерж реквест разработчик отвечает за каждый коммит, добавляемый в основной граф. В том числе и за такие "технические" мержи. Поэтому пулл/мерж реквест должен по-хорошему содержать коммиты от максимально свежего, не содержать лишних ветвлений и мержей — это позволит сильно экономить мыслетопливо при чтении истории.
Какой еще rebase после push?
Там проблема в том, что кто-то мог от неё уже отрезать свою ветку, для работ требующих этих изменений.
Вопрос можно? А не является ли эта история следствием каких-то организационных проблем?
Предположу, что странным может показаться что разработчик просто выкинул чужие изменения, но и конфликт там был в очень большом количестве файлов — в ветке делали рефакторинг системы, насколько я понял.
Что разработчик сделал merge, a не pull/merge request, который, если не ошибаюсь, был бы отклонен как раз из-за конфликта. А дальше, см. stackoverflow.
Тогда скорее можно попробовать упрекнуть процесс/инструмент ревью кода. Или там не было видно изменений (и тогда это проблема инструмента) или изменения просто не заметили или пропустили (и тогда это проблема разработчика/процесса). К сожалению, у нас именно последний вариант (не заметили — изменений было банально слишком много).
В целом тут можно пофилосовствовать дальше: не стоило делать такие большие изменения в одной ветке, например. Это правда, но этого может быть тяжело добиться и тяжело заставить людей следовать такому правилу.
В вашем тестовом репозитории я этого не вижу. Ветка changekiller мержится в master.
Немного напоминает совет не пользоваться многократным undo и redo в редакторе кода, когда результат может не всегда совпадать с исходным.
Уважаемый автор, я скачал ваш репозиторий, посмотрел на него PyCharm'ом и, да, в Log'е не не сразу очевидно, что произошло (надо всматриваться), а вот если попросить Git history файла test.php, то все видно мгновенно — то, что вы при разрешении merge conflict не приняли изменений в changekiller, в отличие от ситуации, описанной в статье.
P.S. И там еще много лишнего видно типа ветки interesting_changes — удалить надо?
P.s. Лишнюю ветку удалил, спасибо!
Интересная проблема
Мне кажется, решение, когда программист не может напрямую мержить в мастер, позволяет избежать такой проблемы. По крайней мере, если мерж-реквесты обрабатывает грамотный человек. В этом случае в коммите хотя бы будет нужная информация
См. тестовый репозиторий и мою дискуссию с автором статьи выше. Т.е. в конце концов. таки (другой) программист, который делал рефакторинг, смержил свою ветку обратно в мастер. Иначе, как бы еще могли потеряться исправления в master'е?
Ну, судя по статье и тестовому репозиторию первого мержа из мастера в ветку не было… Лишь в процессе обсуждения выяснилось, что автор посчитал его несущественным для объяснения ситуации.
И да, я проверил, что если в ветке файл правится, потом мерж из мастера с конфликтом, криво разрешенным в свою пользу, то последующий мерж из ветки в мастер — уже без формального конфликта, но приводящий к regresson ошибке.
Как причину ошибки искать, это уже второй вопрос (с простым ответом, или консольные команды лучше знать, или GUI пользоваться), а вот как поймать и не допустить? Только если тестами, так ведь и их можно в ветке кривым мержем "откатить".
История потерянного коммита