Вопрос:

Как запустить средство форматирования кода поверх моего источника без изменения истории git?

git formatting git-filter-branch prettier

448 просмотра

4 ответа

1610 Репутация автора

Я пытаюсь отформатировать весь репо с помощью инструмента форматирования кода. При этом я хочу сохранить информацию о том, кто зафиксировал какую строку, чтобы такие команды, как git blameвсе равно, отображали правильную информацию. Под этим я подразумеваю, что он должен показывать автора, который ранее редактировал каждую строку (до того, как она была отформатирована).

Есть команда git filter-branch, которая позволяет вам запускать команды для каждой ревизии репо, начиная с начала времени.

git filter-branch --tree-filter '\
  npx prettier --write "src/main/web/app/**/**.{js, jsx}" || \
  echo "Error: no JS files found or invalid syntax"' \
  -- --all

Это займет целую вечность, и на самом деле меня не волнует прошлое. Я просто хочу отформатировать основную ветку, не меняя владельца каждой строки. Как я могу это сделать? Я попытался поиграть с rev-listв конце и другими типами фильтров, но это все еще не работает. Должен быть способ отформатировать кодовую базу, сохраняя информацию об авторе для каждой строки.

Автор: aherriot Источник Размещён: 27.11.2018 03:13

Ответы (4)


1 плюс

22651 Репутация автора

Решение

То, что вы пытаетесь сделать, невозможно. Вы не можете в какой-то момент изменить строку кода, и все же получить git-отчет о том, что самое последнее изменение этой строки кода произошло до того момента.

Я полагаю, что инструмент управления исходным кодом мог бы поддержать идею «несущественного изменения», когда вы помечаете коммит как косметический, а затем анализ истории пропускает этот коммит. Я не уверен, как инструмент будет проверять, действительно ли изменение было косметическим, и без какой-либо формы принудительного применения инструмента эта функция наверняка будет использована неправильно, что приведет к появлению ошибок, которые могут быть скрыты в «неважных» фиксациях. Но на самом деле причины, по которым я считаю, что это плохая идея, академичны - суть в том, что у git такой функции нет. (И при этом я не могу думать ни о каком инструменте контроля источника, который делает.)

Вы можете изменить форматирование в будущем. Вы можете сохранить видимость прошлых изменений. Вы можете избежать редактирования истории. Но вы не можете делать все три одновременно, поэтому вам придется решить, какой из них пожертвовать.

Кстати, в переписывании истории есть пара минусов. Вы упомянули время обработки, поэтому давайте сначала посмотрим на это:

Как вы заметили, простой способ сделать это filter-branchбудет очень много времени. Есть вещи, которые вы можете сделать, чтобы ускорить его (например, предоставить виртуальный диск для его рабочего дерева), но это tree-filterи включает в себя обработку каждой версии каждого файла.

Если бы вы сделали некоторую предварительную обработку, вы могли бы быть несколько более эффективными. Например, вы можете предварительно обработать каждый BLOBэлемент в базе данных и создать отображение (где a TREEсодержит BLOBX, замените его на BLOBY), а затем использовать a index-filterдля выполнения подстановок. Это позволит избежать всех операций извлечения и добавления и избежать повторного форматирования одних и тех же файлов кода. Так что это экономит много ввода-вывода. Но это нетривиальная вещь для настройки, и все же может занять много времени.

(Можно написать более специализированный инструмент, основанный на этом же принципе, но AFAIK никто не написал. Существует прецедент, что более специализированные инструменты могут быть быстрее, чем filter-branch...)

Даже если вы найдете решение, которое будет работать достаточно быстро, имейте в виду, что переписывание истории нарушит все ваши ссылки. Как и при любом переписывании истории, всем пользователям репо будет необходимо обновить свои клоны - и для чего-то такого стремительного, я рекомендую сделать это, выбрасывая клонов до того, как вы начнете переписывать, а потом клонировать.

Это также означает, что если у вас есть что-то, что зависит от идентификаторов коммитов, это также будет сломано. (Это может включать в себя сборку инфраструктуры или выпуск документации и т. Д .; в зависимости от практики вашего проекта.)

Таким образом, переписывание истории - довольно радикальное решение. И с другой стороны, также кажется решительным предположить, что форматирование кода невозможно просто потому, что это не было сделано с первого дня. Итак, мой совет:

Сделайте переформатирование в новом коммите. Если вам нужно использовать git blame, и он указывает вам на коммит, в котором произошло переформатирование, затем выполните git blameповторный запуск на родительском коммите переформатирования.

Да, это отстой. Какое-то время. Но данный кусок истории имеет тенденцию становиться менее важным с возрастом, поэтому оттуда вы просто позволяете проблеме постепенно уйти в прошлое.

Автор: Mark Adelsberger Размещён: 27.11.2018 03:56

0 плюса

111318 Репутация автора

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

Одна вещь, которую вы могли бы сделать, это перейти от некоторого более раннего коммита, переформатировать код, а затем перебазировать masterв вашу ветку. Это сохранит авторство для всех изменений, которые произошли после любого коммита, с которого вы начинаете.

Такова идея, но есть несколько серьезных причин, по которым вам не следует это делать:

  1. Перебазирование общей ветки - плохая идея. Тот факт, что вы даже заботитесь о сохранении авторства изменений, вероятно, означает, что есть много людей, активно работающих над кодом. Если вы пойдете и перебазируете основную ветку, то у каждого форка или клона вашего репо будет основная ветка со старой историей, и это неизбежно вызовет путаницу и боль, если вы не будете очень осторожны в управлении процессом и уверенности что все знают о том, что вы делаете, и обновляют свои копии соответствующим образом. Лучшим подходом, вероятно, было бы не перебазировать master, а вместо этого объединять коммиты из master в вашу ветку. Затем пусть все начнут использовать новую ветку вместо master.

  2. Слияние конфликтов. Переформатируя всю кодовую базу, вы, вероятно, собираетесь вносить изменения в большое количество строк почти в каждом файле. Когда вы объединяете последующие коммиты, будь то через rebaseили merge, у вас, вероятно, будет большое количество конфликтов для разрешения. Если вы воспользуетесь подходом, который я предложил выше, и объедините коммиты из master в новую ветку, а не перебазируете, тогда будет легче упорядочить эти конфликты, потому что вы можете объединять несколько коммитов за раз, пока вас не поймают вверх.

  3. Неполное решение. Вам нужно будет выяснить, куда в истории вы хотите вставить свою операцию переформатирования. Чем дальше вы идете назад, тем больше вы сохраняете авторство изменений, но тем больше работы вам потребуется для объединения в последующие изменения. Таким образом, вы, вероятно, все равно будете иметь много кода, в котором ваш коммит переформатирования является последним изменением.

  4. Ограниченная выгода. На самом деле вы никогда не потеряете информацию об авторстве git- просто инструменты обычно показывают, кто внес последние изменения. Но вы все равно можете вернуться к предыдущим коммитам и просмотреть всю историю любого фрагмента кода, включая того, кто его сделал. Таким образом, единственное, что вставляет вашу операцию переформатирования в историю, действительно покупает вас, это удобство просмотра того, кто изменил какой-то фрагмент кода без дополнительного шага возврата к более раннему коммиту.

  5. Это нечестно. Когда вы переписываете историю ветки, вы изменяете фактическую запись того, как код менялся с течением времени, и это может создать реальные проблемы. Давайте представим , что ваше переформатирование не совсем так , как несущественное вы имеете в виду, чтобы это были, и при этом переформатировании вы на самом деле создать ошибку. Скажем, например, что вы вводите дополнительный пробел в многострочную строковую константу. Несколько недель спустя, кто-то наконец замечает проблему и ищет ее причину, и похоже, что изменение было сделано полтора года назад (потому что именно там вы вставили свое переформатирование в историю). Но проблема кажется новой - она ​​не обнаруживается в сборке, поставленной два месяца назад, так что, черт возьми, происходит?

  6. Польза уменьшается со временем. По мере продолжения разработки изменения, которые вы стараетесь не скрывать, в любом случае будут покрыты некоторыми другими изменениями, и ваши переформатированные изменения также будут заменены этими новыми изменениями. С течением времени и развития работа, которую вы делаете, чтобы похоронить ваши переформатированные изменения, не будет иметь большого значения.

Если вы не хотите, чтобы ваше имя отображалось в качестве автора каждой строки в вашем проекте, но вы также не хотите мириться с проблемами, описанными выше, тогда вы можете переосмыслить свой подход. Лучшее решениевозможно, стоит заняться переформатированием как командой: заставить всех членов команды согласиться запускать форматировщик для любого файла, который они изменяют, и сделать надлежащее форматирование обязательным требованием во всех обзорах кода в будущем. Со временем ваша команда охватит большую часть кода, и информация об авторстве будет в основном уместной, поскольку каждый файл, который будет переформатирован, должен был быть изменен в любом случае. В конечном итоге вы можете получить небольшое количество файлов, которые никогда не переформатируются, потому что они очень стабильны и не нуждаются в обновлениях, и вы можете переформатировать их (потому что некоторые плохо отформатированные файлы сводят вас с ума) или нет (потому что в любом случае никто не работает в этих файлах).

Автор: Caleb Размещён: 27.11.2018 06:53

0 плюса

1 Репутация автора

git filter-branch --tree-filter "find

-regex '. *. (cpp \ | h \ | c \ | )' -exec <команда форматирования> {} \;" -- --все

< dir > : directory of related, так как выше необходимо запускать из корневого каталога, но вы можете отформатировать только определенный вспомогательный каталог в корневом каталоге git.

< etc > : другие форматы файлов.

< formatter-command > : команда, которую вы можете запустить для одного файла, и она будет форматировать этот файл.

--all в конце означает сделать это для всех веток git (всего 4 тире)

Например, это то, что у меня есть, где мой git содержит каталог src (кроме тестов, инструментов и т. Д.)

git filter-branch --tree-filter "find src -regex '. *. (cpp \ | h \ | cu \ | inl)' -exec clang-format -style = google -i {} \;" -- --все

Выше будет переписывать каждый коммит git, но не изменять аннотацию git. Так как это изменяет историю мерзавцев, каждый должен будет откинуться, как только это будет выдвинуто.

Автор: Saurabh Ranjan Размещён: 16.05.2019 07:28

0 плюса

6746 Репутация автора

У Mercurial есть (экспериментальная) опция для этого, --skip:

--skip <REV[+]>
    revision to not display (EXPERIMENTAL)

Я думаю, что в git по умолчанию еще нет эквивалента, но есть команда гипер-обвинения, разработанная извне.

По моему опыту, оба не очень хорошо справляются с изменениями форматирования, особенно когда несколько строк объединены в одну.

Автор: Marco Размещён: 12.06.2019 09:18
Вопросы из категории :
32x32