Додайте лише непроменеві зміни


343

У мене є текстовий редактор, який автоматично обрізає пробіл пробілів після збереження файлу, і я беру участь у проекті з відкритим кодом, який має серйозні проблеми із заднім пробілом.

Кожен раз, коли я намагаюся надіслати виправлення, я повинен спочатку ігнорувати всі зміни, що стосуються лише пробілів, вручну, щоб вибрати лише відповідну інформацію. Мало того, але коли я бігаю, git rebaseто, як правило, через них виникають декілька проблем.

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

Хтось знає, як це зробити?

EDIT: Я не можу змінити спосіб роботи проекту, і вони вирішили, обговоривши його у списку розсилки, проігнорувати це.

Відповіді:


395

Рішення @Frew було не зовсім те, що мені потрібно, тому це псевдонім, який я зробив для тієї самої проблеми:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

Або ви можете просто запустити:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

Оновлення

Відповідно до цього коментаря, додані варіанти -U0та --unidiff-zeroвідповідно до вирішення проблем, що відповідають контексту .

В основному він застосовує патч, який застосовувався б addбез пробілів. Ви помітите, що після git addnw your/fileзміни не зміниться, залишилися пробіли.

Не потрібен кольоровий колір, але оскільки у мене завжди встановлені кольори, я мушу його використовувати. У будь-якому випадку, краще безпечно, ніж шкода.


7
Це добре працювало для мене, проте мені довелося використовувати git apply --ignore-whitespaceінакше патч не застосовуватись із очевидних причин.
— jupp0r

106
Справді має бути варіант додавання git, як git add -wце робилося.
— Ярл

7
Це створює мені проблеми з patch does not applyі error while searching for... Будь-які ідеї?
— DTI-Matt

18
не працювало для мене. Знайшли patch does not applyпомилку.
— Джеррі Саравія

13
Якщо ви отримуєте «патч не вдалося» з - за прогалин в контексті , як @bronson вказує, ця переглянута команда працює (Він генерує патч, без контексту): git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero. Це не є ризиковим, оскільки індекс вже настільки сучасний, як це може бути, тому це надійна база для виправлення.
— void.pointer

36

Це працює для мене:

Якщо ви хочете зберегти приховування навколо, це працює

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Я не як схованки, але я вже зіткнувся з помилкою в мерзотник + Cygwin , де я втрачу зміни, так , щоб переконатися , що матеріал пішов в reflog по крайней мере , я створив наступне:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

В основному ми створюємо diff, який не включає зміни простору, повертаємо всі наші зміни, а потім застосовуємо diff.


1
+1. Ви можете git stashзамість оформлення замовлення зробити резервну копію змін, принаймні, поки вона не буде перевірена.
— Paŭlo Ebermann

1
У вас закінчиться багато схованок, і в основному вам не потрібно все це робити. Це працює, але я думаю, це трохи безладно
— Колін Геберт

3
Я згоден з Коліном. Якщо сценарій працює, тоді не потрібно створювати скриньку. Що може бути добре врахувати, хоч би це запустити скриньку, а потім сховати поп. Зняті схованки можуть бути відновлені, якщо це необхідно, але в іншому випадку ви не закінчите з великою кількістю схованок. Це також залишає додатковий файл, що лежить навколо
— Casebash

Як щодо пропуск бінарних файлів? При спробі застосувати вищевказаний фрагмент, я отримую помилки, що патч неможливо застосувати без повного рядка індексу! Що мене б'є, це те, що я навіть навіть не торкався цих файлів / бінарних файлів!
— tver3305

1
Я думаю, що наприкінці першої команди "git rm foo.patch" має бути просто "rm foo.patch". Інакше дуже корисно дякую.
— Джек Кейсі

33

Створіть файл патча, що містить лише реальні зміни (виключаючи рядки із лише пробілами), потім очистіть робочу область та застосуйте цей патч-файл:

git diff> резервне копіювання
git diff -w> зміни
git reset - твердий
патч <зміни

Перегляньте решта відмінностей, то addі commitяк звичайно.

Еквівалент для Mercurial - це зробити:

hg diff> резервне копіювання
hg diff -w> зміни
hg revert - всі
імпорт hg - no-внесення змін


Що таке "захищене" питання? і я занадто відповідає. Я не думаю, що це навіть не відповідає мені, бо, здається, питання було
— знято

4
@jww Основним питанням оригінального плаката є "як уникнути внесення змін у пробіл лише для зміни джерела". ОП звичайно використовує Git, але це стосується також кожної системи управління джерелами, яку я коли-небудь використовував. Ця відповідь показує правильну процедуру, якщо хтось використовує Mercurial. Я міг би уявити, що хтось інший також може внести рішення для людей, які використовують сублізію тощо.
— Стів

1
@jww і @ pagid: я відредагував свою відповідь, щоб спеціально звернутися до Git, використовуючи той самий підхід, що і моє рішення для Mercurial. На мою думку, StackOverflow - це не просто ще один Q + A форум - він також має роль сховища знань. Люди, окрім оригінального плаката, можуть отримати користь від наданих відповідей, і їх обставини відрізняються. Тому я вважаю, що відповіді, що передають загальний принцип, справедливі, а не орієнтовані лише на одну конкретну ситуацію.
— Стів Пітчерс

@Steve - "Я відредагував свою відповідь, щоб спеціально звернутися до Git ..." - чому ви не задали нове запитання в контексті меркуріалу, а потім не додали власну відповідь на нове запитання ???
— jww

8
Це насправді найчистіший, найбільш зрозумілий і найбільш непорушний підхід, який я бачив.
— Kzqai

12

Відповідь, яку отримують голоси, працює не у всіх випадках, через пробіл у контексті виправлень, на думку користувачів у коментарях.

Я переглянув команду наступним чином:

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

Це генерує виправлення без контексту. Не повинно бути проблем, оскільки патч короткочасний.

Відповідний псевдонім, знову перегляд того, що вже було надано іншими користувачами:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -

Щоб ігнорувати зміни відступу, мені довелося використовувати --ignore-space-changeзамість -w. git diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
— Енді

Слово застереження не використовувати цей чудовий жодний контекстний трюк з --ignore-blank-linesіншим, ви знайдете різні шматки, які будуть зафіксовані при неправильних зміщеннях, якщо деякі зміни "білого простору", які ви хочете ігнорувати, - це видалення / доповнення порожніх рядків.
— elbeardmorez

12

Додайте до свого .gitconfig:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

Завдяки відповіді @Colin Herbert за натхнення.

Синтаксичне пояснення

Фінал #повинен бути цитований, тому він не трактується як коментар всередині .gitconfig, а натомість проходить через нього і трактується як коментар всередині оболонки - він вставляється між кінцем git applyта аргументами, що надаються користувачем, що gitавтоматично розміщується у кінець командного рядка. Ці аргументи тут не потрібні - ми не хочемо git applyїх споживати, звідси і попередній символ коментаря. Ви можете запустити цю команду, GIT_TRACE=1 git anwщоб побачити це в дії.

У --сигналах кінця аргументів і дозволяють в разі , що у вас є файл з ім'ям -wабо що - то , що буде виглядати як перемикач на git diff.

Уникнути подвійних лапок $@, необхідних для збереження будь-яких цитованих аргументів, що надаються користувачем. Якщо "персонаж не уникне, він буде спожитий .gitconfigпарсером і не досягне оболонки.

Примітка: .gitconfigпсевдонім розбір не визнає одинарні лапки нічого особливого - його тільки спеціальні символи ", \, \n, і ;(за межі "-quoted рядки). Ось чому "завжди потрібно уникати, навіть якщо це виглядає так, що воно знаходиться в одній цитованій рядку (про що git повністю агностик).

Це важливо, наприклад. якщо у вас є зручний псевдонім для виконання bashкоманди в корені робочого дерева. Неправильна рецептура:

sh = !bash -c '"$@"' -

Хоча правильним є:

sh = !bash -c '\"$@\"' -

Відмінно. Це дозволило мені додати один файл одночасно. Окрім додавання кореневого каталогу для аргументу, чи існує спосіб зробити цю роботу на зразок 'git add -A'?
— Чакі

7

Як щодо наступного:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

Команда всередині зворотних котирувань отримує назви файлів, які не змінюють пробілів.


2
або просто git add `git diff -w |grep '^+++' |cut -c7-`якщо субмодулі не використовуються
— karmakaze

-1

Спершу слід подумати, чи є пробіл із заднім числом навмисний. Багато проектів, включаючи ядро ​​Linux, Mozilla, Drupal та Kerberos (щоб назвати декілька зі сторінки Вікіпедії за стилем), забороняють залишати пробіли. З документації на ядро ​​Linux:

Отримайте гідний редактор і не залишайте пробілів у кінці рядків.

У вашому випадку проблема полягає в навпаки: попередні комісії (а може бути і поточні) не дотримувались цього керівництва.

Я б став на загрозу, що ніхто не захоче пробілу пробілу, і виправлення проблеми може бути бажаною зміною. Інші користувачі також можуть зіткнутися з тією ж проблемою, що і ви. Можливо також, що учасники, які додають пробіли, не знають, що вони роблять.

Замість того, щоб намагатися перенастроїти git, щоб ігнорувати проблему, або відключити бажану функціональність у вашому редакторі, я б почав із публікації до списку розсилки проекту, що пояснює проблему. Багато редакторів (і самих git) можуть бути налаштовані на обробку трейлінгу пробілів.


16
Це не навмисно, але я не можу змінити спосіб мислення 100+ людей, які сприяють проекту. Вони не заперечують проти цього і не прийматимуть патчів із змінами 1000+, що стосується лише пробілу білого простору. Вони знають про проблему і вирішили її проігнорувати. Ця дискусія вже відбулась у списку і була закрита. У цьому випадку мені потрібно адаптуватися до них.
— Еду Феліпе

19
Потім налаштуйте редактор таким чином, щоб він не обрізав пробіли пробілів під час роботи над кодом цього проекту.
— Jamessan

-2

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

  #!/bin/sh

  if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
     against=HEAD
  else
     # Initial commit: diff against an empty tree object
     against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
  fi
  # Find files with trailing whitespace
  for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
     # Fix them!
     sed -i 's/[[:space:]]*$//' "$FILE"
  done
  exit

4
Це питання задає питання, як зберегти відсталий пробіл.
— Дуглас

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