Сброс или возврат определенного файла к определенной ревизии с помощью Git?

3597

Я внес некоторые изменения в файл, который был передан несколько раз как часть группы файлов, но теперь хочу reset/вернуть изменения на него обратно в предыдущую версию.

Я сделал git log вместе с git diff, чтобы найти нужный мне вариант, но просто не знаю, как вернуть файл в прежнее состояние в прошлом.

  • 8
    После возврата не забудьте --cached при проверке git diff . ссылка на сайт
  • 3
    Я нашел твой вопрос, когда погуглил мой. Но после того, как я прочитал решение, я проверил свой журнал и обнаружил, что я сделал эти изменения как отдельный коммит, поэтому я сделал git revert для этого коммита, а все остальное осталось так, как я хотел. Не решение, просто другой способ сделать это иногда.
Теги:
version-control

31 ответ

4862
Лучший ответ

Предполагая, что хеш коммита, который вы хотите, c5f567:

git checkout c5f567 -- file1/to/restore file2/to/restore

Страница руководства git checkout дает больше информации.

Если вы хотите вернуться к фиксации до c5f567, добавьте ~1 (работает с любым числом):

git checkout c5f567~1 -- file1/to/restore file2/to/restore

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

  • 10
    @shadowhand: есть ли способ отменить это, так что это версия сразу после?
  • 14
    @aliteralmind: Нет, к сожалению, сокращенная запись истории Git в истории движется только назад.
Показать ещё 18 комментариев
568

Вы можете быстро просмотреть изменения, внесенные в файл, используя команду diff:

git diff <commit hash> <filename>

Затем, чтобы вернуть конкретный файл этому фиксатору, используйте команду reset:

git reset <commit hash> <filename>

Возможно, вам придется использовать опцию --hard, если у вас есть локальные модификации.

Хорошим документооборотом для управления путевыми точками является использование тегов для чистоты точек на вашей временной шкале. Я не могу понять ваше последнее предложение, но то, что вам может понадобиться, - это расхождение ветки с предыдущего момента времени. Для этого используйте удобную команду checkout:

git checkout <commit hash>
git checkout -b <new branch name>

Затем вы можете переустановить это против своей основной линии, когда будете готовы объединить эти изменения:

git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>
  • 6
    Команда 'git checkout <commit hash>' вернула мне мою старую версию проекта, именно эту, которую я искал. Спасибо, Крис.
  • 2
    «git reset <commit hash> <filename>» не изменил мой конкретный файл, который я хотел изменить. Есть ли способ проверить версию файла, а не оформить весь проект?
Показать ещё 6 комментариев
334

Вы можете использовать любую ссылку на фиксацию git, включая SHA-1, если это наиболее удобно. Дело в том, что команда выглядит так:

git checkout [commit-ref] -- [filename]

  • 16
    В чем разница между этим ответом, который имеет -- , и принятым, который не имеет?
  • 65
    В git знак «-» перед списком файлов говорит git, что все последующие аргументы должны интерпретироваться как имена файлов, а не как имена веток или что-то еще. Иногда это помогает разобраться.
Показать ещё 7 комментариев
256
git checkout -- foo

Это будет reset foo для HEAD. Вы также можете:

git checkout HEAD^ foo

для одной ревизии и т.д.

  • 9
    Я бы предложил использовать синтаксис git checkout -- foo чтобы избежать ошибок, если foo - это что-то особенное (например, каталог или файл с именем -f ). В git, если вы не уверены, всегда ставьте перед всеми файлами и каталогами специальный аргумент -- .
  • 6
    Дополнительное примечание к комментарию Микко: -- это не команда git и не специально для git. Это встроенный bash для обозначения конца параметров команды. Вы также можете использовать его со многими другими командами bash.
Показать ещё 1 комментарий
119

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

git checkout HEAD file/to/restore
  • 2
    В чем разница между этим (git checkout HEAD file / to / restore) и git reset --hard file / to / restore ???
  • 2
    1) легче запомнить более общий способ 2) не беспокойтесь, чтобы нажать Enter перед вводом имени файла
97

У меня была такая же проблема только сейчас, и я нашел этот ответ проще всего понять (commit-ref - значение SHA изменения в журнале, который вы хотите отправить назад):

git checkout [commit-ref] [filename]

Это ставит эту старую версию в ваш рабочий каталог, и оттуда вы можете ее зафиксировать, если хотите.

88

Если вы знаете, сколько коммитов вам нужно вернуться, вы можете использовать:

git checkout master~5 image.png

Предполагается, что вы находитесь в ветке master, а желаемая версия - 5.

78

Я думаю, что нашел... от http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html

Иногда вы просто хотите вернуться и забыть обо всех изменениях за определенный момент, потому что все они неправы.

Начните с:

$ git log

который показывает вам список последних коммитов и их хэш SHA1.

Затем введите:

$ git reset --hard SHA1_HASH

чтобы восстановить состояние для данной фиксации и стереть все новые записи из записи навсегда.

  • 23
    Git никогда ничего не удаляет. Ваши старые коммиты все еще там, но если на них не будет указана ветка, они больше не будут доступны. git reflog будет показывать их, пока вы не очистите свой репозиторий с помощью git-gc.
  • 1
    @Bombe: Спасибо за информацию. Я проверил старую версию файла. После прочтения вашего комментария я смог использовать "gitref" для поиска частичного хэша SHA1 и использовать "checkout", чтобы вернуться к самой последней версии. Другие пользователи git могут найти эту информацию полезной.
Показать ещё 8 комментариев
61

Это сработало для меня:

git checkout <commit hash> file

Затем зафиксируйте изменение:

git commit -a
52

Вы должны быть осторожны, когда говорите "откат". Если вы использовали одну версию файла в commit $A, а затем сделали два изменения в двух отдельных коммитах $B и $C (так что вы видите, это третья итерация файла), и если вы скажете "Я хочу вернуться к первому", вы действительно это имеете в виду?

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

$ git checkout $A file

а затем вы фиксируете результат. Команда запрашивает "Я хочу проверить файл из состояния, записанного фиксацией $A".

С другой стороны, то, что вы имели в виду, это избавиться от изменения второй итерации (то есть совершить $B), при сохранении того, что зафиксировал файл $C в файле, вы хотели бы вернуть $B

$ git revert $B

Обратите внимание: кто бы ни создавал commit $B, возможно, не был очень дисциплинирован и мог совершить совершенно несвязанные изменения в одной и той же фиксации, и это возвращение может касаться файлов, отличных от файла, который вы видите, оскорбительные изменения, поэтому вы можете проверить результат тщательно после этого.

  • 0
    Я сделал это, но тогда «файл журнала git» сказал бы, что я был на исходном коммите, HEAD. Казалось, что «Git Checkout» не удается. Тем не менее, состояние git показывало, что файл действительно был изменен, и "git diff --staged file" будет показывать фактические изменения. Кроме того, «git status» показал, что файл также изменился. Так что не используйте здесь «git log», чтобы отслеживать, какие файлы были изменены.
36

Интересно, 'git checkout foo' не будет работать, если рабочая копия находится в каталоге с именем foo; однако, как "w20 > checkout HEAD foo" и "git checkout./foo" будет:

$ pwd
/Users/aaron/Documents/work/foo
$ git checkout foo
D   foo
Already on "foo"
$ git checkout ./foo
$ git checkout HEAD foo
  • 23
    или git checkout -- foo
31

Здесь rebase работает:

git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>

Предположим, что у вас есть

---o----o----o----o  master
    \---A----B       <my branch>

Первые две команды... совершить    git выписка   git мастер переустановки

... проверьте ветвь изменений, которые вы хотите применить к ветки master. Команда rebase берет коммиты из <my branch> (которые не найдены в master) и повторно применяет их к заголовку master. Другими словами, родительский элемент первого коммита в <my branch> больше не является предыдущим фиксатором в истории master, а текущим заголовком master. Две команды такие же, как:

git rebase master <my branch>

Возможно, было бы легче запомнить эту команду, так как ветки "base" и "modify" явно.

. Конечный результат:

---o----o----o----o   master
                   \----A'----B'  <my branch>

Последние две команды...

git checkout master
git merge <my branch>

... выполните быстрое слияние для применения всех изменений <my branch> на master. Без этого шага фиксация rebase не добавляется к master. Конечный результат:

---o----o----o----o----A'----B'  master, <my branch>

master и <my branch> обе ссылки B'. Кроме того, с этой точки можно безопасно удалить ссылку <my branch>.

git branch -d <my branch>
20

git -алиасы, awk и функции оболочки для спасения!

git prevision <N> <filename>

где <N> - это количество исправлений файла для отката для файла <filename>.
Например, чтобы проверить немедленную предыдущую ревизию одного файла x/y/z.c, запустите

git prevision -1 x/y/z.c

Как работает git предикция?

Добавьте в свой gitconfig

следующее:
[alias]
        prevision = "!f() { git checkout `git log --oneline $2 |  awk -v commit="$1" 'FNR == -commit+1 {print $1}'` $2;} ;f"

Команда в основном

  • выполняет git log в указанном файле и
  • выбирает соответствующий идентификатор фиксации в истории файла и
  • выполняет git checkout идентификатор commit для указанного файла.

По существу, все, что можно было бы сделать вручную в этой ситуации,
завернутый в один красивый, эффективный git -alias - git-prevision

20

Мне нужно подключить EasyGit здесь, который является оберткой, чтобы сделать git более доступным для новичков, не запутывая опытных пользователей. Одна из вещей, которые она делает, - дает больше значений git revert. В этом случае вы просто скажете:

eg revert foo/bar foo/baz

  • 1
    Это должно быть, eg revert --in REVISON -- FILENAME . --in важно. Для пользователей Windows: откройте git bash. Выполнить echo %PATH . Первый путь должен быть в вашем пользовательском каталоге, заканчивающемся bin . Создайте этот путь. Хранить, например, там. Назовите это eg . Не например eg.txt .
19

Первая Reset Голова для целевого файла

git reset HEAD path_to_file

Вторая проверка этого файла

git checkout -- path_to_file
  • 3
    +1, хотя не уверен в намерении сброса HEAD. Это может или не может быть необходимо. В моей ситуации я хотел вернуть только один конкретный файл к версии в репозитории (которая сохранила оставшиеся локальные изменения без изменений. Мне достаточно было выполнить второй шаг выше)
19

В случае, если вы хотите вернуть файл в предыдущую фиксацию (и файл, который вы хотите вернуть уже зафиксирован), вы можете использовать

git checkout HEAD^1 path/to/file

или

git checkout HEAD~1 path/to/file

Затем просто выполните этап и зафиксируйте "новую" версию.

Вооружившись знаниями о том, что в случае слияния commit может иметь двух родителей, вы должны знать, что HEAD ^ 1 является первым родителем, а HEAD ~ 1 является вторым родителем.

Либо будет работать, если в дереве есть только один родитель.

19

Обратите внимание, что git checkout ./foo и git checkout HEAD ./foo не точно одно и то же; пример:

$ echo A > foo
$ git add foo
$ git commit -m 'A' foo
Created commit a1f085f: A
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 foo
$ echo B >> foo
$ git add foo
$ echo C >> foo
$ cat foo
A
B
C
$ git checkout ./foo
$ cat foo
A
B
$ git checkout HEAD ./foo
$ cat foo
A

(Второй add обрабатывает файл в индексе, но он не получает совершено.)

git checkout ./foo означает возврат пути ./foo к индексу ; добавление HEAD инструктирует Git вернуть этот путь в индекс к его HEAD до этого.

14

Здесь много предложений, большинство из них в духе git checkout $revision -- $file. Пара неясных альтернатив:

git show $revision:$file > $file

А также, я часто использую это только для того, чтобы временно увидеть конкретную версию:

git show $revision:$file

или же

git show $revision:$file | vim -R -

(OBS: $file должен начинаться с префикса ./ если это относительный путь для git show $revision:$file to work)

И тем более странно

git archive $revision $file | tar -x0 > $file
  • 1
    Это хорошая альтернатива, если вы не уверены, какую версию коммита вы хотите, и вам нужно «посмотреть» без перезаписи вашего рабочего каталога.
11

Чтобы перейти к предыдущей версии файла фиксации, получите номер фиксации, скажем, eb917a1 то

git checkout eb917a1 YourFileName

Если вам просто нужно вернуться к последней зарегистрированной версии

git reset HEAD YourFileName
git checkout YourFileName

Это приведет вас к последнему зафиксированному состоянию файла

10

Для меня ни один ответ не казался действительно ясным, и поэтому я хотел бы добавить мой, который кажется супер простым.

У меня есть commit abc1, и после него я сделал несколько (или одну модификацию) файла file.txt.

Теперь скажите, что я что-то испортил в файле file.txt, и я хочу вернуться к предыдущему commit abc1.

1. git checkout file.txt: это приведет к удалению локальных изменений, если они вам не нужны.

2. git checkout abc1 file.txt: это приведет ваш файл к вашей желаемой версии

3. git commit -m "Restored file.txt to version abc1": это приведет к вашей реверсии.

  1. git push: это приведет все в удаленный репозиторий

Между шагами 2 и 3, конечно, вы можете сделать git status, чтобы понять, что происходит. Обычно вы должны видеть, что file.txt уже добавлен, и поэтому нет необходимости в git add.

  • 2
    Итак, я думаю, что шаги 1. и 2. являются взаимоисключающими: если abc1 - ваш последний коммит, нет необходимости в 2. и если после abc1 были другие коммиты, вы можете напрямую сделать 2.
  • 2
    отличный ответ. это должно быть № 1
10

git checkout ref | commitHash - filePath

например.

git checkout HEAD~5 -- foo.bar
or 
git checkout 048ee28 -- foo.bar
8

Многие ответы здесь требуют использовать git reset ... <file> или git checkout ... <file>, но при этом вы потеряете все изменения в <file>, совершенные после коммита, который вы хотите вернуть.

Если вы хотите отменить изменения только от одного фиксации только в одном файле, как это сделал бы git revert, но только для одного файла (или, скажем, подмножества файлов фиксации), я предлагаю использовать как git diff, так и git apply как это (с <sha>= хеш коммита, который вы хотите вернуть):

git diff <sha>^ <sha> path/to/file.ext | git apply -R

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

Конечно, он не работает, если ревертированные строки были изменены любым фиксацией между <sha1> и HEAD (конфликтом).

  • 1
    Это оно! Должен быть отмечен как лучший ответ
8

Используйте git log для получения хеш-ключа для конкретной версии, а затем используйте git checkout <hashkey>

Примечание. Не забудьте ввести хэш перед последним. Последний хэш указывает текущую позицию (HEAD) и ничего не меняет.

7

Очевидно, кому-то нужно написать понятную книгу на git или git, чтобы ее лучше объяснить в документации. Столкнувшись с этой же проблемой, я догадался, что

cd <working copy>
git revert master

отменяет последнее совершение, которое, как представляется, делает.

Ян

5

Если вы делаете неправильный файл в ваших последних коммитах, следуйте инструкциям:

  1. дерево с открытым исходным кодом, измените этот коммит

Изображение 7461

  1. измените строки и найдите ваш коммит, который неверный файл отправил как коммит

Изображение 7462

  1. вы можете увидеть список ваших изменений в этом коммите Изображение 7463
  2. выберите его, а затем нажмите... кнопки с правой стороны... нажмите обратный файл
  3. затем вы можете увидеть его на вкладке статуса файла в левой нижней части, затем нажмите "untage":

Изображение 7464

  1. откройте код Visual Studio и вернитесь обратно, зафиксировав удаленные файлы
  2. после всех них вы можете увидеть результаты вашего последнего коммита в исходном дереве

Изображение 7465

4

Вы можете сделать это в 4 этапа:

  1. отменить весь коммит с файлом, который вы хотите специально отменить - это создаст новый коммит в вашей ветке
  2. soft reset that commit - удаляет коммит и перемещает изменения в рабочую область
  3. отобрать файлы вручную, чтобы вернуть и зафиксировать их
  4. бросить все остальные файлы в вашей рабочей области

Что нужно набрать в своем терминале:

  1. git revert <commit_hash>
  2. git reset HEAD~1
  3. git add <file_i_want_to_revert> && git commit -m 'reverting file'
  4. git checkout.

удачи

  • 0
    разве это не отменяет ВСЕ изменения?
  • 1
    @ arcee123 Да, но последующий сброс отменяет отмену всех изменений. Проблема в том, что git-revert действует только на весь репо, поэтому чтобы компенсировать это, мы должны отменить все остальное.
Показать ещё 4 комментария
4
git revert <hash>

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

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

1

Это очень простой шаг. Извлеките файл с идентификатором фиксации, который мы хотим, здесь один идентификатор фиксации ранее, а затем просто выполните команду git commitmend, и все готово.

# git checkout <previous commit_id> <file_name>
# git commit --amend

Это очень удобно. Если мы хотим вывести какой-либо файл с любым идентификатором предыдущей фиксации в верхней части фиксации, мы можем легко это сделать.

1

Если вы используете Git Extensions и хотите вернуться к родительскому фиксации для файла, вы можете выбрать фиксацию, содержащую изменения, которые хотите вернуть, затем выбрать вкладку "Diff" в деталях щелкните правой кнопкой мыши файл, который вы хотите вернуть, затем Reset файл на "....", затем "A" (родительский)

1

Вот мой путь.

a) В Android Studio откройте файл.

b) git → Показать историю, найти предыдущую фиксацию, к которой я хочу вернуться. Получите commit_id (т.е. Commit hash).

c) git checkout commit_id file_path

  • 2
    Твой путь - это путь принятого ответа.
0
  1. Git вернуть файл к определенной фиксации

git checkout Last_Stable_commit_Number - fileName

2.Git вернуть файл в определенную ветку

git checkout branchName_Which_Has_stable_Commit fileName

Ещё вопросы

Сообщество Overcoder
Наверх
Меню