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

У меня есть проект на git. В моем проекте есть такие файлы, как:

file1.js
file2.html
file3.js
file4.css
file5.html
file6.jpg
file7.html
file8.js
file9.css

Я сделал git -rm имя файла для всех файлов и зафиксировал их, пока не остался с

file1.js
file2.html

Мне нужно вернуть мой файл6.jpg

Как мне получить file6.jpg, чтобы в моем репо было

file1.js
file2.html
file6.jpg

person Mike    schedule 05.04.2013    source источник
comment
вы сделали один коммит для всех удалений?   -  person niculare    schedule 05.04.2013
comment
затем выполните проверку при фиксации, прежде чем вы удалите файл 6.jpg и удалите другие файлы, кроме 1, 2 и 6.   -  person niculare    schedule 05.04.2013


Ответы (4)


git checkout HEAD~N -- file6.jpg

Где N — количество коммитов назад во времени, когда присутствовал file6.jpg.

person Gabriele Petronella    schedule 05.04.2013
comment
Я думаю, что это имеет смысл, похоже, я вернул файл, но он не появится на github.com. Я также сделал git push origin master - person Mike; 05.04.2013
comment
вам нужно зафиксировать его после оформления заказа, прежде чем нажать - person Gabriele Petronella; 05.04.2013
comment
Спасибо. Это сработало. Если бы я удалил все файлы одним коммитом. Какая альтернатива в таком случае? - person Mike; 06.04.2013
comment
Вы можете либо поставить HEAD~1, чтобы вернуться к одному коммиту, либо HEAD^, что является синонимом. - person Gabriele Petronella; 06.04.2013

git checkout может быть самым простым вариантом для одного файла.

  1. Используйте git log для просмотра истории коммитов. Найдите хэш коммита до удаления рассматриваемого файла. Например:

    commit 5faff7e3f74c3408985acecd1dbb90feeb7b1d75 <--- "hash"
    Author: Nick Tomlin <[email protected]>
    Date:   Fri Apr 5 11:34:03 2013 -0500
    
  2. затем запустите git checkout <hash> path/to/file6.jpg, заменив <hash> строкой символов выше (обычно вам нужны только последние 5 или около того, но давайте просто используем их все сейчас, чтобы быть в безопасности. Если вы находитесь в каталоге, в котором находится file6.jpg, вы можете просто сделать git checkout <hash> file6.jpg

Это более длинный подход к доступу к коммиту, можно просто использовать HEAD~6, но я обычно предпочитаю его, когда ссылаюсь на коммиты, которые находятся дальше, чем HEAD~3. Легче сослаться на неправильную фиксацию, используя относительную ссылку ~, и я в конечном итоге просматриваю свой журнал, чтобы выяснить, какой именно коммит мне все равно нужен :).

person Nick Tomlin    schedule 05.04.2013
comment
как найти хэш. извините, я новичок в git. - person Mike; 05.04.2013
comment
Спасибо, это сработало, однако подход Габриэля тоже сработал. Знаете, в чем разница между этими двумя подходами? Если бы я удалил и зафиксировал все файлы одним коротким. как вернуть нужный файл. - person Mike; 06.04.2013
comment
@Mike, они выполняют одно и то же действие; Габриэль - это просто другой способ ссылки на фиксацию. Я обновил свой ответ, чтобы объяснить это подробнее. Вы можете использовать тот же метод checkout, если все файлы были удалены за одну фиксацию. Вам просто нужно будет сослаться на фиксацию, предшествовавшую той, в которой вы удалили файлы. Для более чем одного файла, вероятно, лучше использовать что-то вроде git revert ссылка, но это не так просто; просто хорошо :) - person Nick Tomlin; 06.04.2013

git checkout $(git log -1 --pretty='%h' -- <path>)^ -- <path>

Разбивка

Использование git log для поиска последней фиксации, влияющей на нужный файл

$(git log -1 --pretty='%h' -- <path>)

  • Запускает команду git log, используя форматирование --pretty, которое просто показывает хэш.
  • Использует разделитель -- для явного указания файла, а не ссылки фиксации.
  • Далее следует путь и имя файла, который мы хотим получить.
  • Все это завернуто в $(), чтобы мы могли встроить его в другую команду git, как переменную.
  • Это вернет фиксацию, в которой данный файл был удален.

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

Использование git checkout для получения файла в том виде, в котором он был в данной фиксации

git checkout <ref>^ -- <path>

  • Запускает git checkout, используя коммит и указывая путь.
  • Когда указан путь, git просто воссоздает состояние этого пути по предоставленной ссылке.
  • Добавляя морковь ^ к ссылке, мы фактически указываем на непосредственного предка.
  • Нам нужен непосредственный предок, потому что фиксация, которую мы получаем из журнала, не будет иметь файла, поскольку это фиксация, в которой файл был удален.

Соберите все это вместе, и вы извлекаете файл в том состоянии, в котором он был в коммите непосредственно перед тем, как этот файл был удален. Если вы запустите это на файле, который не был удален, он просто отменит любое изменение, которое было последним сделано в этом файле.

Псевдоним

git config --global alias.unrm '!COMMIT=$(git log -1 --pretty='%h' -- "$1"); git checkout $COMMIT^ -- "$1"'

Я создал из этого псевдоним под названием unrm, как в un-remove. Если вы запустите приведенную выше команду, с этого момента вам просто нужно запустить..

git unrm <path>

Редактировать: я добавил отзыв к команде.

git config --global alias.unrm '!COMMIT=$(git log -1 --pretty='%h' -- "$1"); git checkout $COMMIT^ -- "$1"; echo "File: $1, was restored from commit $COMMIT"; git show -s $COMMIT'

Теперь он информирует вас о том, что он сделал, и показывает коммит, из которого он восстановил файл.

person eddiemoya    schedule 06.04.2013

Предполагая, что file6.jpg был ранее зафиксирован, вы можете получить все версии file6.jpg в своем репозитории git, выполнив:

git rev-list --objects --all | grep file6.jpg

Затем вы можете восстановить файл, используя

git cat-file {sha} > file6.jpg

Добавьте файл и зафиксируйте.

См. также этот ответ, в котором рассказывается о том, как получить все объекты из репозитория git: https://stackoverflow.com/a/7350019

и этот сайт о внутреннем устройстве объекта git: http://git-scm.com/book/en/Git-Internals-Git-Objects

person Charlie    schedule 05.04.2013
comment
это действительно самый сложный способ, который я когда-либо видел для такой простой задачи. - person Gabriele Petronella; 06.04.2013