Як я можу скинути або повернути файл до певної версії?


4511

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

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


11
Після повернення не забудьте --cachedперевіряти git diff. посилання
Джеффрі Хейл

5
Я знайшов ваше запитання, коли я гуглив свою. Але після того, як я прочитав рішення, я перевірив свій журнал і з’ясував, що я вніс ти зміни в якості окремої фіксації, тому я здійснив повернення git до цього фіксації, і все інше залишилося так, як я цього хотів. Не рішення, просто інший спосіб зробити це іноді.
sudo97

Відповіді:


6130

Припустимо, що хеш потрібного вам зобов'язання 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

Як зауваження, мені завжди було незручно з цією командою, оскільки вона використовується як для звичайних речей (змінюється між гілками), так і для незвичайних, руйнівних речей (відхилення змін у робочому каталозі).


12
@shadowhand: Чи є спосіб змінити це, тож це версія відразу після цього?
aliteralmind

16
@aliteralmind: Ні, на жаль, ярлик ярликів історії Git йде лише назад.
Грег Хьюгілл

46
Якщо ви збираєтесь використовувати назву гілки для abcde (наприклад develop), вам захочеться git checkout develop -- file/to/restore(зверніть увагу на подвійний тире)
Охад Шнайдер

8
@aliteralmind: Насправді, так, є спосіб зробити це: "git log - зворотний -1 --ancestry-path yourgitrev..master", а потім скористайтеся відповідними параметрами, щоб просто отримати git rev. --ancestry-path "прокреслить лінію" між двома комітами, а -1 відобразить лише одну версію, а - reverse забезпечить, що перший запис, випущений, є найстарішим.
Кріс Когдон

6
Особисто мені здається, що HEAD ^ легше набрати, ніж HEAD ~ 1 :)
juzzlin

606

Ви можете швидко переглянути зміни, внесені у файл, використовуючи команду diff:

git diff <commit hash> <filename>

Потім для повернення певного файлу до цього комітету скористайтеся командою скидання:

git reset <commit hash> <filename>

Можливо, вам доведеться використовувати цю --hardопцію, якщо у вас є місцеві модифікації.

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

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

Потім ви можете відновити це відносно основного рядка, коли ви готові об'єднати ці зміни:

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

7
Команда 'git checkout <commit hash>' повернула мені старішу версію проекту саме в цьому, за яким я шукав спасибі Chris.
vidur punj

48
Для відновлення файл git checkout <commit hash> <filename>працював для мене краще, ніжgit reset
Motti Strom

3
Я хотів отримати ранню версію одного файлу, оскільки я перезаписав 150 рядків із неправильно вибраною копією / вставкою. git checkout <commit hash> <filename>працював на мене. Це не повинно бути прийнятою відповіддю, ІМХО. git resetне.
harperville

24
не git resetвдалося скинути один файл, ви отримаєте помилкуfatal: Cannot do hard reset with paths
slier

13
Що Сільє сказав: не можна git reset --hard <commit hash> <filename>. Це призведе до помилки з тим, fatal: Cannot do hard reset with paths.що сказав Мотті Стром: використанняgit checkout <commit hash> <filename>
Хокі Паркер

366

Ви можете використовувати будь-яке посилання на git-коміт, включаючи SHA-1, якщо це найбільш зручно. Справа в тому, що команда виглядає так:

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


22
Чим відрізняється ця відповідь --від прийнятої, яка не відповідає?
2rs2ts

80
У git, '-' перед списком файлів повідомляє git, що всі наступні аргументи слід інтерпретувати як назви файлів, а не як назви гілок чи щось інше. Іноді це корисний розбірник.
foxxtrot

49
"-" - це не тільки умова git, але й те, що ви знайдете в різних місцях у командному рядку * nix. rm -- -f(видаліть файл з назвою -f), здається, є канонічним прикладом. Більш докладно тут
Hawkeye Parker

7
Просто додайте до того, що сказав @HawkeyeParker, rmкоманда використовує getopt (3) для розбору своїх аргументів. getoptце команда для розбору аргументів команди. gnu.org/software/libc/manual/html_node/Getopt.html
Devy

2
@Honey Так, це я маю на увазі, і так, мабуть, зовсім не часто. Я бачив цей приклад у різних місцях, можливо, просто для того, щоб зробити його незабутнім: rm -f, як відомо, є страшним / небезпечним. Але суть полягає в тому, що в * nix ім'я файлу може починатися з «-», і це заплутає різні інтерпретатори командного рядка, які, побачивши «-», очікують, що наступний варіант команди. Це може бути будь-який файл, починаючи з '-'; наприклад, "-mySpecialFile".
Хокі Паркер

287
git checkout -- foo

Це повернеться fooдо HEAD. Ви також можете:

git checkout HEAD^ foo

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


12
Я б запропонував використовувати синтаксис, git checkout -- fooщоб уникнути помилок, якщо fooце щось особливе (наприклад, каталог або називається файл -f). Якщо ви не впевнені, завжди додайте всі файли та каталоги за допомогою спеціального аргументу --.
Мікко Ранталайнен

8
Додаткова примітка до коментаря Мікко: --це не команда git і не особлива для git. Це вбудований bash для позначення кінця параметрів команд. Ви можете використовувати його і з багатьма іншими командами bash.
Матфей

14
@matthaeus також взагалі не характерний ні для bash, ні для оболонки. Це умова, реалізована в багатьох різних командах (і підтримується getopt).
Грег Хьюгілл

2
Ні, --це НЕ є вбудованим спеціальним словом в БАШЕЄВ. Але це загальна конвенція, яка підтримується багатьма аналізаторами командного рядка і використовується багатьма CLI, включаючи git.
Еміль Лундберг

123

А для повернення до останньої вчиненої версії, яка найчастіше потрібна, ви можете скористатися цією більш простою командою.

git checkout HEAD file/to/restore

2
Яка різниця між цим (git checkout HEAD файл / до / відновлення) та git reset - твердий файл / до / відновлення ???
Мотті Шноор

2
1) легше запам’ятати більш загальний спосіб 2) не хвилюйтесь натискати Enter перед введенням імені файлу
Роман Сузі

105

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

git checkout [commit-ref] [filename]

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


91

Якщо ви знаєте, скільки комісій потрібно повернути назад, ви можете скористатися:

git checkout master~5 image.png

Це передбачає, що ви на masterгілці, а потрібна версія 5 повертається назад.


80

Я думаю, що я його знайшов .... від http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html

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

Починати з:

$ git log

який показує вам список останніх комітетів та їх хеші SHA1.

Далі введіть:

$ git reset --hard SHA1_HASH

щоб відновити стан заданої фіксації та назавжди видалити всі нові зобов’язання із запису.


24
Git ніколи нічого не знімає. Ваші старі зобов’язання все ще є, але, якщо на них немає кінця гілки, вони більше недоступні. git reflog все одно буде показувати їх, поки ви не очистите свій сховище за допомогою git-gc.
Бомбе

1
@Bombe: Дякую за інформацію. Я перевірив стару версію файлу. Прочитавши ваш коментар, я зміг скористатися "gitref" для пошуку часткового хешу SHA1 і за допомогою "checkout" повернутися до останньої версії. Інші користувачі git можуть вважати цю інформацію корисною.
Вінстон С. Ян

4
можливо, після цьогоgit push --force
bshirley

4
Якщо у вас залишилися зміни, ви втратите їх, якщо скиньте git
Hard

5
@Bombe - "Git ніколи нічого не видаляє. Ваші старі зобов’язання все ще є, але, якщо на них немає кінця гілки, вони більше недоступні". - але такі зобов’язання обрізаються через певний встановлений час, тому "Git ніколи нічого не знімає" не відповідає дійсності.
Bulwersator

61

Це працювало для мене:

git checkout <commit hash> file

Потім введіть зміни:

git commit -a

54

Ви повинні бути обережними, коли говорите "відкат". Якщо у вас була одна версія файлу у фіксації $ A, а пізніше внесені дві зміни в дві окремі коміти $ B і $ C (тому ви бачите третю ітерацію файлу), і якщо ви скажете " Я хочу відкотитися до першого ", ти це справді маєш на увазі?

Якщо ви хочете позбутися змін як другої, так і третьої ітерацій, це дуже просто:

$ git checkout $A file

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

З іншого боку, те, що ви мали на увазі - позбутися зміни, внесеної другою ітерацією (тобто введення $ B), при цьому зберігаючи те, що фіксація $ C зробила у файлі, ви хочете повернути $ B

$ git revert $B

Зауважте, що той, хто створив фіксацію $ B, може бути не дуже дисциплінований і, можливо, здійснив цілком неспоріднені зміни в тій самій фіксації, і це відновлення може торкнутися файлів, окрім файлів, на яких ви бачите ображаючі зміни, тому ви можете ретельно перевірити результат після цього тому.


Я зробив це, але тоді "файл журналу git" сказав би, що я був на початковій комісії, HEAD. Здавалося, що "git checkout" провалився. Однак статус git показав, що файл насправді змінено, і "git diff - стадіонний файл" буде показувати фактичні зміни. Також "git status" показав, що файл також змінився. Тому не використовуйте тут "git log", щоб відстежувати, які файли змінилися.
Фредерік Оллінгер

37

Забавно, 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

26
абоgit checkout -- foo
knittl

32

Ось як 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>

26

Станом на git v2.23.0 є новий метод відновлення git, який повинен брати на себе частину того, що git checkoutвідповідав (навіть прийнята відповідь згадує, що git checkoutдосить заплутано). Перегляньте основні моменти змін у блозі github .

Типова поведінка цієї команди полягає у відновленні стану робочого дерева із вмістом, що надходить із sourceпараметра (який у вашому випадку буде хешем фіксації).

Отже, виходячи з відповіді Грега Х'югілла (якщо припустити, що хеш-коміт є c5f567) команда виглядатиме так:

git restore --source=c5f567 file1/to/restore file2/to/restore

Або якщо ви хочете відновити вміст одного комітету до c5f567:

git restore --source=c5f567~1 file1/to/restore file2/to/restore

24

Перша скидання головки для цільового файлу

git reset HEAD path_to_file

Другий замовлення цього файлу

git checkout -- path_to_file

4
+1, хоча і не впевнений у намірі скинути HEAD. Він може бути, а може і не знадобитися. У моїй ситуації я хотів повернути лише один конкретний файл до версії в сховищі (що зберігає залишилися локальні зміни недоторканими. Для мене достатньо було виконати другий крок вище
fkl

Так, мені потрібно виконати лише 2-ю команду. Як -> shellhacks.com/git-revert-file-to-previous-commit
javaPlease42

22

git-псевдоніми, awk та shell-функції на допомогу!

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ідентифікатор комісії для вказаного файлу.

По суті, все, що можна було б зробити вручну в цій ситуації,
загорнувшись в один прекрасний, ефективний псевдонім git - 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.
коппор

20

У випадку, якщо ви хочете повернути файл до попередньої фіксації (і файл, який ви хочете відновити, вже скоєний), ви можете використовувати

git checkout HEAD^1 path/to/file

або

git checkout HEAD~1 path/to/file

Потім просто поставити і зробити "нову" версію.

Озброївшись знаннями про те, що комісія може мати двох батьків у разі злиття, ви повинні знати, що HEAD ^ 1 - перший з батьків, а HEAD ~ 1 - другий з батьків.

Або буде працювати, якщо на дереві є лише один з батьків.


19

Тут багато пропозицій, найбільше за змістом 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

1
Це приємна альтернатива, якщо ви не впевнені, яку версію фіксації ви хочете, і вам потрібно "заглянути" навколо, не перезаписуючи свій робочий каталог.
wisbucky

18

Однак зауважте, що це 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

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

У мене є фіксація, 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.


2
Гаразд, тому я думаю, що кроки 1. і 2. є взаємовиключними: якщо abc1 - ваш останній фільтр, немає потреби в 2. а якщо після abc1 були інші комісії, ви можете безпосередньо зробити 2.
Jean Paul

13
  1. Git поверне файл до певної комісії
git checkout Last_Stable_commit_Number -- fileName

2.Git поверне файл до певної гілки

git checkout branchName_Which_Has_stable_Commit fileName

11

Щоб перейти до попередньої версії файлу файлу, отримайте номер фіксування, скажімо, тоді eb917a1

git checkout eb917a1 YourFileName

Якщо вам просто потрібно повернутися до останньої зафіксованої версії

git reset HEAD YourFileName
git checkout YourFileName

Це просто переведе вас до останнього скоєного стану файлу



10

Багато відповідей тут стверджує, що вони використовуються 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(конфліктом).


Це має бути схвалена відповідь. Я можу запропонувати трохи спрощену версію:git show -p <sha> path/to/file.ext|git apply -R
Amaury D

ви можете використовувати <sha>^!замість<sha>^ <sha>
cambunvolu

8

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

Примітка. Не забудьте ввести хеш перед останнім. Останній хеш вказує на ваше поточне положення (HEAD) і нічого не змінює.


7

Очевидно, що хтось або повинен написати розбірливу книгу про git, або git потрібно краще пояснити в документації. Зіткнувшись із цією ж проблемою, я здогадався про це

cd <working copy>
git revert master

скасує останнє зобов'язання, яке, здається, робиться.

Ян


7

Це можна зробити в 4 етапи:

  1. скасуйте всю комісію з файлом, який ви хочете спеціально відновити - це створить нову комісію для вашої гілки
  2. м'яке скидання, яке виконує - видаляє фіксацію та переміщує зміни до робочої області
  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 .

Щасти


це не поверне ВСІ зміни?
arcee123

1
@ arcee123 Так, але подальше скидання скасовує відновлення всіх змін. Проблема полягає в тому, що git-revertпрацює лише на весь репо, тому для компенсації нам потрібно скасувати все інше.
Тимофій

2
Я рекомендую використовувати: 1. git revert --no-commit <commit_hash>2. git reset HEADЦе економить додатковий комітет, який плаває навколо, і робить усі зміни лише у вашому робочому каталозі.
Тимофій

Відповідь @ greg-hewgill краще та помітити. Цей паршивий і його не слід використовувати.
Даніель Транка

Це саме те, що потрібно для справжнього відновлення конкретних файлів. Мені потрібно було скасувати зміни до декількох файлів з попередньої версії, які вже були висунуті у віддалений сховище. Я повернув, скинув і здійснив результат: git revert _oldcommit_ --no-commit git reset -- _unchanged1_ _unchanged2_ ... git commit -m "branch without changes to specific files"Нова порада відділення відображала всі зміни, крім повернених файлів.
Suncat2000

7

Це дуже простий крок. Файл оформлення замовлення в потрібний ідентифікатор виконувати, тут один ідентифікатор фіксації раніше, а потім просто змінити git fix і ми закінчили.

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

Це дуже зручно. Якщо ми хочемо донести будь-який файл до будь-якого попереднього ідентифікатора фіксації у верхній частині фіксації, ми можемо це легко зробити.


5
git revert <hash>

Поверне дану комісію. Це здається, що ви думаєте, що git revertвпливає лише на останні поступки.

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


5

якщо ви створюєте неправильний файл у своїх останніх зобов'язаннях, дотримуйтесь інструкцій:

  1. дерево з відкритим вихідним кодом, змініть цю команду

дерево з відкритим кодом

  1. змінити рядки і виявити твою фіксацію, що неправильний файл, надісланий як фіксація

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

  1. ви можете побачити список своїх змін у цій комісії список файлів у вихідному дереві
  2. виберіть його та натисніть на ... кнопки праворуч ... натисніть на зворотній файл
  3. тоді ви можете побачити його на вкладці стану файлу внизу ліворуч, а потім натисніть на провал:

вкладка стану файлу

  1. відкрийте свій візуальний код студії та поверніть назад, виконавши видалені файли
  2. після всіх їх результатів ви можете бачити результати останньої фіксації у вихідному дереві

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.