Как восстановить локально потерянный репозиторий git bare (используя отдельный git-dir) с помощью одного из его пультов - PullRequest
0 голосов
/ 04 октября 2019

Давным-давно я настроил репо с помощью git --separate-git-dir, потому что я хотел, чтобы репо находилось в рабочем каталоге. К сожалению, это отдельное (предположительно «голое»?) Хранилище было потеряно из-за сбоя жесткого диска, и я хочу восстановить его, используя содержимое удаленного мною удаленного (который часто передавался).

Какмне сделать это?

Я попытался воссоздать новое пустое git-репо:

git init --separate-git-dir=/desired/path/to/bare/git/repo

Это, конечно, создает файл .git в рабочем каталоге с содержимым, gitdir: /desired/path/to/bare/git/repo

Затем я сделал:

git remote add network ssh://host/path/to/repo
git fetch network

Но, если я бегу git status, я получаю

On branch master

No commits yet

Что я хотел бы получить

Я только когда-либо использовал (и выдвигал) главную ветвь. Я надеюсь перевести этот репозиторий в состояние БЕЗ ИЗМЕНЕНИЯ РАБОЧЕГО ДИРЕКТОРА, в котором я могу набрать git status, и, надеюсь, он видит только изменения между текущим, неизмененным рабочим каталогом и последним коммитом, отправленным на удаленный компьютер, который теперь должен находиться вмой местный голый?

Я действительно просто пытаюсь подобрать то, на чем остановился.

Спасибо.

Ответы [ 2 ]

1 голос
/ 06 октября 2019

TL; DR: остается только создать ветку master, возможно, с git branch master network/master (возможно, с различными флагами; см. Ниже), и заполнить индекс, возможно, с использованием git read-tree,Следовательно:

git branch master network/master
git read-tree master

, вероятно, достаточно.


Позвольте мне превратить мои комментарии выше в реальный ответ теперь, когда у меня есть немного свободного времени. Мы отметили, что --separate-git-dir не делает хранилище голым - голое хранилище - это хранилище с no рабочим деревом - оно просто помещает рабочее дерево и хранилище (.git/* файлов) в двух разных местах файловой системы. Чтобы сделать эту функцию, Git добавляет .git файл в рабочее дерево, содержащий путь к самому репозиторию, как вы заметили.

Итак, в этом случае этосамо хранилище было повреждено или уничтожено. У вас есть рабочее дерево без хранилища. Вы создали новый пустой репозиторий, используя другой git init --separate-git-dir=... и выполнили команды:

git remote add network ssh://host/path/to/repo

(я бы назвал удаленный origin вместо networkно нет ничего неправильно с network, это просто немного нетрадиционно.)

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

git fetch network

В самом вашем репозитории (в любом каталоге) теперь есть некоторый набор коммитов, скопированный из репозитория Git по URL-адресу, по которому вы запустили git fetch.

Atэта точка почти все нормально. Отсутствуют две вещи:

  • Нет локальных ветвей, несмотря на то, что ветвь current является той, которая называется master. Ветвь master не существует.

  • Индекс - набор файлов, которые будут помещены в следующий коммит, который вы сделаете, - пуст.

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

  1. Чтобы создать локальное имя master, соответствующее имени удаленного отслеживания origin/master, которое указывает на окончательную фиксацию ветви master вnetwork хранилище, из которого вы скопировали все его коммиты. Чтобы сделать это, используйте:

    git branch master network/master
    

    . В качестве последнего аргумента вы можете использовать все, что вам нравится, при условии, что он называет любую действительную фиксацию: будет достаточно сырого хеш-идентификатора или что-то вроде network/master^,network/master~3 или что угодно. Если вы do используете имя network/master, Git распознает, что это имя удаленного отслеживания . 1 Как следствие, git branch устанавливает этот удаленный-tracking name как upstream нового (локального) имени ветви master.

    Точнее, автоматическая настройка upstream - это действие default для git branch здесь (а также для некоторых форм git checkout). Вы можете настроить Git для изменения значения по умолчанию или добавить флаги командной строки, чтобы переопределить любое значение по умолчанию, которое вы установили или не установили.

    На запрет этой восходящей настройки, используйте git branch --no-track master network/master,Чтобы заставить настройку восходящего потока, используйте git branch --track master network/master, который можно сократить как git branch --track network/master.

    Независимо от того, когда и когда устанавливать настройку восходящего потока, зависит от вас. Вы всегда можете изменить его позже, используя git branch --set-upstream, или удалить его позже, используя git branch --unset-upstream.

  2. Теперь, когда существует master, или вы можете сделать это до создания master,но я бы сделал это позже, так как все становится проще и проще - вы захотите заполнить свой индекс из коммита, который вы выбрали в качестве вашего текущего коммита. Обычно - в ситуации, отличной от этого случая «восстановления поврежденного Git-репозитория» - мы выполняем шаги 1 и 2 одновременно, используя git checkout, но вы хотите сделать это без , мешая текущей работе-tree, и git checkout мешает текущему рабочему дереву. Так что мы делаем это как отдельный шаг 2, используя одну из команд Git нижнего уровня plumbing : 2

    git read-tree master
    

    (или git read-tree HEADили git read-tree @, если вы хотите печатать меньше: все три делают одно и то же). Это просто считывает именованный коммит в индекс, вообще ничего не делая: он заменяет все, что было в индексе (которое было ничем), на то, что находится в именованном коммите.

Последелая git branch и git read-tree, git status сможет сравнить текущий коммит - тот, который назван HEAD / master - с текущим содержимым индекса - они будут совпадать, конечно - и затем сравнитьтекущее содержимое индекса с текущим содержимым рабочего дерева. Они будут совпадать или различаться в зависимости от того, какой коммит вы выбрали при настройке собственного master на шаге 1, и в любом случае вы будете готовы к git add и сделаете новые коммиты, если хотите.


1 A имя для удаленного отслеживания - это любое имя, полное написание которого начинается с refs/remotes/. В этом случае network/master действительно refs/remotes/network/master. Документация Git в основном называет эти имена веток для удаленного отслеживания , но слово «ветвь» здесь, как мне кажется, больше вводит в заблуждение, чем нет, поэтому я опускаю его.

Эти имена существуют в ваш Git-репозиторий и автоматически создаются и обновляются на основе имен веток, которые ваш Git получает от другого Git - по URL-адресу, хранящемуся под именем network - всякий раз, когда ваш Git делает git fetch изGit на network. Успешный git push network также обновляет все ветви, которые они устанавливают на основе запросов вашего Git.

2 Различие между сантехникой и фарфором вGit действительно с точки зрения того, кто должен использовать команду: фарфоровая команда должна быть удобной для пользователя и целеустремленной, 3 , а сантехническая команда должна быть командой, что фарфоровая командаможет использовать в качестве одной из серии таких команд (и / или в сочетании с другими системными утилитами) для достижения какой-то реальной цели. Таким образом, сантехнические команды имеют тенденцию быть сверхспецифичными и ориентированными на механизм (git read-tree, «заполнить индекс из коммита»; git rev-parse, «превратить удобочитаемое имя во внутренний идентификатор хеша»; git update-ref, «записать необработанный хеш»)Идентификатор в произвольной ссылке ").

3 Или, возможно," менее активно враждебно для пользователя ". :-) Смотри также https://git -man-page-generator.lokaltog.net /

1 голос
/ 06 октября 2019

Я думаю, что это лучший способ:

Введенные вами команды - хорошее начало:

git init --separate-git-dir=/desired/path/to/bare/git/repo
git remote add network ssh://host/path/to/repo
git fetch network

Теперь у вас есть новый репозиторий, и ваше рабочее дерево остается полностью неизменным,Git автоматически создает ветку с именем "master". Сеть филиалов / master содержит всю историю коммитов. Но твой местный хозяин - сирота .. не совершает этого. Решение состоит в том, чтобы указать локальный мастер на мастер сети:

git reset network/master

Ваше локальное рабочее дерево остается неизменным ... но ваш индекс и HEAD теперь идентичны сети / мастеру. Git status и git diff должны показывать ваши измененные файлы. Теперь вы можете использовать git commit -a или git commit add и git commit.

...