Как я могу сбросить или вернуть файл к определенной ревизии?

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

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

18.10.2008 23:34:02
После возврата не забудьте --cachedпри проверке git diff. ссылка
Geoffrey Hale 2.12.2015 19:20:46
Я нашел твой вопрос, когда погуглил мой. Но после того, как я прочитал решение, я проверил свой журнал и обнаружил, что я сделал эти изменения как отдельный коммит, поэтому я сделал git revert для этого коммита, а все остальное осталось так, как я хотел. Не решение, просто другой способ сделать это иногда.
sudo97 8.08.2017 14:08:27
30 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

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

6052
26.03.2020 16:24:37
@shadowhand: Есть ли способ отменить это, так что это версия сразу после?
aliteralmind 29.04.2014 12:57:17
@aliteralmind: Нет, к сожалению, сокращенная запись истории Git в истории идет только назад.
Greg Hewgill 29.04.2014 18:02:22
Если вы собираетесь использовать название ветви для abcde (например develop), которое вам нужно git checkout develop -- file/to/restore(обратите внимание на двойную черту)
Ohad Schneider 7.10.2014 15:14:07
@aliteralmind: На самом деле, да, есть способ сделать это: "git log --reverse -1 --ancestry-path yourgitrev..master", а затем используйте соответствующие параметры, чтобы просто получить git rev. --ancestry-path "нарисует линию" между двумя коммитами, а -1 покажет вам только одну версию, а --reverse обеспечит, чтобы первая отправленная запись была самой старой.
Chris Cogdon 19.11.2014 19:29:52
Лично я нахожу ГОЛОВУ ^ легче набирать, чем ГОЛОВУ ~ 1 :)
juzzlin 1.07.2016 11:38:02
git checkout -- foo

Это сбросит fooна ГОЛОВУ. Вы также можете:

git checkout HEAD^ foo

за одну ревизию назад и т. д.

283
18.03.2013 07:47:14
Я бы предложил использовать синтаксис, git checkout -- fooчтобы избежать каких-либо ошибок, если fooчто-то особенное (например, каталог или файл с именем -f). С git, если вы не уверены, всегда ставьте перед всеми файлами и каталогами специальный аргумент --.
Mikko Rantalainen 18.03.2013 07:22:58
Дополнительное примечание к комментарию Микко: --это не команда git и не специально для git. Это встроенный bash для обозначения конца параметров команды. Вы также можете использовать его со многими другими командами bash.
matthaeus 4.03.2016 13:04:33
@matthaeus также не относится ни к bash, ни к функциям оболочки. Это соглашение реализовано во многих различных командах (и поддерживается getopt).
Greg Hewgill 4.03.2016 17:47:19
Нет, --это не встроенное специальное слово в bash. Но это общее соглашение, поддерживаемое многими анализаторами командной строки и используемое многими CLI, включая git.
Emil Lundberg 1.09.2019 14:20:16

Забавно, git checkout fooне будет работать, если рабочая копия находится в каталоге с именем foo; однако, и так git 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
37
2.07.2019 13:56:43
илиgit checkout -- foo
knittl 7.03.2010 16:34:26

Обратите внимание, однако, что 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ревизии, прежде чем сделать это.

18
29.04.2014 12:21:11

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

eg revert foo/bar foo/baz

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

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

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

Начните с:

$ git log

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

Далее введите:

$ git reset --hard SHA1_HASH

чтобы восстановить состояние данного коммита и удалить все новые коммиты из записи навсегда.

80
20.11.2011 00:55:15
Git никогда ничего не удаляет. Ваши старые коммиты все еще там, но если на них не будет указана ветка, они больше не будут доступны. git reflog будет показывать их, пока вы не очистите свой репозиторий с помощью git-gc.
Bombe 17.12.2008 09:15:21
@Bombe: Спасибо за информацию. Я проверил старую версию файла. После прочтения вашего комментария я смог использовать "gitref" для поиска частичного хэша SHA1 и использовать "checkout", чтобы вернуться к самой последней версии. Другие пользователи git могут найти эту информацию полезной.
Winston C. Yang 19.05.2010 14:53:18
возможно последует agit push --force
bshirley 18.04.2012 21:47:55
Если у вас есть незафиксированные изменения, вы потеряете их, если выполните git reset --hard
Boklucius 24.04.2012 15:30:55
@Bombe - «Git никогда ничего не удаляет. Ваши старые коммиты все еще там, но если на них нет подсказки ветки, они больше недоступны». - но такие коммиты обрезаются через определенное время, поэтому «Git никогда ничего не удаляет» не соответствует действительности.
Bulwersator 29.04.2014 07:07:42

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

git diff <commit hash> <filename>

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

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>
597
17.12.2008 06:59:33
Команда 'git checkout <commit hash>' вернула мне мою старую версию проекта, именно эту, которую я искал. Спасибо, Крис.
vidur punj 27.01.2013 09:26:39
Чтобы вернуть файл git checkout <commit hash> <filename>работал лучше для меня, чемgit reset
Motti Strom 7.03.2013 16:53:47
Я хотел раннюю версию одного файла, потому что я перезаписал 150 строк неправильно выбранной копией / вставкой. git checkout <commit hash> <filename>работал на меня. Это не должно быть принятым ответом, ИМХО. git resetне.
harperville 27.02.2014 20:58:24
не можете использовать git resetдля сброса одного файла, вы получите ошибкуfatal: Cannot do hard reset with paths
slier 23.12.2014 17:11:59
Что Слиер сказал: вы не можете git reset --hard <commit hash> <filename>. Это ошибка с тем, fatal: Cannot do hard reset with paths.что сказал Мотти Стром: использованиеgit checkout <commit hash> <filename>
Hawkeye Parker 6.02.2015 05:36:26
git revert <hash>

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

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

5
17.12.2008 18:56:14

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

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

$ git checkout $A file

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

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

$ git revert $B

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

54
11.01.2009 08:13:39
Я сделал это, но тогда «файл журнала git» сказал бы, что я был на исходном коммите, HEAD. Казалось, что «Git Checkout» не удается. Тем не менее, состояние git показало, что файл действительно был изменен, и «git diff --staged file» покажет реальные изменения. Кроме того, «git status» показывает, что файл также изменился. Так что не используйте здесь «git log», чтобы отслеживать, какие файлы были изменены.
Frederick Ollinger 8.06.2018 18:35:11

Вот как это 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 checkout git rebase master

... проверить ветку изменений, которые вы хотите применить к 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. Без этого шага коммит ребаз не будет добавлен в master. Окончательный результат:

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

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

git branch -d <my branch>
32
29.04.2014 12:21:47

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

git checkout master~5 image.png

Это предполагает, что вы находитесь на masterветке, и версия, которую вы хотите, 5 коммитов назад.

91
1.06.2012 07:06:19

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

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

363
29.04.2014 12:22:45
В чем разница между этим ответом, который имеет --, и принятым, который не дает?
2rs2ts 9.10.2014 00:20:29
В git «-» перед списком файлов говорит git, что все последующие аргументы должны интерпретироваться как имена файлов, а не как имена веток или что-то еще. Иногда это помогает разобраться.
foxxtrot 9.10.2014 14:32:00
'-' - это не только соглашение git, но и то, что вы можете найти в различных местах командной строки * nix. rm -- -f(удалить файл с именем -f) кажется каноническим примером. Более подробно здесь
Hawkeye Parker 6.02.2015 05:49:24
Просто добавьте к тому, что сказал @HawkeyeParker, rmкоманда использует getopt (3) для анализа своих аргументов. getoptэто команда для анализа аргументов команды. gnu.org/software/libc/manual/html_node/Getopt.html
Devy 14.07.2015 18:11:41
@Honey Да, это то, что я имею в виду, и да, наверное, не совсем обычное. Я видел этот пример в разных местах, может быть, просто чтобы сделать его запоминающимся: rm -f, как известно, страшен / опасен. Но дело в том, что в * nix имя файла может начинаться с «-», и это приведет к путанице в различных интерпретаторах командной строки, которые, увидев «-», ожидают, что параметр команды будет следовать. Это может быть любой файл, начинающийся с '-'; например, "-mySpecialFile".
Hawkeye Parker 5.04.2017 20:35:50

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

git checkout [commit-ref] [filename]

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

105
23.05.2017 11:47:31

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

git checkout <commit hash> file

Затем внесите изменения:

git commit -a
61
25.08.2011 22:12:22

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

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

8
5.11.2012 04:25:28

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

cd <working copy>
git revert master

отменяет последний коммит, который, кажется, делает.

Ян

7
16.12.2011 03:40:53

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

git checkout HEAD file/to/restore
122
14.01.2012 06:15:35
В чем разница между этим (git checkout HEAD file / to / restore) и git reset --hard file / to / restore ???
Motti Shneor 26.01.2016 13:23:26
1) легче запомнить более общий способ 2) не беспокойтесь, нажав Enter перед вводом имени файла
Roman Susi 10.01.2017 19:03:07

git checkout ref | commitHash - filePath

например

git checkout HEAD~5 -- foo.bar
or 
git checkout 048ee28 -- foo.bar
10
26.09.2013 17:04:32

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

git checkout HEAD^1 path/to/file

или

git checkout HEAD~1 path/to/file

Затем просто подготовьте и зафиксируйте «новую» версию.

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

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

20
11.01.2014 00:29:50

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

git checkout eb917a1 YourFileName

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

git reset HEAD YourFileName
git checkout YourFileName

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

11
25.02.2014 14:01:20

git-aliases, awk и shell-функции на помощь!

git prevision <N> <filename>

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

git prevision -1 x/y/z.c

Как работает git prevision?

Добавьте следующее к вашему 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коммит-идентификатор для указанного файла.

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

22
22.01.2016 08:14:18

Здесь много предложений, в основном по направлениям 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работы)

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

git archive $revision $file | tar -x0 > $file
19
17.02.2018 23:05:02
Это хорошая альтернатива, если вы не уверены, какую версию коммита вы хотите, и вам нужно «посмотреть» без перезаписи вашего рабочего каталога.
wisbucky 16.02.2018 22:25:00

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

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

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

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

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

10
7.12.2016 14:43:49
Это должен быть одобренный ответ. Могу я предложить несколько упрощенную версию:git show -p <sha> path/to/file.ext|git apply -R
Amaury D 19.09.2019 13:49:10
вы можете использовать <sha>^!вместо<sha>^ <sha>
cambunctious 10.12.2019 20:57:13

Вот мой путь.

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

б) git -> Показать историю, найти предыдущий коммит, к которому я хочу вернуться. Получите commit_id (т.е. передайте хэш).

с) git checkout commit_id file_path

3
13.03.2017 08:15:36
Твой путь - это путь принятого ответа.
Uwe Allner 13.03.2017 08:33:07

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

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

Теперь скажите, что я что-то испортил в файле file.txtи хочу вернуться к предыдущему коммиту 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.

14
22.03.2017 21:33:50
Хорошо, так что я думаю, что шаги 1. и 2. являются взаимоисключающими: если abc1 - ваш последний коммит, нет необходимости в 2. и если после abc1 были другие коммиты, вы можете напрямую сделать 2.
Jean Paul 15.11.2017 10:58:32
отличный ответ. это должно быть # 1
user3089840 21.06.2018 23:24:59

Первая головка сброса для целевого файла

git reset HEAD path_to_file

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

git checkout -- path_to_file
24
4.04.2017 10:25:08
+1, хотя и не уверен в намерении сброса HEAD. Это может или не может быть необходимо. В моей ситуации я хотел вернуть только один конкретный файл к версии в репозитории (которая сохранила оставшиеся локальные изменения без изменений. Мне достаточно было
fkl 19.01.2018 23:56:20
Да, мне нужно только запустить 2-ю команду. Like -> shellhacks.com/git-revert-file-to-previous-commit
javaPlease42 30.05.2019 17:07:47

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

2
26.09.2017 01:48:14

Вы можете сделать это в 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 .

удачи

7
8.05.2018 10:26:21
разве это не отменяет ВСЕ изменения?
arcee123 29.10.2018 13:22:01
@ arcee123 Да, но последующий сброс отменяет отмену всех изменений. Проблема в том, что git-revertдействует только на весь репо, поэтому чтобы компенсировать это, мы должны отменить все остальное.
Timothy 5.02.2019 22:01:28
Я рекомендую использовать: 1. git revert --no-commit <commit_hash>2. git reset HEADЭто сохраняет дополнительный коммит и делает все изменения только в вашем рабочем каталоге.
Timothy 5.02.2019 22:04:03
Ответ @ greg-hewgill лучше и точнее. Этот паршивый и не должен использоваться.
Daniel Tranca 28.02.2019 16:27:03
Это именно то, что нужно для истинного возврата определенных файлов. Мне нужно было отменить изменения в нескольких файлах из более ранней фиксации, которая уже была отправлена ​​в удаленный репозиторий. Я отменил, сбросил и зафиксировал результат: git revert _oldcommit_ --no-commit git reset -- _unchanged1_ _unchanged2_ ... git commit -m "branch without changes to specific files"новая подсказка ветви отразила все изменения, кроме возвращенных файлов.
Suncat2000 21.03.2019 15:30:51

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

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

дерево с открытым исходным кодом

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

введите описание изображения здесь

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

вкладка состояния файла

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

введите описание изображения здесь

5
23.08.2018 09:53:27

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

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

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

7
24.01.2019 17:21:50