Можно ли восстановить ветку после ее удаления в Git?


1068

Если я бегу git branch -d XYZ, есть ли способ восстановить ветку? Есть ли способ вернуться, как будто я не запускал команду удаления ветки?


4
Замечательное замечание о принятом ответе заключается в том, что он работает, даже если ветка была удалена в источнике! Я только что восстановил несколько веток, которых у меня больше не было локально после того, как они были случайно удалены в источнике.
Theblang

Ответы:


1956

Да, вы должны быть в состоянии сделать git reflogи найти SHA1 для коммита в конце вашей удаленной ветви, а затем просто git checkout [sha]. И как только вы получите этот коммит, вы можете просто git checkout -b [branchname]восстановить ветку оттуда.


Благодарим @Cascabel за эту сокращенную / однострочную версию.

Вы можете сделать это за один шаг:

git checkout -b <branch> <sha>

477
Вы можете сделать это в один шаг: git checkout -b <branch> <sha>.
Каскабель

200
Подсказка - если вы только что удалили ветку, вы увидите что-то вроде этого в своем терминале - «Удаленная ветка <your-branch> (была <sha>)». И тогда это очень просто - просто используйте это <sha>. Например, как упомянуто выше -git checkout -b <branch> <sha>
Snowcrash

6
да, просто прокрутите вверх в своем терминале (если вы не сделали CMD+K)
neaumusic

42
Используйте, git reflog --no-abbrevчтобы увидеть полный <sha>текст, сокращенный по умолчанию.
Jkulak

5
Для любого, как я, у которого были проблемы с поиском ша удаленной ветви: я смог git checkout remotes/origin/deleted_branch.
Джефф Ирвин

161

Большую часть времени недоступные коммиты находятся в reflog. Итак, первое, что нужно попробовать - посмотреть на reflog с помощью команды git reflog(для которой отображается reflog HEAD).

Возможно, что-то проще, если коммит был частью определенной ветки, которая еще существует, - это использовать команду git reflog name-of-my-branch. Он также работает с пультом дистанционного управления, например, если вы принудительно нажали (дополнительный совет: всегда предпочитайте git push --force-with-leaseвместо этого лучше предотвращать ошибки и лучше восстанавливать).


Если ваши коммиты отсутствуют в вашем reflog (возможно, из-за того, что они были удалены сторонним инструментом, который не записывает в reflog), я успешно восстановил ветку, переустановив свою ветку в шаре коммита, найденного с помощью такой команды ( создает файл со всеми висячими коммитами):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

Если вам нужно использовать его более одного раза (или вы хотите сохранить его где-нибудь), вы также можете создать псевдоним с помощью этой команды ...

git config --global alias.rescue '!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt'

и использовать его с git rescue

Чтобы исследовать найденные коммиты, вы можете отобразить каждый коммит, используя некоторые команды для их просмотра.

Чтобы отобразить метаданные фиксации (автор, дата создания и сообщение фиксации):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Чтобы увидеть также различия:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Как только вы нашли свой коммит, создайте ветку для этого коммита с помощью:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

Для тех, которые находятся под Windows и им нравятся графические интерфейсы, вы можете легко восстановить коммиты (а также некоммитированные промежуточные файлы) с помощью GitExtensions , используя функцию Repository=> Git maintenance=>Recover lost objects...


Аналогичная команда для легкого восстановления удаленных удаленных файлов: https://stackoverflow.com/a/58853981/717372


2
Огромная помощь. У меня был потерянный коммит, которого никогда не было в моем локальном репо. Первая ваша команда помогла мне найти ее на сервере. +1
Шон Адкинсон

1
этот псевдоним спасения - находка !!! Большое спасибо за помощь!
72A12F4E

2
Вы спасли мою жизнь.
Джед Линч

Ответ Патрика Куреваара мне помог, потому что я не знаю своих последних удаленных разветвленных коммитов <sha>.
Монир Хан

@ Монир-Хан А? Что я должен сделать вывод? Ответ Патрика - это просто копия / вставка моей команды (с ошибкой: он забыл отфильтровать коммиты) ...
Филипп

45

Если вам нравится использовать графический интерфейс, вы можете выполнить всю операцию с помощью gitk.

gitk --reflog

Это позволит вам увидеть историю коммитов ветки, как если бы ветка не была удалена. Теперь просто щелкните правой кнопкой мыши самый последний коммит в ветке и выберите пункт меню Create new branch.


28

Решение с наибольшим количеством голосов на самом деле делает больше, чем просили:

git checkout <sha>
git checkout -b <branch>

или

git checkout -b <branch> <sha>

перенести вас в новую ветку вместе со всеми последними изменениями, которые вы, возможно, забыли зафиксировать. Это не может быть вашим намерением, особенно в «режиме паники» после потери ветки.

Более чистое (и более простое) решение кажется однострочным (после того, как вы нашли <sha>с git reflog):

git branch <branch> <sha>

Теперь ни ваша текущая ветка, ни незафиксированные изменения не затронуты. Вместо этого будет создана только новая ветка вплоть до <sha>.

Если это не совет, он все равно будет работать, и вы получите более короткую ветвь, тогда вы можете повторить попытку с новым <sha>и новым именем ветки, пока не получите это правильно.

Наконец, вы можете переименовать успешно восстановленную ветку в то, что она была названа или что-то еще:

git branch -m <restored branch> <final branch>

Само собой разумеется, ключ к успеху был в том, чтобы найти правильный коммит <sha>, поэтому называйте свои коммиты с умом :)


14

Добавление к т.ут ответ : есть также git-resurrect.sh сценарий в contrib/области источников Git (в git.git хранилища), который может помочь вам.

git-resurrect <name>пытается найти следы названного кончика ветви <name>и пытается воскресить его. В настоящее время в reflog выполняется поиск сообщений извлечения, а -rтакже сообщений слияния. С помощью -mи -t, история всех ссылок сканируется для Merge <name> into other/ Merge <other> into <name>(соответственно) фиксации тем, что довольно медленно, но позволяет вам воскрешать ветки тем других людей.


1
Теперь это работает для меня, хотя мне пришлось добавить / usr / lib / git-core / в мою PATH. Но это не выполнило чудо, на которое я надеялся :(
AmanicA

10

Я использовал следующие команды, чтобы найти и получить мою удаленную ветку. Первые шаги взяты из описания gcb.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Теперь найдите git commit id (GIT-SHA) на основе комментариев коммита и используйте его в приведенной ниже команде. Оформить заказ на новую ветку под названием NEW-BRANCH с ранее найденным GIT-SHA:

$ git checkout -b NEW-BRANCH GIT-SHA

Большое спасибо. Потребовалось немного времени для поиска имени, но время того стоило. Если есть способ также выполнить поиск по строке сообщения о коммите, было бы намного лучше.
Монир Хан

9

Если у вас нет рефлога, например. поскольку вы работаете в пустом хранилище, в котором не включен рефлог, а коммит, который вы хотите восстановить, был создан недавно, другой вариант - найти недавно созданные объекты коммитов и просмотреть их.

Внутри .git/objectsкаталога запустите:

find . -ctime -12h -type f | sed 's/[./]//g' | git cat-file --batch-check | grep commit

Он находит все объекты (коммиты, файлы, теги и т. Д.), Созданные за последние 12 часов, и фильтрует их, показывая только коммиты. Проверка это тогда быстрый процесс.

Сначала я бы попробовал скрипт git-ressurect.sh, упомянутый в ответе Якуба .


1
Хорошая альтернативная идея! Ваша команда выдает ошибку, хотя. Проблема в части «12h» (фактически «h»). Как только я удалил букву "h", все заработало. From man find: "-ctime n - статус файла был последний раз изменен n * 24 часа назад." Таким образом, мы должны также изменить 12 на 0,5, чтобы иметь ожидаемое поведение последних 12 часов.
pagliuca

1
Я использую OS X 10.8 здесь, поэтому флаги 'find' выше основаны на версии, которая поставляется.
Роберт Найт

1
Да, конечно, проблема с версиями! Вот почему я проголосовал за ваш ответ на первом месте! Я просто прокомментировал, чтобы люди понимали, что параметры могут быть разными.
pagliuca

9

Для пользователей GitHub без установленного Git:

Если вы хотите восстановить его с веб-сайта GitHub , вы можете использовать их API, чтобы получить список событий, связанных с репо:

Первый

  • найти эти SHA (зафиксировать хэши):

    curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

    ... или для частных репозиториев:

    curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

    (будет предложено ввести пароль GitHub)

    • (Если для репо требуется двухфакторная аутентификация, см. Комментарии к этому ответу ниже.)

следующий

  • перейдите на GitHub и создайте новую временную ветку, которая будет удалена навсегда ( предпочтительнее Chrome ).

   • Перейдите в разделы и удалите этот.

   •   На той же странице, без перезагрузки , откройте DevTools, панель «Сеть». Теперь приготовьтесь ...

   • Нажмите восстановить. Вы заметите новую «линию». Щелкните правой кнопкой мыши на нем и выберите «Копировать как cURL» и сохраните этот текст в каком-то редакторе.

   • Append до конца скопированной строки кода, это: -H "Cookie=".

Теперь вы должны получить что-то вроде:

    curl 'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName' -H 'Cookie:' -H 'Origin: https://github.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US' -H 'User-Agent: User-Agent' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: https://github.com/UserName/ProjectName/branches' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=token' --compressed

Заключительный этап

  • замените "BranchSHA" на свой SHA-хэш и BranchName с нужным именем (кстати, это отличный способ переименовать ветку из сети). Если вы не слишком медлительны, вам все равно нужно сделать этот запрос. Например, просто скопируйте и вставьте в терминал.

PS

Я понимаю, что это может быть не самое простое или правильное решение, но оно предлагается на случай, если кто-то посчитает его полезным.


1
Вышеприведенный git reflogпример является одним из немногих, на которые нельзя положиться, и поэтому он был полезен, например, при удалении удаленной ветви и потере доступа к компьютеру, что было сделано из ничего полезного reflog. Обратите внимание , при использовании OAuth или двухфакторной аутентификации на Githubcurl команды становится вид: curl -u username:token https://api.github.com/userилиcurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
TT--

@ TT-- вау, я рада, что это помогло! и спасибо за ваш вклад в авторизацию токена :)
Максим Мазурок

8

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

git branch -d [branch]

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

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

git branch -D [branch]

Это часть обязательного просмотра видео от Скотта Чакона о Git. Проверьте минуты 58:00, когда он говорит о ветках и как их удалить.

Введение в Git со Скоттом Чаконом из GitHub


7
Как это помогает ответить на вопрос?
Дмитрий Зайцев

6
Говорят спрашивающему, что ветви не содержат контент, но на самом деле являются указателями. Вам не нужно бояться удаления веток ... вы можете создавать новые, указывающие на тот же коммит, что и удаленный .... Вау! Я до сих пор помню, когда я задал этот вопрос. Хорошие времена в 2012 году!
Фабиопаготи

1
Пришлось прокрутить три экрана, чтобы ПОСЛЕДНЕЕ найти ответ, который решает проблему: удаление ветки означает удаление простого указателя. Здесь нет ситуации с потерей данных, единственное, что нужно восстановить, это куда она указывает. Ответы, которые идут напрямую reflog, просто излишни.
RomainValeri

5

Убедитесь, что все это выполняется локально, и подтвердите, что репо находится в желаемом состоянии, прежде чем отправлять в Bitbucket Cloud. Также может быть хорошей идеей клонировать текущее хранилище и сначала протестировать эти решения.

  1. Если вы только что удалили ветку, вы увидите что-то вроде этого в своем терминале:
    Deleted branch <your-branch> (was <sha>)

2. Для восстановления ветки используйте:

    git checkout -b <branch> <sha>

Если вы не знаете «ша» на макушке головы, вы можете:

  1. Найдите 'sha' для коммита в конце удаленной ветки, используя:
    git reflog
  1. Чтобы восстановить ветку, используйте:
    git checkout -b <branch> <sha>

Если ваши коммиты отсутствуют в вашем журнале:

  1. Вы можете попытаться восстановить ветку, сбросив ветку до шага коммита, найденного с помощью такой команды:
    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

2.Вы можете затем отобразить каждый коммит, используя один из них:

    git log -p <commit>
    git cat-file -p <commit>

4

Чтобы восстановить удаленную ветку, сначала просмотрите историю рефлогов,

git reflog -n 60

Где n относится к последним n коммитам. Затем найдите правильную голову и создайте ветку с этой головой.

git branch testbranch HEAD@{30}

4

Я перебросил ветку с пульта, чтобы попытаться очистить несколько коммитов, которые мне не нужны, и собирался выбрать нужные мне. Конечно я написал SHA неправильно ...

Вот как я их нашел (в основном это более простой интерфейс / взаимодействие с ответами здесь):

Сначала создайте список свободных коммитов в своем журнале. Сделайте это как можно скорее и перестаньте работать, поскольку они могут быть сброшены сборщиком мусора.

git fsck --full --no-reflogs --unreachable --lost-found > lost

Это создаст lostфайл со всеми коммитами, которые вам придется посмотреть. Чтобы упростить нашу жизнь, давайте вырезать из нее только SHA:

cat lost | cut -d\  -f3 > commits

Теперь у вас есть commitsфайл со всеми коммитами, которые вам нужно посмотреть.

Предполагая, что вы используете Bash, последний шаг:

for c in `cat commits`; do  git show $c; read; done

Это покажет вам diff и передаст информацию для каждого из них. И жду, когда ты нажмешь Enter. Теперь запишите все те, которые вы хотите, и затем выберите их. После того, как вы закончите, просто нажмите Ctrl-C.


2

БОЛЬШОЕ ДА

если вы используете GIT, выполните следующие простые действия: https://confluence.atlassian.com/bbkb/how-to-restore-a-deleted-branch-765757540.html

если вы используете smartgit и уже переместили эту ветку в исходное положение , найдите эту ветку и щелкните правой кнопкой мыши, затем оформите заказ


1

Сначала зайдите в git batch the move в ваш проект, например:

cd android studio project
cd Myproject
then type :
git reflog

У всех вас есть список изменений и ссылочный номер взять номер ссылки, а затем
оформить заказ в Android Studio или Git Betcha. другое решение взять номер ссылки и перейти к Android Studio. Нажмите на ветки git вниз, затем нажмите на тег оформления заказа или ревизию после ссылочного номера, и тогда у вас есть ветви.


1

В дополнение к ответу tfe, вы можете восстановить этот процесс, если он не является сборщиком мусора. Ветвь Git - это просто указатель на определенный коммит в дереве коммитов. Но если вы удалите указатель и коммиты в этой ветке не будут объединены с другой существующей веткой, то git будет обрабатывать их как висячие коммиты и удаляет их во время сборки мусора, который он может периодически запускать автоматически.

Если ваша ветвь не была объединена с существующей веткой, и если она была собрана сборщиком мусора, вы потеряете все коммиты вплоть до точки, откуда ветка была разветвлена ​​из существующей ветки.


1

Связанная проблема: я пришел на эту страницу после поиска «как узнать, что такое удаленные ветки».

При удалении многих старых веток я почувствовал, что по ошибке удалил одну из новых веток, но не знал названия для ее восстановления.

Чтобы узнать, какие ветви недавно были удалены, выполните следующие действия:

Если вы перейдете на свой Git URL, который будет выглядеть примерно так:

https://your-website-name/orgs/your-org-name/dashboard

Затем вы можете увидеть канал, который удален, кем, в недавнем прошлом.


Конечно. Ответ выше для GitHub. Мы установили GitHub локально. Спасибо, что задали вопрос.
Манохар Редди Поредди

1

Я сделал это на компьютере, который я удаляю ветку:

git reflog

ответ:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

и я получаю ветку с этой командой:

git checkout -b newBranchName 74b2383


0

Просто использование git reflogне вернуло shaдля меня. Только commit id(это 8 символов в длину и ша намного)

Так что я использовал git reflog --no-abbrev

И затем сделайте то же самое, что упомянуто выше: git checkout -b <branch> <sha>


вы всегда можете использовать сокращенный 8-символьный ша, вам не нужно использовать полный ша
Майкл Дрехер

0

Если вы используете VSCode ... и в какой-то момент вы синхронизировали свою ветку с сервером перед удалением ...

Обратите внимание, что git branch delete удаляет только локальную копию, а не копию на сервере. Во-первых, на панели Git (значок git на левой панели инструментов), просмотрите ветки и посмотрите, есть ли там ваша ветка в "origin / your_branch_name". Если это так, просто выберите это, и вы должны получить свой код обратно (предложить немедленно скопировать / вставить / сохранить его локально в другом месте).

Если вы не видите «origin / your_branch_name», установите расширение GitLens. Это позволяет визуально просматривать репозитории сервера и находить копию, которую вы синхронизировали с сервером. Если у вас есть несколько репозиториев, обратите внимание, что может потребоваться открыть хотя бы один файл из нужного репозитория, чтобы репозиторий появился в GitLens. Затем:

  1. Откройте панель GitLens

  2. Разверните хранилище

  3. Вы должны увидеть список категорий: Филиалы / Авторы / Remotes / Stashes / etc

Вы должны найти YourLostTreasure в разделе «Филиалы» или, возможно, в разделе «Remotes -> Origins». Надеюсь, вы увидите ветку с нужным именем - если вы развернете ее, вы должны увидеть файлы, которые вы изменили в этой ветке. Дважды щелкните имена файлов, чтобы открыть их, и немедленно сделайте резервную копию этого кода.

Если вы не сразу видите потерянную ветку, покопайтесь и, если найдете что-то многообещающее, немедленно откройте ее и возьмите код. Мне пришлось немного поковыряться, пока я не нашел TheGoldenBranch, и даже тогда в коде отсутствовали последние один или два сохранения (возможно, из-за того, что я не смог выполнить синхронизацию с сервером перед попыткой слияния ветвлений, но случайно щелкнуть) Отделение-Delete). Мой поиск был излишне удлинен, потому что, когда я впервые нашел ветвь, я не был полностью уверен, что имя было правильным, поэтому продолжал искать, и потребовалось некоторое время, чтобы повторно найти эту первую ветку. (Таким образом, Carpe Carpum, а затем продолжать искать.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.