Отменить изменения в файле в фиксации

126

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

Могу ли я использовать для этого команду git revert?

Любой другой простой способ сделать это?

Лакшман Прасад
источник
Дубликат stackoverflow.com/questions/215718/…
koppor
Странно ... почему все изменилось после стольких лет?
VonC

Ответы:

222

Самый чистый способ, который я видел, описан здесь.

git show some_commit_sha1 -- some_file.c | git apply -R

Подобно ответу VonC, но с использованием git showи git apply.

mgalgs
источник
10
Отлично сделано. Решение сценария является излишним для этого. Почему не может быть просто git revert sha-1 filename?
Марк Эдингтон
16
Это работает на моем Mac, но в Windows (под Cygwin) это дает мне:fatal: unrecognized input
Kedar Mhaswade
1
@MerhawiFissehaye: Я думаю, что git checkout снова вернет изменения, чтобы вернуться к состоянию, которое было в фиксации. Я сделал 'git add filename; git commit --amend ', чтобы удалить файл из фиксации.
ViFI
3
Просто совет: мне почти всегда приходится добавлять -3флаг в git apply для трехстороннего слияния, когда патч не работает, так как я обычно исправляю изменение немного назад во времени.
angularsen
2
Может быть , очевидно , для большинства , но обеспечить some_file.cвключает в себя путь к файлу , если есть один в противном случае вы не будете молча заплаты ничего :)
Warpling
35

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

Например, вы хотите отменить изменения в 1 файле ( badfile.txt) при фиксации aaa222:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

Сделайте повторную базу на базовом коммите, исправьте фиксацию проблемы и продолжите.

1) Запустите интерактивную перебазировку:

git rebase -i aaa111

2) Отметьте фиксацию проблемы для редактирования в редакторе, изменив pickна e(для редактирования):

e aaa222
pick aaa333

3) Отменить изменения в плохой файл:

git show -- badfile.txt | git apply -R

4) Добавьте изменения и исправьте фиксацию:

git add badfile.txt
git commit --amend

5) Завершите перебазирование:

git rebase --continue
тройник
источник
Просто хочу отметить, что здесь предполагается, что вы можете редактировать историю git. Некоторые ответы выше создают новую фиксацию, которая отменяет конкретное изменение без редактирования истории, что не всегда возможно / разрешено.
angularsen
Фантастика. Это было именно то, что я искал. У меня уже была эта идея, но я запутался, когда делал интерактивную перебазировку, что файлы при выполнении editне отображались как измененные. Но он git show -- badfile.txt | git apply -Rдал нужный мне ответ <3
mraxus
если я понимаю, что git apply -R удаляет фиксацию в этом файле, возвращая его в исходное измененное состояние?
DaImTo
19

git revert для всего содержимого файла в коммитах.

Для одного файла вы можете написать сценарий :

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(Из утилит git-shell-scripts от smtlaissezfaire )


Примечание:

здесь описан другой способ, если вы еще не зафиксировали текущую модификацию.

git checkout -- filename

git checkout имеет несколько параметров для файла, изменение файла из HEAD, перезапись вашего изменения.


Dropped.on.Caprica упоминает в комментариях :

Вы можете добавить псевдоним к git, чтобы вы могли сделать это git revert-file <hash> <file-loc>и восстановить этот конкретный файл.
Смотрите в этом суть .

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh
VonC
источник
Чтобы добавить к обсуждению здесь, вы можете добавить псевдоним к git, чтобы вы могли сделать это git revert-file <hash> <file-loc>и вернуть этот конкретный файл. Я отказался от этого ответа (хотя мне пришлось внести пару изменений, чтобы работать правильно). Вы можете найти копию моего .gitconfigи отредактированного сценария здесь: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
AlbertEngelB 02
@ Dropped.on.Caprica - хороший аргумент. Я включил его в ответ для большей наглядности.
VonC
12

Я бы просто использовал --no-commitопцию, git-revertа затем удалил файлы, которые вы не хотите возвращать из индекса, прежде чем окончательно зафиксировать его. Вот пример, показывающий, как легко вернуть только изменения в foo.c во второй по времени фиксации:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

Сначала git-reset"деактивирует" все файлы, чтобы затем мы могли добавить обратно только один файл, который мы хотим вернуть. Финал git-reset --hardизбавляется от оставшихся возвратов файлов, которые мы не хотим сохранять.

Дэн Молдинг
источник
9

Гораздо проще:

git reset HEAD^ path/to/file/to/revert

затем

git commit --amend   

а потом

git push -f

файл исчез, а хеш фиксации, сообщение и т. д. остались прежними.

Форрест
источник
Для полноты картины нужен git checkout -- path/to/file/to/revertшаг? Кроме того, неверно, что после этого хеш остается прежним, верно? Последнее предложение могло бы быть лучше, чем-то вроде: «В результате последняя фиксация заменяется новой, которая отличается только тем, что она не содержит изменений в возвращенном файле».
Кевин
@ Кевин, ты, наверное, прав. Мне придется дважды проверить эту последнюю строку, но, оглядываясь назад на это пару лет назад, я был бы удивлен, если хеш фиксации не изменился.
Форрест
6
git reset HEAD^ path/to/file/to/revert/in/commit

Приведенная выше команда выведет файл из фиксации, но отразится в git status.

git checkout path/to/file/to/revert/in/commit

Приведенная выше команда отменит изменения (в результате вы получите такой же файл, как HEAD).

git commit

(Пройдите, --amendчтобы изменить фиксацию.)

git push

При этом файл, который уже находится в фиксации, удаляется и возвращается.

Вышеуказанные шаги должны выполняться из ветки, в которой сделан коммит.

Бхарат Т.С.
источник
5

Вы можете выполнить эту процедуру:

  1. git revert -n <*commit*>( -nотменить все изменения, но не фиксировать их)
  2. git add <*filename*> (имя файла / ов, которые вы хотите отменить и зафиксировать)
  3. git commit -m 'reverted message' (добавить сообщение для возврата)
  4. после фиксации отменить изменения в других файлах, чтобы файлы оставались обновленными с учетом изменений, которые вы зафиксировали до возврата
Имран Сахил
источник
1

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

Обратите внимание, что файл будет добавлен в область подготовки.

git checkout <prev_commit_hash> -- <path_to_your_file>

Надеюсь, поможет :)

Gabeeka
источник