2015-08-19 5 views
7

Предположим, у меня есть файл a.txt. Однажды я удалил его, совершил и нажал.Git восстановить удаленный файл и сохранить историю файлов

На следующий день мне захотелось вернуть последнюю фиксацию, возвращая a.txt. Я пробовал использовать git revert, но когда я сделал git blame, все строки показывают возврат хэша. Исходная история вины теряется.

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

Спасибо!

+0

Вы имеете в виду, что вы не можете сделать -force push вверх по течению? – shengy

+2

Git не отслеживает историю файлов; он отслеживает историю всего корневого каталога. Поэтому восстановление истории файлов является проблемой при запросе просмотра истории, а не при возврате файла. – Nayuki

+0

@shengy Нет, я не могу – fushar

ответ

0

Вы можете сделать это, используя git reset вместо git revert. git reset сбрасывает новую фиксацию и проверку предыдущей фиксации. Это не рекомендуется, если вы уже нажали вверх.

NAME 
     git-reset - Reset current HEAD to the specified state 

SYNOPSIS 
     git reset [-q] [<tree-ish>] [--] <paths>... 
     git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] 
     git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>] 

DESCRIPTION 
     In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the 
     current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The 
     <tree-ish>/<commit> defaults to HEAD in all forms. 

Поскольку ты уже толкать:

  • Если у вас нет активных коллаборационистов, которые вытащили тот же день, используйте git reset и заставить толчок git push -f.
+0

Он уже удалил файл и нажал на восходящий поток, 'git reset' в этот момент не работает для него. – shengy

1

Run мерзавец вино с опцией -C указано три раза:

git blame -C -C -C 

Это вызывает git blame искать содержимое копируется из файлов в предыдущих фиксациях.

От the documentation for git blame:

-C|<num>|

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

<num> не является обязательным, но это нижняя граница числа буквенно-цифровых символов, которые Git должны обнаружить, как перемещение/копирование между файлов для того, чтобы связать эти строки с родителем фиксации. И значение по умолчанию - 40. Если задано более одного значения -C, вступает в силу аргумент <num> последних -C.

+0

Вы уверены, что это работает? Я пробовал что-то вроде 'git init'' echo "test"> a.txt "' 'git add a.txt'' git commit -m "Commit 1" '' echo "foobar" >> a.txt' 'git add a.txt '' git commit -m "Commit 2" '' git rm a.txt' 'git commit -m" Commit 3 "' 'git revert HEAD'' git blame -C -C -C a.txt' и обе строки показывают revert commit ... – fushar

+0

@fushar Я уверен, что вам нужно больше одного слова для git, чтобы зарегистрировать, что вы что-то переехали. Документы говорят, что 40 символов - это минимум. Я отредактировал цитату в своем ответе чтобы быть более полным. – Ajedi32

+0

Я просто хотел показать, что ваше решение не работает в простейшем примере. На самом деле это тоже не работает на моем реальном проекте (мой удаленный файловый контент намного больше 40, конечно). - 'git blame -C1 -C1 -C1 a.txt', к сожалению, также не работает для примера' a.txt'. – fushar

2

Вы CAN сделать это!Вот как это делается:

  1. Запустите новую ветку от фиксации, предшествующей удалению, которое вы хотите отменить.
  2. Объединить оскорбительные изменения с помощью git merge <sha> -s ours.
  3. Если совершить изменения имели помимо удаления, которые вы хотите сохранить:
    1. Повторно изменения в вашей рабочей копии с git diff <sha>^..<sha> | git apply.
    2. Отменить удаление (доступно много методов: git checkout -p может работать хорошо для вас).
  4. Слейте эту ветку обратно в главную ветвь (например, мастер).

Это дает историю с двумя ветвями; один, в котором файл был удален, и тот, в котором он никогда не был удален. В результате git может отслеживать историю файлов, не прибегая к героике, такой как -C -C -C. (Фактически, даже с -C -C -C, файл не «восстановлен», потому что то, что git видит, это то, что новый файл был создан как копия ранее существовавшего файла. С помощью этой техники вы повторно вводите тот же файл.)

+0

Работает как лечить, и я узнал кое-что сейчас, спасибо @Matthew! Мое дело было довольно сложным, и мне нужно было немного почитать «git checkout -p», но даже на частично оскорбительном коммите со смешанными изменениями этот подход в конечном итоге работал именно так, как мне было нужно. – bossi

Смежные вопросы