Питання Знайдіть і відновіть видалений файл у сховищі Git


Скажімо, я перебуваю в сховищі Git. Я видалю файл і здійснити цю зміну. Я продовжую працювати і робити ще кілька команд. Потім я вважаю, що мені потрібно відновити цей файл.

Я знаю, що можу перевірити файл за допомогою git checkout HEAD^ foo.bar, але я не знаю, коли цей файл був видалений.

  1. Який найшвидший спосіб знайти фікс, який видаляє певне ім'я файлу?
  2. Який найпростіший спосіб повернути цей файл у мою робочу копію?

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


2386
2018-06-04 22:40


походження


$ git checkout deletedFile, ніхто чітко не заявив про це ?! Відповісти на заголовок для майбутніх Googlers ... - hhh
Зауважте, що попередній коментар відповідає на питання в заголовку, а не в тілі - це включає виявлення коли файл був знищений. - avdgaag
Щоб знайти файл, який було скоєно, видалено в: git log --diff-filter=D -- path/to/file - titaniumdecoy
Пов'язані: Як ви відкидаєте непоправні зміни в GIT?.
@ ххх git checkout deletedFile буде відновлено deletedFile якщо воно було видалено, але це видалення ще не було встановлено чи скоєно. Це не те, про що питає тут питання; це питання полягає в тому, як відновити файл, чий видалення було вчинено багатьма компаніями, які здійснювали це попереднє. - Mark Amery


Відповіді:


Знайдіть останню фіксацію, яка вплинула на вказаний шлях. Оскільки файл не входить в HEAD, це зобов'язання повинно було його видалити.

git rev-list -n 1 HEAD -- <file_path>

Потім перевірте версію на фіксації раніше, використовуючи карет (^) символ:

git checkout <deleting_commit>^ -- <file_path>

Або в одній команді, якщо $file це файл, про який йде мова.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Якщо ви використовуєте zsh та включили параметр EXTENDED_GLOB, символ caret не спрацює. Ви можете використовувати ~1 замість цього.

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"

2725
2017-07-11 07:12



Хитрість полягає в тому, щоб перевірити копію ПЕРЕД, використовуючи суфікс ^. Дякую. - Christian Oudard
Що за кінець? - ranman
@Ранман: Це означає "перший батько". - CB Bailey
З командного рядка windows я отримав помилку. error: pathspec <filename> did not match any file(s) known to git.. Рішенням було використовувати git bash. - donturner
@zoras zsh це власне розширення на "^", я вважаю, але ви можете використовувати альтернативний синтаксис "~ 1": git checkout <deleting-commit>~1 -- <file-path>  ~ X дозволяє вказати X, що робить зобов'язання перед вказаною фіксацією, тому ~ 1 - це commit до, ~ 2 - це два, що виконує раніше, і т.д. - Nils Luxton


  1. Використовуйте git log --diff-filter=D --summary щоб отримати всі зобов'язання, що видаляли файли та видалені файли;
  2. Використовуйте git checkout $commit~1 filename відновити видалений файл.

Де $commit це значення зобов'язання, яке ви виявили на кроці 1, наприклад e4cf499627


724
2018-06-04 23:10



Цікаво, що означає ~ 1? - tommy chheng
@tommy - тильда специфікації дасть вам n-й онук названої фіксації. Побачити book.git-scm.com/4_git_treeishes.html для більш детальної інформації. - Robert Munteanu
це, безумовно, найпростіший і інтуїтивно зрозумілий підхід. git log -- *PartOfMyFileName*. Дякую за $commit~1 - bgs
в git checkout $commit~1 filename Синтаксис ідеально підходить для окремих файлів, а також працює для цілих каталогів. тобто: відновити всі видалені зображення в ./images від sha 12345: git checkout 12345~1 images. дякую за цю відповідь! - noinput
@ Алексар $commit~1 означає, що ви повинні додати назву фіксації. Щось на зразок 1d0c9ef6eb4e39488490543570c31c2ff594426c де $commit є - Eugene


Щоб відновити всі ці видалені файли в папці, введіть таку команду.

git ls-files -d | xargs git checkout --

302
2017-12-02 06:11



Звідки взяти файли? Я не бачу змін. - William Grand
Це, мабуть, найпростіший спосіб. Його збочене, як важко git зробив навіть найпростіше завдання. - jww
що означає -- ? - Tebe
git checkout - [файл] поверне зміни в [file]. Труба замінить [файл] на ім'я видалених файлів. - Manu
The ls-files Під-команда зручна, але, здається, не працює для файлів, які були видалені git rm тобто поставили, не кажучи вже про здійснені, про що запитував О.П. - MarkHu


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

git checkout HEAD -- path/to/file.ext


100
2018-04-10 00:03



Дякую. Це працює для мене. Відновити файл, який я ще не внесли зміни. - Hua Zhang
Це найпростіше і найкраще. - SmallChess


Якщо ти божевільний, скористайся git-bisect. Ось що робити:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

Настав час запустити автоматичний тест. Команда оболонки '[ -e foo.bar ]' повернемо 0, якщо foo.bar існує, і 1 в іншому випадку. "Запустити" команду git-bisect буде використовувати бінарний пошук, щоб автоматично знаходити перший фікс, де тест не вдається. Він починається наполовину за заданим діапазоном (від хорошого до поганого) і скорочується наполовину на підставі результату зазначеного тесту.

git bisect run '[ -e foo.bar ]'

Тепер ви перебуваєте на фіксації, який видалив його. Звідси ви можете повернутися до майбутнього і використовувати git-revert щоб скасувати зміну

git bisect reset
git revert <the offending commit>

або ви можете повернутися назад до однієї фіксації та вручну перевірити збиток:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .

82
2018-06-04 22:46



Не могли б ви детально розібратися git bisect run '[ -e foo.bar ]'? - avdgaag
Ви також можете використовувати добре і погано вручну, якщо це те, що не можна перевірити автоматично. Дивіться сторінку "бішек". - Josh Lee
Це не найпростіше рішення, але воно досить вражає. Дякую за написання. - avdgaag
@ avggaag the git bisect run говорить Gіt, щоб автоматизувати розподіл, запустивши команду за назвою "run", де команда повинна повернутись 0 для good версія (див git help bisect для подробиць). The '[ -e foo.bar ]' є стандартним виразом для тестування, якщо файл foo.bar існує (реалізація зазвичай знаходиться у файлі /usr/bin/[ яка зазвичай тісно пов'язана /usr/bin/test), і одиничні квантові позначки використовуються для того, щоб створити це як єдиний аргумент командного рядка. - Mikko Rantalainen


Мій новий улюблений псевдонім на основі бонііііс відповісти (виправданий), і моя власна відповідь про "Передайте аргумент команді псевдоніму Git":

git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'

Я загубив файл, помилково видалений кількома видами роботи?
Швидко:

git restore my_deleted_file

Криза відвернулася.


Роберт Дейлі пропонує в коментарях наступний псевдонім:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"

І джаган додає в коментарях:

Для налаштування псевдоніму з командного рядка я використав цю команду:

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 

61
2018-02-17 15:33



Це відновлює всю фіксацію, а не лише запитуваного файлу. - Daniel Bang
Ось мій псевдонім, чудово працює: restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1" - void.pointer
@RobertDailey Це чудово виглядає! Я включив ваш псевдонім у відповідь для більшої видимості. - VonC
git: "restore" - це не команда git. - resultsway
Для налаштування псевдоніму з командного рядка я використав цю команду: git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" - jegan


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

Перерахуйте всі повноваження для цього файлу.

git log -- path/to/file

Остання копія (найпотужніша) - це той, що видаляє файл. Отже, вам потрібно відновити другий, щоб зробити останню фіксацію.

git checkout {second to last commit} -- path/to/file

42
2018-02-27 01:50



Так. Це було правильне рішення для мене! Простий та чіткий - Fabrizio Bertoglio
Просто використовував це рішення, і для видалення не було ніяких зобов'язань. Мені вдалося відновити файл за допомогою останнього посередника. - Adam
+10 для second to last commit роз'яснення! - colminator
Чи не буде останній зобов'язаний (колишній зобов'язання до видалення) містити найновішу версію видаленого файлу? Second-to-last (здійснення до попередньої відданості видаленню) може бути безнадійно застарілим. - Suncat2000
Це перше рішення, яке я бачив, досить просто, що мені не доведеться повернутися сюди, щоб знайти його наступного разу. Може бути. - Eloff