Я думаю, что корень проблемы в том, что git (и управление версиями в целом) заставляет вас думать с точки зрения последовательности изменений, но набор изменений или ветвь функций или как вы называете сплоченную группу связанных изменений в целом не логически последовательный. Порядок, в котором был написан код, является второстепенным и не обязательно связан с порядком, в котором он должен быть прочитан.
У меня нет решения, но я написал Perl-скрипт , чтобы помочь автоматизировать процесс переписывания истории. Он похож на скрипт Python @MikaEloranta, который я не видел, когда писал его.
commit --fixup
и rebase --autosquash
великолепны, но их недостаточно. Когда у меня есть последовательность коммитов A-B-C
, и я записываю еще несколько изменений в мое рабочее дерево, которые принадлежат одному или нескольким из этих существующих коммитов, я должен вручную просмотреть историю, решить, какие изменения принадлежат тем или иным коммитам, подготовить их и создайте коммиты fixup!
. Но у git уже есть доступ к информации, достаточной для того, чтобы сделать все это за меня.
Для каждого блока в git diff
скрипт использует git blame
, чтобы найти коммит, который последним коснулся соответствующих строк, и вызывает git commit --fixup
, чтобы написать соответствующие fixup!
коммиты, по сути, делая то же самое, что я делал вручную до этого.
Если сценарий не может разрешить ханк в однозначном коммите, он сообщит о нем как о неудачном ханке, и вам придется прибегнуть к ручному подходу для этого. Если вы дважды изменили строку в двух отдельных фиксациях, сценарий разрешит изменение в этой строке до самой последней из этих фиксаций, что не всегда может быть правильным разрешением. ИМХО в ветке функций «нормальной формы» вы не должны менять строку дважды в двух разных коммитах, каждый коммит должен представлять окончательную версию строк, к которой он прикасается, чтобы помочь рецензенту (-ам). Тем не менее, это может произойти в ветке с исправлениями ошибок, например, если строка foo(bar());
может быть затронута коммитом A (переименовать foo
в fox
) и коммитом B (переименовать bar
в baz
).
Если вы найдете скрипт полезным, пожалуйста, не стесняйтесь улучшать его и повторять его, и, возможно, однажды мы получим такую функцию в git
. Я хотел бы увидеть инструмент, который может понять, как конфликт слияния должен быть разрешен, когда он был введен с помощью интерактивной перебазировки.