Запустите git-clang-format для серии коммитов git

Я написал серию коммитов git с ужасным форматированием кода.
Прежде чем отправить их на github, я хочу запускать git-clang-format для каждого коммита, чтобы получить хорошо отформатированный код в моей истории.

Есть ли какая-то комбинация rebase и git-clang-format, которая позволит это сделать?


person Chris Jefferson    schedule 15.05.2017    source источник


Ответы (3)


Это похоже на работу для git filter-branch, который может переписать нужные вам коммиты. Поскольку эти коммиты еще не отправлены, изменение их содержимого (и, следовательно, их SHA1) не имеет большого значения.
И эффект аналогичен тому, что может сделать перебазирование или выбор вишни, за исключением того, что вы можете запустить любую команду для каждый коммит воспроизводится.

Вы можете запустить filter-branch для нескольких последних коммитов:

См. "Переформатирование кодовой базы с помощью git filter-branch< /a>", автор Эллиот Чанс

git filter-branch --tree-filter 'git-clang-format' -- <SHA1>..HEAD

Учитывая git-clang-formatсинтаксис, вы можете применить его только к измененным файлам в каждом коммите.
Например, для .cpp файлов:

git filter-branch --tree-filter 'git-clang-format $(\
  git diff-index --diff-filter=AM --name-only $GIT_COMMIT |\
    grep .cpp)' -- <SHA1>..HEAD

Обновление 2017, с Git 2.14.x/2.15 (Q4 2017) у вас есть иллюстрация:

См. коммит 2118805, коммит 6134de6 (14 августа 2017 г.), автор Брэндон Уильямс (mbrandonw) .
(Объединено Хунио С. Хамано -- gitster -- в commit a36f631, 25 сентября 2017 г.)

Makefile: добавить правило сборки стиля

Добавьте правило сборки "style", которое будет запускать git-clang-format при разнице между HEAD и текущим рабочим деревом.
Результатом будет разница предлагаемых изменений.

.PHONY: style
style:
    git clang-format --style file --diff --extensions c,h
person VonC    schedule 15.07.2017

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

Шаги начинаются с последней фиксации. Если вы начнете с HEAD~#, то изменения почти никогда не произойдут, если только они не будут атомарными и несвязанными. git clang-format изменяет только код, который вы изменили (и связанные с ним блоки кода), но не другой нетронутый код.

  1. git clang-format HEAD~1: результатом будут измененные файлы. Скомпилируйте и проверьте.
  2. git зафиксирует эти новые файлы как временную фиксацию.
  3. git rebase -i HEAD~2
  4. Измените новый коммит на «исправление» и завершите перебазирование.

(вы можете сделать это вручную в командной строке, но я почему-то все еще делаю это с редактированием).

Затем вы повторяете шаги для HEAD~2, HEAD~3, пока не закончите свой путь до цепочки.

Некоторые примечания по этому поводу. clang-format будет изменять один и тот же код снова и снова в определенных случаях. Это стало намного реже, но иногда приходится их игнорировать.

person TML Winston    schedule 21.12.2018
comment
вместо того, чтобы создавать новую фиксацию, а затем сжимать ее, вы также можете обновить HEAD напрямую, используя --amend. - person psykid; 07.12.2020

Если вы хотите применить clang-формат только к измененным строкам в каждом коммите, сделайте следующее:

# The first commit you want to edit.
# You can use the following command if it’s a child of origin/master.
export FIRST_COMMIT=$(git rev-list --ancestry-path origin/master..HEAD | tail -n 1)

git filter-branch --tree-filter 'git-clang-format $FIRST_COMMIT^' -- $FIRST_COMMIT..HEAD

Это сделает следующее для каждого коммита:

  1. проверить фиксацию, как это было в исходной истории
  2. вычислить разницу с родителем FIRST_COMMIT (например, origin/master). (ПРИМЕЧАНИЕ. Если вам нужно было вычислить разницу только с текущим родительским коммитом, вы можете отменить изменения в формате clang, сделанные для других коммитов!)
  3. clang-форматировать затронутые строки
  4. создать копию коммита поверх предыдущего
person rumpel    schedule 22.08.2019