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


126

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

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

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



Странно ... почему все изменилось после стольких лет?
VonC

Ответы:


222

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

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

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


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

Чтобы добавить к обсуждению здесь, вы можете добавить псевдоним к 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>

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.