Намагаються виправити закінчення рядків за допомогою git filter-branch, але не пощастивши


270

Мене покусав випускний рядок Windows / Linux з git. За допомогою GitHub, MSysGit та інших джерел, здається, найкращим рішенням є встановлення локальних репостів для використання закінчень рядків у стилі Linux, але встановлених core.autocrlfна true. На жаль, я цього не робив досить рано, тому тепер кожного разу, коли я перетягую зміни, закінчуються лінії закінчень.

Я думав, що знайшов відповідь тут, але не можу змусити мене працювати. Мої знання в командному рядку Linux в кращому випадку обмежені, тому я навіть не впевнений, що робить у його сценарії рядок "xargs fromdos". Я продовжую отримувати повідомлення про відсутність такого файлу чи каталогу, і коли мені вдається вказати його на існуючий каталог, він говорить мені, що у мене немає дозволів.

Я спробував це з MSysGit в Windows та через термінал Mac OS X.


Я не можу підтвердити цю тему навіть майже достатньо. +1 ++ - це найкраща відповідь з цього питання.
sjas

Погодьтеся з Чарльзом. Однак у моєму випадку (за допомогою Mac OS X 10.8)> git config core.autocrlf помилково працював, а не> git config core.autocrlf input
user1045085

Відповіді:


187

Документація git для gitattributes тепер документує інший підхід для "виправлення" або нормалізації всіх закінчень рядків у вашому проекті. Ось суть цього:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

Якщо будь-які файли, які не слід нормалізувати, відображаються у статусі git, скасуйте їх атрибут тексту перед запуском git add -u.

manual.pdf -text

І навпаки, текстові файли, які git не визначає, можуть нормалізувати функцію вручну.

weirdchars.txt text

Це використовує новий --renormalizeпрапор, доданий у git v2.16.0, випущеному січні 2018 року. Для старих версій git є ще кілька кроків:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

1
Скажіть git reset, будь ласка, яка мета цього , будь ласка?
crdx

1
змушує git відновити індекс, під час якого він сканує кожен файл, щоб здогадатися, чи є його бінарним. Rm видаляє старий індекс, скидання будує новий індекс.
Русс Еган

16
Дякую, це працювало для мене. Корисна команда після запуску git status- запустити git diff --ignore-space-at-eolпросто, щоб переконатися, що єдині зміни, які ви здійснюєте, - це закінчення рядків.
zelanix

1
Примітка. Єдина "реальна" різниця між цим та "старим" рішенням є в наявності .gitattributes (з відповідним вмістом). Без цього не git resetбуде виявлено жодних модифікацій і, таким чином, марно.
Роб

3
Інструкції по gitattributes сторінки були оновлені , щоб скористатися --renormalizeпрапором доданого в мерзотникові v2.16.0 , який був випущений в січні 2018 року --renormalizeпрапор консолідує процес повторних обробки закінчень рядків для кожного гусеничного файлу в одну команду: git add --renormalize ..
Майк Гілл

389

Найпростіший спосіб це виправити - це зробити один фіксатор, який фіксує всі закінчення рядка. Якщо припустити, що у вас немає модифікованих файлів, ви можете зробити це наступним чином.

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .

7
PS Я рекомендував ваші виправлення хлопцям на github.com, і вони оновили посібник з довідки, щоб використовувати ваше рішення (раніше він тільки що рекомендував свіжий клон і жорсткий перезавантаження, який, схоже, не отримував усі файли.) Help.github. com / deal-with-lineendings
Брайан

31
Дякую ... це чудове виправлення. Знайшли його на GitHub.
ФЛАК

4
Ви також можете перевірити config.safecrlf, щоб переконатися, що ви не змінюєте crlfs у нетекстових файлах (таких як двійкові). Перевірте це в документах kernel.org/pub/software/scm/git/docs/git-config.html .
vrish88

4
@ vrish88: Однак, якщо ви потрапили в цю ситуацію, ви, ймовірно, страждаєте від змішаних підкладкових закінчень і core.safecrlf, можливо, фактично заважаєте вам робити те, що вам потрібно зробити. Напевно, простіше не використовувати safecrlf. git не часто виявляє помилкове виявлення бінарних файлів, і, якщо це відбувається, ви можете вручну позначити його як бінарний.
CB Bailey

26
Нове рішення, яке рекомендується у відповіді Русса Егана нижче, є простішим і не передбачає страшних речей, як видалення всього вашого вихідного коду , тому я б дуже рекомендував людям користуватися цим, хоча це старе рішення має в 10 разів більше голосів!
Porculus

11

Моя процедура поводження з закінченнями рядків така (битва перевірена на багатьох репостах):

Під час створення нового репо:

  • поставити .gitattributesв першому фіксації разом з іншими типовими файлами як .gitignoreіREADME.md

У роботі з існуючим репо:

  • Створіть / змініть .gitattributesвідповідно
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n( --no-verifyце пропустити гачки, які попередньо здійснюють)
    • Доводиться це робити досить часто, щоб я визначив це псевдонімом alias fixCRLF="..."
  • повторити попередню команду
    • так, це вуду, але, як правило, я повинен виконувати команду двічі, перший раз вона нормалізує деякі файли, вдруге навіть більше файлів. Як правило, найкраще це повторити, поки не буде створено нове зобов’язання :)
  • кілька разів переходити між старою (безпосередньо перед нормалізацією) та новою гілкою. Після перемикання гілки інколи git знайде ще більше файлів, які потрібно перенормувати!

В .gitattributesя заявляю, що всі текстові файли явно мають LF EOL, оскільки інструменти для Windows зазвичай сумісні з LF, тоді як інструменти, що не належать до Windows, не сумісні з CRLF (навіть багато інструментів командного рядка nodejs передбачають LF і, отже, можуть змінювати EOL у ваших файлах).

Зміст .gitattributes

Моє .gitattributesзазвичай виглядає так:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

Щоб зрозуміти, які чіткі розширення відстежуються git у поточному репо, дивіться тут

Випуски після нормалізації

Як тільки це зроблено, є ще один загальний застереження.

Скажіть, ваш masterуже оновлений і нормалізований, і тоді ви оформляєте замовлення outdated-branch. Досить часто відразу після перевірки цієї гілки git позначає багато файлів як змінені.

Рішення полягає в тому, щоб зробити фальшивий фіксатор ( git add -A . && git commit -m 'fake commit') і потім git rebase master. Після перезавантаження, фальшива фіксація повинна піти.


1
Я думав, що я зійшов з розуму, поки не прочитав твій пост, бо мені довелося кілька разів виконувати вказану послідовність команд. Вуду! ;)
Шон Фаусетт

Для версії git 2.7.0.windows.1я використав наступне: git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
Шон Фаусетт

4
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Пояснення:

  • git status --short

    Тут відображається кожен рядок, який git є і про який не відомо. Файли, які не знаходяться під контролем git, позначаються на початку рядка знаком "?". Файли, які модифікуються, позначені знаком "M."

  • grep "^ *M"

    Це фільтрує лише ті файли, які були змінені.

  • awk '{print $2}'

    Це показує лише ім'я файлу без маркерів.

  • xargs fromdos

    Це забирає назви файлів з попередньої команди і запускає їх через утиліту 'fromdos' для перетворення закінчень рядків.


Це круто. Дякую. Для тих, хто шукає рішення dos2unixзамість використання Homebrew fromdos.
Альмір Сарайчич

4

Ось як я виправив усі закінчення рядків у всій історії за допомогою git filter-branch. ^MСимвол повинен бути введений з допомогою CTRL-V+ CTRL-M. Я використовував dos2unixдля перетворення файлів, оскільки це автоматично пропускає двійкові файли.

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'


3

"| Xargs fromdos" читає зі стандартного вводу (файли findзнаходять) і використовує його як аргументи для команди fromdos, яка перетворює закінчення рядків. (Чи є стандарт нормами в цих середовищах? Я звик до dos2unix). Зауважте, що ви можете уникати використання xargs (особливо корисно, якщо у вас достатньо файлів, список аргументів занадто довгий для xargs):

find <path, tests...> -exec fromdos '{}' \;

або

find <path, tests...> | while read file; do fromdos $file; done

Я не зовсім впевнений у ваших повідомленнях про помилки. Я успішно випробував цей метод. Яку програму виробляє кожен? На які файли / каталоги у вас немає дозволів? Однак ось угадка в здогадуванні, що це може бути:

Один з простих способів отримати помилку "файл не знайдений" для сценарію - за допомогою відносного шляху - використовувати абсолютний. Так само ви можете отримати помилку дозволів, якщо ви не зробили свій сценарій виконуваним (chmod + x).

Додайте коментарі, і я спробую допомогти вам розібратися!


Я бачив ще один приклад з dos2unix, і думав, що це якось копіювати файли в папку з назвою, але тепер я це отримую. Нічого собі, зараз очевидно. Спасибі за вашу допомогу!
Брайан Донахю

1

гаразд ... під cygwin у нас немає легкодоступних данихdodos, і цей підкінець awk підірве вам в обличчя, якщо у вас є пробіли в шляхах до модифікованих файлів (які у нас були), тож я повинен був зробити це дещо інакше:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

kudos to @lloyd для основної частини цього рішення


-2

Виконайте ці кроки, якщо жоден з інших відповідей не працює для вас:

  1. Якщо ви працюєте в Windows, зробіть це git config --global core.autocrlf true; якщо ви перебуваєте на Unix, зробіть цеgit config core.autocrlf input
  2. Біжи git rm --cached -r .
  3. Видаліть файл .gitattributes
  4. Біжи git add -A
  5. Біжи git reset --hard

Тоді ваші місцеві повинні тепер бути чистими.


4
Дійсно? Видалення .gitattributesфайлу - це рішення проблеми закінчення рядків?
Олександр М

Так, будь ласка, зверніться до коментаря @AleksandrM
Mr_and_Mrs_D
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.