0% прочитано

git restore -p на практиці: як прибрати зайве з diff і не втратити потрібну зміну

Після push у diff разом із потрібною зміною з’явилося стороннє форматування. Показую, як я використала git restore -p, щоб точково повернути непотрібні фрагменти до production і не втратити саму задачу.

1 жовтня 2026 р. 7 хв читанняGit

Іноді задача дуже маленька, а після push у pull request раптом з’являється значно більший diff.

Саме так сталося в мене нещодавно. Я змінювала відступи для одного елемента на сторінці. Потрібна зміна була невеликою, але під час перегляду diff я побачила сторонні пробіли, перенесення рядків і форматування, які взагалі не стосувалися задачі.

Повністю повернути файли до production я не могла, тому що в тих самих файлах уже знаходилась потрібна зміна.

Отже задача була іншою: прибрати тільки випадкові зміни форматування і залишити функціональну зміну.

Для цього мені дуже допоміг git restore -p.

Цей сценарій відрізняється від звичайного rollback. Я не хотіла повернути весь файл назад. Мені потрібно було вибірково повернути лише окремі фрагменти.

Спочатку я ще раз перевірила diff

BASH - Порівняти потрібні файли з production
git diff origin/master -- \  resources/assets/css/styles/page.scss \  resources/views/front/model/page/show.blade.php

Перед будь-яким відновленням я ще раз подивилася, що саме відрізняється від базової гілки.

У diff були змішані два типи змін:

  • моя потрібна зміна;
  • стороннє форматування та пробіли.

Саме тому звичайне повне відновлення файлів тут не підходило. Воно прибрало б не лише зайве, а й саму задачу.

Чому повне відновлення файлу тут небезпечне

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

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

Тому мені потрібен був не вибір між "залишити файл" і "повернути файл", а можливість приймати рішення для кожного окремого фрагмента diff.

Вибіркове відновлення через git restore -p

BASH - Відновлювати файли по фрагментах
git restore -p \  --source=origin/master \  -- \  resources/assets/css/styles/page.scss \  resources/views/front/model/page/show.blade.php

Опція -p означає patch.

Git не відновлює весь файл одразу. Він показує зміни окремими фрагментами - hunks - і для кожного запитує, що робити.

Git asks about every hunk
Discard this hunk from worktree [y,n,q,a,d,s,e,?]?

Найважливіше - не переплутати y та n

Що означають y та n
y - так, повернути цей фрагмент до версії з origin/production    поточна локальна зміна в цьому фрагменті зникне n - ні, не повертати цей фрагмент    поточна зміна залишиться
У git restore -p відповідь y означає не "залишити мою зміну", а навпаки - погодитися повернути цей фрагмент до source. Саме тут найпростіше помилитися.

Як я вирішувала, що залишити

Коли Git показував фрагмент, у якому були лише випадкові пробіли, перенесення рядків або інше форматування, я відповідала y.

Це означало: повернути саме цей фрагмент до origin/production.

Коли ж Git доходив до справжньої зміни задачі, я відповідала n, щоб залишити її в робочому файлі.

Фрагменти потрібної зміни
&--withdrawn-gap lot__rate--withdrawn-gap

У моєму випадку ці назви допомагали швидко впізнати потрібну зміну серед інших фрагментів.

Тобто логіка була дуже проста:

  • бачу лише випадкове форматування - y;
  • бачу зміну, заради якої створена задача - n.

У цьому й була головна перевага git restore -p: я працювала не з файлом цілком, а з окремими частинами його diff.

Після відновлення я знову перевірила diff

BASH - Перевірити результат очищення
git diff git diff -w git diff --check git status -sb

Після проходження всіх фрагментів я не покладалася лише на пам’ять про відповіді y та n. Я ще раз подивилася результат.

Звичайний git diff показує весь поточний diff.

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

git diff --check додатково перевіряє типові проблеми з пробілами, а git status -sb дає короткий стан гілки та файлів.

Що змінюється, якщо код уже був запушений

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

git restore -p не переписує старий commit у віддаленому репозиторії. Команда лише змінює мої поточні робочі файли.

Після очищення я перевірила результат, додала виправлені файли до нового commit і запушила його.

BASH - Створити окремий commit з очищенням diff
git add \  resources/assets/css/styles/page.scss \  resources/views/front/model/page/show.blade.php git commit -m "Restore unrelated whitespace" git push

У результаті pull request отримав ще один commit, який прибирав випадкові зміни, але не торкався самої задачі.

Якщо пізніше потрібно привести історію до одного чистого commit, це вже окрема операція. Для мене на цьому етапі важливішим було спочатку отримати правильний і зрозумілий diff.

Чому я не повертала все вручну

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

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

git restore -p вже має всю потрібну інформацію. Git показує конкретний фрагмент різниці, а я лише вирішую, повернути його до базової версії чи залишити.

Команда, яку я хочу запам’ятати

BASH - Вибірково повернути фрагменти файлу
git restore -p \  --source=origin/production \  -- \  path/to/file
Коротка підказка
y - повернути цей фрагмент до версії з sourcen - залишити мою поточну зміну

Коли в одному файлі змішані потрібні й випадкові зміни, мені не обов’язково вибирати між брудним diff і повним відкатом. Я можу повернути тільки конкретні фрагменти.

Це маленька Git-команда, але вона вирішила дуже конкретну проблему.

Потрібна зміна вже була зроблена й запушена. Повний restore знищив би її разом із зайвим форматуванням. Ручне повернення пробілів було б повільнішим і менш надійним.

git restore -p дозволив пройти diff по частинах і для кожної окремо вирішити: це повернути чи це залишити.

У результаті я прибрала тільки те, що випадково потрапило в pull request, і зберегла саме ту зміну, заради якої створювалася задача.