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


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.