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

1275

Когда-то в моем проекте был файл, который я бы хотел получить.

Проблема: я понятия не имею, когда я удалил это и по какому пути это было.

Как я могу найти коммиты этого файла, когда он существовал?

Педро Роло
источник
Подобный вопрос здесь: stackoverflow.com/questions/7093602/…
eckes
3
Возможный дубликат Find, когда файл был удален в Git
Dan Dascalescu
13
Ответы здесь более полезны для меня, чем ответы в дубликатах .
Фелипе Альварес
5
согласился ... независимо от дубликатов ... они не появлялись в поиске Google ... этот сделал ... надеюсь, мы перестанем тратить время на погоню за дубликатами ... только время и алгоритм Google будет скажи какой вопрос самый лучший.
Тим Боланд,

Ответы:

1601

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

git log --all --full-history -- "**/thefile.*"

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

git log --all --full-history -- <path-to-file>

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

git show <SHA> -- <path-to-file>

Или восстановите его в рабочую копию с помощью:

git checkout <SHA>^ -- <path-to-file>

Обратите внимание на символ вставки ( ^), который получает извлечение до идентифицированного, потому что в момент <SHA>фиксации файл удаляется, нам нужно посмотреть предыдущий коммит, чтобы получить содержимое удаленного файла.

янтарный
источник
2
Попробуйте использовать относительный путь вместо абсолютного (если вы еще этого не сделали).
Янтарная
63
Что делать, если вы не знаете точный путь? Все, что вы знаете, это имя файла?
priestc
17
@PedroMorteRolo не git log -- <path>будет выводить, когда вы находитесь на ветке, в которой файл никогда не существовал. Вы должны всегда использовать git log --all -- <path>, чтобы убедиться, что вы не пропустите изменения, которые произошли в других ветках. Команда git log -- <path>может быть очень опасной, если у вас более одной ветви и вы склонны забывать пути и ветви (как я), а также опасно, если вы работаете с другими разработчиками.
варенье
4
@Amber, подумайте над добавлением --all(спасибо Филиппу ) к вашему git logответу, чтобы люди не пропустили изменения и файлы в других ветках. Это спасло бы забывчивых людей, таких как я, от горя.
вар
3
Как указано в ответе ниже, восстановление файла должно быть git checkout <SHA>^ -- <path-to-file>(обратите внимание на символ ^), потому что в момент фиксации <SHA> файл удаляется, нам нужно посмотреть предыдущий коммит, чтобы получить содержимое удаленного файла
kipelovets
393

Получить список удаленных файлов и скопировать полный путь к удаленному файлу

git log --diff-filter=D --summary | grep delete

Выполните следующую команду, чтобы найти идентификатор фиксации этого коммита и скопировать идентификатор коммита

git log --all -- FILEPATH

Показать разницу удаленного файла

git show COMMIT_ID -- FILE_PATH

Помните, что вы можете записать вывод в файл, используя >как

git show COMMIT_ID -- FILE_PATH > deleted.diff
Фатих Ацет
источник
1
Хотя я нашел путь с помощью первого шага, второй шаг выдает эту ошибку: unknown revision or path not in the working tree.
jvannistelrooy
6
Чтобы увидеть хеши коммитов вместе с удалениями, вы можете сделатьgit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Крис Миддлтон
1
Шаг 2 ничего не возвращает. Есть идеи, почему это может произойти? Мое имя файла правильное.
Денис Княжев
2
Чтобы найти объединение трех в одну функцию, добавьте это в ваш .bashrc или .zshrc: git-grep-latest(){ result_path=$(git log --diff-filter=D --summary | grep $1 | head -1 | awk '{print $4;}'); latest_commit=$(git log --all -- $result_path | head -1 | awk '{print $2;}'); git show $latest_commit -- $result_path; }и теперь вы можете просто сделать:git-grep-latest some_text
randomor
1
@TylerJones, вы можете кормить что угодно с помощью Linux с помощью каналов - Google linux pipes... вам понравится.
Джон Хант
37

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

чтобы восстановить файл в git, используйте следующее (обратите внимание на знак '^' сразу после SHA)

git checkout <SHA>^ -- /path/to/file
Акшай Агарвал
источник
Я не понимаю, почему вы хотите ^. Файл находится в коммите с этим SHA ... почему вы хотите оттуда откатить еще один коммит?
Тони К.
19
Он находится в коммите с этим sha как «удаленный», что означает, что он все еще не существует. Вы должны пойти на коммит до этого, чтобы получить его обратно.
tandrewnichols
6
@tandrewnichols, что просто означает, что вы используете неверный коммит SHA - вы хотите коммит для той версии файла, которую вы хотите ... которая, вероятно, не та версия, в которой файл был удален.
Янтарь
6
@Amber и коммит, который вы хотите, вероятно, самый последний, до того как он был удален, отсюда и этот ответ.
Сэм Холдер
1
@AlexR: <SHA>~1должно работать так же, без необходимости заключать его в кавычки.
CodeManX
37

Предположим, вы хотите восстановить файл с именем MyFile, но не знаете его путь (или его расширение):

Prelim .: Избегайте путаницы, перейдя к корню git

Нетривиальный проект может иметь несколько каталогов с одинаковыми или одинаковыми именами.

> cd <project-root>
  1. Найди полный путь

    git log --diff-filter = D --summary | grep удалить | grep MyFile

    delete mode 100644 full/path/to/MyFile.js

full/path/to/MyFile.js путь и файл, который вы ищете.

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

    git log --oneline --follow - полный / путь / к / MyFile.js

    bd8374c Some helpful commit message

    ba8d20e Another prior commit message affecting that file

    cfea812 The first message for a commit in which that file appeared.

  2. Оформить заказ

Если вы выберете первый в списке коммит (последний в хронологическом порядке, здесь bd8374c), файл не будет найден, так как он был удален в этом коммите.

> git checkout bd8374c -- full/path/to/MyFile.js

`error: pathspec 'full/path/to/MyFile.js' did not match any file(s) known to git.`

Просто выберите предыдущий (добавить каретку) коммит:

> git checkout bd8374c^ -- full/path/to/MyFile.js
Калаф
источник
3
Это намного яснее, чем принятый ответ
Пуян Ходабахш
для консоли Windows (cmd), используйте find вместо grep в шаге 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"И шаг 3 , обратите внимание на кавычки вокруг хеша:git checkout "bd8374c^" -- full/path/to/MyFile.js
user5542121
30

@ Янтарь дал правильный ответ! Еще одно дополнение, если вы не знаете точный путь к файлу, вы можете использовать подстановочные знаки! Это сработало для меня.

git log --all -- **/thefile.*
Петур Собев
источник
4
@PedroMorteRolo Хм. Я не знаю, что я думаю о копировании существующего ответа в голосующий сверху: / Этот ответ тоже был полезен сам по себе; upvote, возможно, было достаточно?
Clément
1
Это не находит файл, если он находится в корне проекта (протестировано в Cygwin).
Вортварт
19

Ниже приведена простая команда, в которой пользователь dev или git может передать имя удаленного файла из корневого каталога репозитория и получить историю:

git log --diff-filter=D --summary | grep filename | awk '{print $4; exit}' | xargs git log --all -- 

Если кто-нибудь, может улучшить команду, пожалуйста, сделайте.

Джейсон
источник
1
Круто, спасибо! Похоже, мой файл вообще никогда не существовал, но это отдельная проблема, гораздо более
убедитесь, что вы запускаете это из корневого каталога репозитория, если ваш файл кажется «отсутствующим»
samaspin
Спасибо @samaspin обновил ответ.
Джейсон
18

Попробуйте использовать одно из средств просмотра, например, gitkчтобы вы могли просмотреть историю, чтобы найти этот наполовину запомненный файл. (используйте gitk --allпри необходимости для всех филиалов)

Филип Окли
источник
4
Этот --allвариант важен как для вашего ответа, так и для принятого ответа.
варочные панели
3
Просмотр истории займет у большинства проектов необычайно много времени.
mikemaccana
5

Резюме:

  1. Шаг 1

Вы ищете полный путь к файлу в истории удаленных файлов. git log --diff-filter=D --summary | grep filename

  1. Шаг 2

Вы восстанавливаете свой файл из коммита до того, как он был удален

restore () {
  filepath="$@"
  last_commit=$(git log --all --full-history -- $filepath | grep commit | head -1 | awk '{print $2; exit}')
  echo "Restoring file from commit before $last_commit"
  git checkout $last_commit^ -- $filepath
}

restore my/file_path
srghma
источник
0

Вот мое решение:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>
Антонио Петричка
источник