Работа с кусочками, которые только меняют пробелы - PullRequest
3 голосов
/ 12 января 2020

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

diff --git a/knuth.tex b/knuth.tex
index 2f6a2f8..7b0827d 100644
--- a/knuth.tex
+++ b/knuth.tex
@@ -1,6 +1,6 @@
 Thus, I came to the conclusion that the designer of a new
 system must not only be the implementer and first
-large||scale user; the designer should also write the first
+large-scale user; the designer should also write the first
 user manual.

 The separation of any of these four components would have
@@ -9,8 +9,7 @@ all these activities, literally hundreds of improvements
 would never have been made, because I would never have
 thought of them or perceived why they were important.

-But a system cannot be successful if it is too strongly
-influenced by a single person. Once the initial design is
-complete and fairly robust, the real test begins as people
-with many different viewpoints undertake their own
-experiments.
+But a system cannot be successful if it is too strongly influenced by
+a single person. Once the initial design is complete and fairly
+robust, the real test begins as people with many different viewpoints
+undertake their own experiments.

Как вы можете видеть, первый ханк внес реальное изменение, заменив || на -, тогда как второй ханк не меняет ничего, кроме разрыва строки и пробела. Фактически, word-diff второго блока будет пустым.

Можно ли установить политику (например, на GitHub или в моем CI) для отклонения коммитов, содержащих такие «пустые» блоки, или переформатировать патч, чтобы полностью исключить эти фрагменты, чтобы я мог git apply обойтись без них?

Связанный: Как git -применить git слово diff

1 Ответ

3 голосов
/ 21 января 2020

Если вы ищете встроенное решение, я не знаю ни одного. Однако это не означает, что это не может быть относительно легко встроено в систему CI.

Вы можете перенаправить вывод соответствующей команды git diff в скрипт, подобный следующему, который будет выходить из 1, если кормил патч, содержащий кусок, как второй выше.

#!/usr/bin/env ruby

def filter(arr)
  arr.join.split("\n\n").map { |x| x.gsub(/\s+/, ' ') }.join("\n\n")
end

def should_reject(before, after)
  return false if before.empty? && after.empty?
  before = filter(before)
  after = filter(after)
  return true if before == after
  false
end

chunk = nil
before = []
after = []
while (line = gets)
  trimmed = line[1..-1]
  case line
  when /^(\+\+\+|---)/
    # Do nothing.
  when /^@@ /
    if should_reject(before, after)
      warn "Useless change to hunk #{chunk}"
      exit 1
    end
    chunk = line
    before = []
    after = []
  when /^ /
    before << trimmed
    after << trimmed
  when /^\+/
    after << trimmed
  when /^-/
    before << trimmed
  end
end

if should_reject(before, after)
  warn "Useless change to hunk #{chunk}"
  exit 1
end

Он по существу разбивает каждый кусок на куски с пустой строкой между ними, превращает все пробелы в пробелы, а затем сравнивает их. Если они равны, он жалуется и выходит ненулевой. Вы можете sh изменить его, чтобы сделать его более надежным, например, иметь дело с окончаниями CRLF или чем-то подобным, но этот подход жизнеспособен.

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

...