Как запустить средство форматирования кода поверх моего источника без изменения истории git? - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь отформатировать весь репо с помощью инструмента форматирования кода.При этом я хочу сохранить информацию о том, кто зафиксировал какую строку, чтобы такие команды, как 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 в конце и другими типами фильтров, но он все еще не работает.Должен быть способ отформатировать кодовую базу, сохраняя информацию об авторе для каждой строки.

Ответы [ 4 ]

0 голосов
/ 13 июня 2019

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

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

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

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

0 голосов
/ 27 ноября 2018

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

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

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

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

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

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

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

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

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

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

0 голосов
/ 16 мая 2019

git filter-branch --tree-filter "find

< dir >: каталог, о котором идет речь, так как выше необходимо запустить из корневого каталога, но вы можете отформатировать только определенный вспомогательный каталог в корневом каталоге 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 {} \;"- --all

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

0 голосов
/ 27 ноября 2018

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

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

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

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

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

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

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

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

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

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

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

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

...