Как создать правильный патч при удалении функции и ее докблока с помощью git

Когда у вас есть докблоки над несколькими функциями, удаление функции создает не оптимальный патч.

index.js:

/**
 * Function foo description.
 */
function foo() {}

/**
 * Function bar description.
 */
function bar() {}

Функция удаления foo с его docblock генерирует следующий патч:

diff --git a/index.js b/index.js
index f4e18ef..933004f 100644
--- a/index.js
+++ b/index.js
@@ -1,9 +1,4 @@
 /**
- * Function foo description.
- */
-function foo() {}
-
-/**
  * Function bar description.
  */
 function bar() {}

Это означает, что любое слияние, которое приносит с собой, совершает то, что касается пространства между функцией foo и панель функций, теперь приводит к конфликту. Например, представьте, что мы создали ветвь feature-1 перед удалением foo, а в index.js добавлена ​​функция foobar между ними. Контекст выглядел бы следующим образом:

/**
<<<<<<< HEAD
=======
 * Function foo description.
 */
function foo() {}

/**
 * Function foobar description.
 */
function foobar() {}

/**
>>>>>>> feature-1
 * Function bar description.
 */
function bar() {}

Я полагаю, что не было бы проблем, если бы /** был захвачен сверху. Я уверен, что есть хорошая причина для git предпочесть удаление с конца, но я хотел бы заставить его захватить его с самого начала. Есть ли способ легко сделать это? Или вручную редактирование патчей?

Ответ 1

Это далеко не идеально, но новый --compaction-heuristic в Git 2.9 часто делает то, что вы хотите. Подробнее см. этот пост в блоге. Вы можете настроить его по умолчанию, но, учитывая, что это иногда ухудшает ситуацию, я этого не делал:

git config --global diff.compactionHeuristic true

Ваша версия Git должна быть не менее 2.9, чтобы это имело какой-либо эффект.

Один из недостатков текущей реализации заключается в том, что она буквально требует пустой строки над модифицированным разделом. Недостаточно начинать в верхней части файла. Например, предположим, что мы начинаем с:

block:
This file has
three blocks.

block:
There is a blank line
between each.

block:
This is the third
block.

Если мы удалим средний блок, по умолчанию diff сохранит вторую строку block: и удалит третью строку block:. Включение уплотнения перемещает diff-hunk вверх до тех пор, пока он не достигнет пустой строки над вторым block:, который мы хотим.

К сожалению, если мы удалим первый блок, эвристика уплотнения попытается перенести diff diff, чтобы включить первую строку block:, но сбой, поскольку она попадает в верхнюю часть файла, где над ним нет пустой строки (так как над ним нет линии). Поэтому он оставляет первое слово block: на месте и удаляет второй.

(Исправление этого требует только того, что алгоритм уплотнения представляет собой "виртуальную нуль нуля", которая является пустой. Обратите внимание, что сама проблема никогда не встречается в конце файла, так как по умолчанию diff способствует удалению более поздних строк. уродливое обходное решение состоит в том, чтобы оставить пустую строку в верхней части каждого файла, просто чтобы уплотнение могло ее увидеть.)