Як знайти видалений файл в історії фіксації проекту?


1274

Колись у моєму проекті був файл, який я зараз хотів би отримати.

Проблема полягає в тому, що я не маю уявлення про те, коли я його видалив і яким шляхом він був.

Як я можу знайти елементи цього файлу, коли він існував?


Схожий питання тут: stackoverflow.com/questions/7093602 / ...
— Екес


13
Відповіді тут корисніші для мене, ніж відповіді у дублікатах .
— Феліпе Альварес

5
погодився ... незалежно від дублікатів ... вони не з'явилися в пошуку Google .... цей зробив ... я сподіваюся, що ми перестанемо витрачати час на переслідування дублікатів ... тільки час і алгоритм Google скажіть, яке питання найкраще.
— Тім Боланд

Відповіді:


1599

Якщо ви не знаєте точний шлях, який ви можете використовувати

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>

Зверніть увагу на символ caret ( ^), який отримує замовлення до ідентифікованого, оскільки в момент <SHA>фіксації файл видаляється, нам потрібно переглянути попередню комісію, щоб отримати вміст видаленого файлу


2
Спробуйте використовувати відносний шлях замість абсолютного (якщо ви ще цього не зробили).
— Бурштин

63
Що робити, якщо ви не знаєте точного шляху? Все, що ви знаєте, це ім'я файлу?
— священик

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> фіксації файл видаляється, нам потрібно переглянути попередню
— комісію,

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

6
@tandrewnichols який просто означає , що ви використовуєте неправильний здійснює SHA - ви хочете, щоб зробити для версії файлу , який ви хочете ... , який , ймовірно , не варіант , коли файл буде видалений.
— Бурштин

6
@ Бурштин і зобов'язання, яке ви хочете, є, ймовірно, останнім, перш ніж його було видалено, звідси і ця відповідь.
— Сем Холдер

1
@AlexR: <SHA>~1має працювати так само, не потребуючи обгортання лапок.
— CodeManX

37

Припустимо, ви хочете відновити названий файл MyFile, але не знаєте його шляху (або його розширення, з цього питання):

Prelim .: Уникайте плутанини, переходячи до кореня git

Нетривіальний проект може мати декілька каталогів з однаковими або однаковими назвами.

> cd <project-root>
  1. Знайдіть повний шлях

    git log --diff-filter = D - підсумок | grep видалити | grep MyFile

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

full/path/to/MyFile.js це шлях та файл, який ви шукаєте.

  1. Визначте всі коміти, які вплинули на цей файл

    git log --oneline - наступний - повний / шлях / до / 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"І step3, зверніть увагу на лапки навколо хеша:git checkout "bd8374c^" -- full/path/to/MyFile.js
— user5542121

30

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

git log --all -- **/thefile.*

4
@PedroMorteRolo Хм. Я не знаю, як мені здається скопіювати існуючу відповідь у голосовані: / Ця відповідь була корисна і сама по собі; може бути достатньо виплат?
— Clément

1
Цей файл не знаходить, якщо він знаходиться в корені проекту (перевірено в Cygwin).
— wortwart

19

Нижче проста команда, де користувач або git може передати видалене ім’я файлу з кореневого каталогу сховища та отримати історію:

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

Якщо хтось, може вдосконалити команду, будь ласка.


1
Дивовижне, дякую! Схоже, мого файлу взагалі ніколи не існувало, але це окрема проблема, яка суттєво переживає…

переконайтеся, що ви запускаєте це з кореневого каталогу репозиторію, якщо ваш файл здається "
— відсутним

Спасибі @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

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