Скасуйте частину нестандартних змін у git


158

Як я скасовую частини моїх нестандартних змін у git, а решту зберігаю як невідомі? Я зрозумів:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Це працює, але було б непогано, якби було щось на зразок git commit --interactiveлише повернення змін. Будь-які кращі методи?

Відповіді:


264

Ви можете використовувати git checkout -p, що дозволяє вибирати окремі перегони з різниці між вашою робочою копією та індексом для відновлення. Аналогічно, git add -pдозволяє вибирати лук для додавання до індексу, а також git reset -pдозволяє вибирати окремі хунки від різниці між індексом та HEAD до того, щоб не виходити з індексу.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Якщо ви хочете заздалегідь зробити знімок у вашому сховищі git, щоб зберегти ці зміни, перш ніж їх повернути, я хочу зробити:

$ git stash; git stash apply

Якщо ви цим часто користуєтесь, ви, можливо, захочете його псевдонімом:

[alias]
    checkpoint = !git stash; git stash apply

Повернення окремих елементів або рядків може бути ще простішим, якщо ви використовуєте хороший режим редактора або плагін, який може забезпечити підтримку вибору рядків безпосередньо для повернення, як це -pможе бути дещо незграбно використовувати. Я використовую Magit , режим Emacs, який дуже допомагає працювати з Git. У програмі Magit ви можете запустити magit-status, знайти розрізки для змін, які ви хочете відновити, виберіть рядки, які ви хочете відновити (або просто покладіть курсор на елементи, які ви хочете відновити, якщо ви хочете повернути лук за раз, а не рядок по черзі) та натисніть, kщоб повернути ці конкретні рядки. Я дуже рекомендую Magit, якщо ви використовуєте Emacs.


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

1
Вибачте, я щойно зрозумів, що git checkoutтакож є -pпрапор, який робить саме те, що ви просили в одній команді. Вибачення за попередній складний набір кроків; ви можете просто використовувати git checkout -p. Що стосується збереження речей, перед тим, як робити щось потенційно руйнівне, я часто роблю git stash; git stash apply(або створюю псевдонім, який робить це як git checkpointчи щось), щоб записати поточне дерево у сховище, щоб я міг повернутися до нього, якщо щось піде не так.
Брайан Кемпбелл

Ось ви йдете, ось це рішення! Що стосується псевдоніму, я думаю, що щось подібне git commit -a -m "Backup Commit" --edit; git reset HEAD^ було б краще, бо тоді це не забруднило б моє сховище, яке я, можливо, використовую для чогось іншого. Тоді, поки у вас є SHA1, ви можете вибирати його у вишні протягом наступних 30 днів. --Edit дозволяє вам додавати інформацію до повідомлення про фіксацію, щоб допомогти вам знайти SHA1 пізніше, якщо ви цього хочете. З іншого боку, це забруднило б рефлог, тому я думаю, що це компроміс на основі того, що ви робите.
асмеурер

Псевдонім контрольної точки для мене не працює: виконується лише перша команда, а не друга. Це сумно, бо мені б це сподобалось. Я використовую git версії 1.7.10.4.
Фаб'єн

Чи є спосіб git checkout -pне застосувати патчі до індексу, а лише встановити їх?
Геремія

28
git diff > patchfile

Потім відредагуйте патч-файл та видаліть частини, які ви не хочете скасовувати, а потім:

patch -R < patchfile

6
Однак ця відповідь особливо захоплюється своєю простотою та зручністю у використанні. +1
грудня

Створений patchfileвиглядає чудово у форматі vim, і це справді допомагає!
Білий

Ідеально. Можна підтвердити, що він також працює під Windows з Cygwin та Ubuntu bash для Windows.
Checo R

1
Зауважте, ви також можете використовувати git apply -Rзамість patch(просто для того, щоб залишитися в царині git, або на відміну від події, patchяка недоступна)
user1556435

patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace

5

Ви могли б зробити

git checkout master -- path/to/file

Для кожного файлу, який потрібно скинути.


Або використовуйте HEAD замість господаря, якщо ви працюєте на гілці. Як сказано у звіті про "git status" (принаймні, в останніх версіях).
Джонатан Леффлер

1

Як щодо

  1. Виберіть резервні файли із змінами в індексі
  2. використовувати git add -pлише для того, щоб додати в індекс зміни, які ви хочете.

1

Коли я запускаю "git status", він говорить:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Отже, щоб скасувати нестандартні редагування, мені потрібно запустити:

git checkout -- makefile

3
Я думаю, що йому було цікаво, як повернути окремі хунки, а не цілий файл одночасно. Звичайно, це рішення, якщо вам просто потрібно скасувати всі зміни у файлі.
Брайан Кемпбелл

Так - я підозрюю, що ти прав. Параметри 'git checkout -p' та 'git add -p' здаються потрібними - як ви сказали.
Джонатан Леффлер

1

Відповідь Брайана Кемпбелла збиває мій git, версія 1.9.2.msysgit.0, з невідомих причин, тому мій підхід полягає в постановці на роботу, я хочу залишити зміни в робочій копії, а потім нестабільність.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .

1
Є також git stash -p. Ви могли б зробити git stash -p; git reset --hard; git stash pop. Це фактично те саме, що ви робите, за винятком того, що вам не потрібно писати повідомлення про фіксацію.
асмеурер

@asmeurer ура. Моєму не потрібне повідомлення про фіксацію, але в цьому випадку має більше сенсу використовувати скрипт, ніж індекс.
G-Wiz

0

ви можете зробити git checkoutі дати ім'ям назв частин, які ви хочете скасувати.

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