Git селективный отменить локальные изменения из файла

149

В моем git-репо, который отслеживает svn-репо, я внес несколько изменений в один файл.

Теперь я хочу отменить эти изменения (например, svn revert), но только части файла.

Я хочу иметь возможность просматривать различия в файле, отменить (отменить) изменения, которые мне не нужны, и сохранить изменения, которые я хочу.

git add -i 

Команда, кажется, имеет возможность сделать это, но я пока не хочу ставить это.

Прадип
источник

Ответы:

91

Вы можете сделать это напрямую с git checkout -p. Смотрите ответ Даниэля Штутцбаха ниже.


Старый ответ (до того, как checkout -pбыл введен):

Вы можете сделать это так:

git add -i

(выберите туки, которые вы хотите сохранить)

git commit -m "tmp"

Теперь у вас есть фиксация только с теми изменениями, которые вы хотите сохранить, а остальное - без изменений.

git reset --hard HEAD

На этом этапе незафиксированные изменения были отброшены, поэтому у вас есть чистый рабочий каталог с изменениями, которые вы хотите сохранить зафиксированными.

git reset --mixed HEAD^

Это удаляет последний коммит ('tmp'), но сохраняет изменения в вашем рабочем каталоге без изменений.

EDIT: заменить --softс --mixed, чтобы очистить плацдарм.

Паоло Каприотти
источник
это внесет изменения, которые я хочу сохранить, не так ли? Я пока не хочу совершать эти изменения. мм возможно я принимаю коммиты слишком серьезно. Может быть, я должен расслабиться сейчас, так как все это в местном репо. Кстати, что делает git reset --soft HEAD ^?
Прадип
«git reset --soft HEAD ^» отменяет коммит в том смысле, что он сохраняет рабочий каталог и индекс, как это было, и перемещает текущую ветвь на один коммит обратно.
Якуб Наребски
Спасибо Якуб. Паоло, почему мягкий сброс на голову - 1 здесь требуется? частичного коммита и полного сброса должно быть достаточно, не для того, чтобы сохранить некоторые изменения и отменить другие?
Прадип
1
Ответ Даниэля ниже очень прост и выглядит как правильный способ сделать это.
Уманг
309

Я считаю, что вы можете сделать это проще всего с:

git checkout -p <optional filename(s)>

Из справочной страницы:

   −p, −−patch
       Interactively select hunks in the difference between the <tree−ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree−ish> was specified, the index).
       This means that you can use git checkout −p to selectively discard
       edits from your current working tree.
Даниэль Штутцбах
источник
1
Также, если вы не хотите делать это выборочно, вы можете использовать «git checkout - <file> ...» для отмены изменений.
DB42
Имеет ли это дело с каталогами?
bbum
1
Мне кажется, что при сбрасывании изменений мне это часто не удавалось («ошибка: исправление не удалось <файл>», «ошибка: исправление <файл> не применяется»). Как ни странно, я получу эти ошибки, когда использую aопцию в режиме патча для удаления всего файла, но git checkout -- <file>работает как положено. Кто-нибудь знает почему?
chrnola
У меня была эта ошибка несколько раз, если файл уже был исправлен, и поэтому интерактивное исправление устарело с примененными исправлениями текущего файла. Это происходило при использовании инструмента с графическим интерфейсом, такого как дерево исходников, когда я дважды случайно отбрасывал кусок. Второй раз выдаст эту ошибку.
Phyatt
3

Вы можете запустить git diffфайл, сохранить результирующий diff, отредактировать его, чтобы удалить изменения, которые вы хотите сохранить, а затем запустить его, patch -Rчтобы отменить оставшиеся diff.

git diff file.txt> patch.tmp
# edit patch.tmp для удаления фрагментов, которые вы хотите сохранить
patch -R <patch.tmp
Грег Хьюгилл
источник
У меня было 2 куска в моем файле патча, и я удалил один. Не уверен, в чем причина, но патч -R продолжает отвергаться.
Прадип
2
Вы упоминаете в другом комментарии, который git diffпоказывает весь файл как измененный. Обычно это происходит, когда вы сохранили файл, используя разные окончания строк, чем это было ранее. Это также может привести patchк отклонению файла исправления. Похоже ли это на то, что могло случиться?
Грег Хьюгилл
Ты прав. окончания строк переключаются всякий раз, когда я использую команду patch. Я на окнах и использую крем / VIM. Мне нужно сначала разобраться с этим, я думаю.
Прадип
Я не смог решить проблему с патчем на Windows. Хотя я уверен, что это работает, я предпочитаю использовать рецепт Паоло. Для любви к этим интерактивным командам для работы с различиями используйте git add -i.
Прадип
3

Похоже, вы хотите

 git revert --no-commit $REVSISON 

Вы можете использовать

 git diff --cached

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

Если бы вы работали с чистым Git-репозиторием, вы могли бы, в зависимости от ваших целей, использовать интерактивную rebase ( git rebase -i), чтобы вернуться к коммиту, который вам не понравился, и отредактировать коммит задним числом, чтобы изменения, которые вам не нравились, никогда не происходили , но это обычно только потому, что если вы ЗНАЕТЕ, вы никогда не захотите увидеть это снова.

Кент Фредрик
источник
Я вернулся, как вы уже упоминали, к предыдущей ревизии (это правильно?), И теперь git diff показывает весь файл как измененный. Предполагается показать правки, которые я сделал?
Прадип
1

Перечитывая вопрос, звучит так, как будто вы хотите отменить изменения, которые есть в вашем рабочем дереве, а не изменения, которые были ранее зафиксированы, но некоторые другие ответы заставляют это звучать так, будто мое чтение может быть неправильным. Вы можете уточнить?

Если изменения находятся только в вашей рабочей копии, то самый простой способ сделать это - внести изменения, которые вы хотите сохранить:

git add -i <file>

Затем отбросьте изменения, которые вы не хотите сохранять, проверив версию индекса:

git checkout -- <file>

Затем отмените внесение изменений, если вы не хотите, чтобы они были поставлены:

git reset -- <file>

Этот рецепт отменяет только выбранные изменения в файле (или файлах, которые вы укажете) и не создает никаких временных фиксаций, которые затем необходимо отменить.

Если вы хотите выборочно применить только некоторые изменения, внесенные в предыдущих фиксациях, вы можете сначала сбросить файл до предыдущего зафиксированного состояния:

git reset <commit_before_first_unwanted_change> -- <file>

Затем вы можете следовать предыдущему рецепту, git add -i <file>чтобы внести те изменения, которые вы хотите сохранить, git checkout -- <file>отбросить нежелательные изменения и git reset -- <file>«удалить их».

CB Bailey
источник
0

Параметры командной строки, описанные в ответах здесь, удобны, когда файл находится на сервере, к которому я обращаюсь через ssh-терминал. Однако, когда файл находится на моей локальной машине, я предпочитаю следующий путь:

Откройте файл в редакторе netbeans (который поставляется с поддержкой git). Netbeans ставит красные / зеленые / синие метки на номера строк, чтобы указать, где материал был удален / добавлен / изменен (соответственно).

Щелчок правой кнопкой мыши по любой из этих меток дает вам возможность отменить это изменение. Кроме того, вы можете щелкнуть правой кнопкой мыши на красные и синие метки, чтобы увидеть, как старая версия появляется во всплывающем окне.

Абхишек Ананд
источник