Подтвердить что ты не робот

Firedrill: воссоздайте центральный репозиторий git от клонов разработчиков

Предположим, что у вас есть сценарий с центральным хранилищем master git, с которым клонируются разработчики и CI-engine. То есть очень близко к традиционной нераспределенной системе управления версиями, с центральным узлом и множеством узлов.

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

Полностью обновленный клон знает все ветки "remotes/origin" с "веткой w2 > -a", но имеет только одну локальную ветвь. (Меня это беспокоит - потеря информации о ветке).

Каковы будут шаги по восстановлению нового центрального хранилища git, ведущего себя каким-либо образом, как старый, ветки и все?

4b9b3361

Ответ 1

Просто создайте пустой репозиторий и, из полностью обновленного клона, выполните:

git remote add new-origin url://to/new/origin

git push --tags new-origin refs/remotes/origin/*:refs/heads/*

Очевидно, что если новое начало имеет тот же url, что и исходный, вы должны быть осторожны, чтобы не извлекать из источника.

Ответ 2

Во-первых, пожалуйста, не устанавливайте gitosis: идите с последним V3 + Gitolite, гораздо более полный уровень авторизации: см. "gitosis vs gitolite?" и "Зачем вам нужен Гитозис или Гитолит?.

Во-вторых, вы не теряете информацию о филиале.

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

В любом из ваших клонов могут быть не все локальные ветки, правда, но все эти ветки все еще находятся в удаленном пространстве имен этих клонов, поскольку они клонированы из того же (теперь ушедшего) "центрального" репо.

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

Примечание. Если вы не можете получить доступ к локальному репо с вашего сервера, свяжите указанное локальное репо и скопируйте один файл, представляющий этот пакет, на ваш сервер: вы сможете клонировать из указанного пакета.
См. "git bundle: связывать теги и головки", чтобы правильно создать пакет.


Краткая версия

# Let re-create a bare "blessed" repo on the server
git clone --mirror /path/to/a/local/repo repo.git
# or git clone --mirror /path/to/repo.bundle repo.git

# restore the local branches
remote=origin ; for brname in `git branch -r | grep $remote | grep -v HEAD | awk '{gsub(/[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream $brname  $remote/$brname ; done

# delete the remotes branches
# (your blessed repo doesn't track anything)
remote=origin ; for brname in `git branch -r | grep $remote | grep -v HEAD | awk '{gsub(/[^\/]+\//,"",$1); print $1}'`; do git branch -r -d origin/$brname ; done

# delete the remote 'origin'
# Not needed for your blessed repo
git remote rm origin

# Let make sure master is the current branch
# for that bare repo:
git symbolic-ref HEAD refs/heads/master

Что это. Готов к работе.


Длинная версия (демонстрация)

Создайте репо с 4 ветвями: master, b1, b2, b3, каждый со своими файлами:

C:\Users\VonC\prog\git\tests>mkdir c
C:\Users\VonC\prog\git\tests>cd c
C:\Users\VonC\prog\git\tests\c>git init r1
Initialized empty Git repository in C:/Users/VonC/prog/git/tests/c/r1/.git/
C:\Users\VonC\prog\git\tests\c>cd r1
C:\Users\VonC\prog\git\tests\c\r1>echo m > m.txt && git add . && git commit -m "first commit"
[master (root-commit) 1ffe5c1] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 m.txt

C:\Users\VonC\prog\git\tests\c\r1>git checkout -b b1
Switched to a new branch 'b1'
C:\Users\VonC\prog\git\tests\c\r1>echo f1 > f1.txt && git add . && git commit -m "f1 in b1"
[b1 1e64d01] f1 in b1
 1 file changed, 1 insertion(+)
 create mode 100644 f1.txt

C:\Users\VonC\prog\git\tests\c\r1>git checkout -b b2 master
Switched to a new branch 'b2'
C:\Users\VonC\prog\git\tests\c\r1>echo f2 > f2.txt git add . && git commit -m "f2 in b2"
[b2 4462b8f] f2 in b2
 1 file changed, 1 insertion(+)
 create mode 100644 f2.txt

C:\Users\VonC\prog\git\tests\c\r1>git checkout -b b3 master
Switched to a new branch 'b3'
C:\Users\VonC\prog\git\tests\c\r1>echo f3 > f3.txt && git add . && git commit -m "f3 in b3"
[b3 7ada753] f3 in b3
 1 file changed, 1 insertion(+)
 create mode 100644 f3.txt

Теперь, если я клонирую r1 в r2 и r2 в r3, да, r3 потеряет информацию о ветвях:

C:\Users\VonC\prog\git\tests\c>git clone r1 r2
Cloning into 'r2'...
done.

C:\Users\VonC\prog\git\tests\c>git clone r2 r3
Cloning into 'r3'...
done.

C:\Users\VonC\prog\git\tests\c>cd r3

C:\Users\VonC\prog\git\tests\c\r3>git br -a
* b3
  remotes/origin/HEAD -> origin/b3
  remotes/origin/b3

Но в вашем случае большинство репозитов есть прямой результат клона из благословенного репо.

r2 имеет все необходимые ветки (одна локальная, 4 ветки удаленного отслеживания, поскольку нет "локальных ветвей отслеживания" ):

C:\Users\VonC\prog\git\tests\c\r2>git br -a
* b3
  remotes/origin/HEAD -> origin/b3
  remotes/origin/b1
  remotes/origin/b2
  remotes/origin/b3
  remotes/origin/master

Если я могу clone --mirror r2 в голый репо r4, я все равно получаю все ветки.
См. " Какая разница между git clone --mirror и git clone --bare" для чего.

C:\Users\VonC\prog\git\tests\c>git clone --mirror r2 r4
Cloning into bare repository 'r4'...
done.

C:\Users\VonC\prog\git\tests\c>cd r4

C:\Users\VonC\prog\git\tests\c\r4>git br -a
* b3
  remotes/origin/HEAD
  remotes/origin/b1
  remotes/origin/b2
  remotes/origin/b3
  remotes/origin/master

Его удаленный объект все еще указывает на r2

[email protected] ~/prog/git/tests/c/r4 (BARE:b3)
$ git remote -v
origin  C:/Users/VonC/prog/git/tests/c/r2 (fetch)
origin  C:/Users/VonC/prog/git/tests/c/r2 (push)

Но это уже не нужно.
Пусть убедитесь, что r2 (или r1, если на то пошло) больше не доступен:

[email protected] ~/prog/git/tests/c/r4 (BARE:b3)
$ cd ..
[email protected] ~/prog/git/tests/c
$ mv r1 r1.old
[email protected] ~/prog/git/tests/c
$ mv r2 r2.old
[email protected] ~/prog/git/tests/c
$ cd r4

Теперь мы можем восстановить локальные ветки, указав их на удаленные ветки отслеживания:
См. "Отслеживать все удаленные ветки git как локальные ветки:

[email protected] ~/prog/git/tests/c/r4 (BARE:b3)
$ remote=origin ; for brname in `git branch -r | grep $remote | grep -v HEAD | awk '{gsub(/[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream $brname  $remote/$brname ; done
Branch b1 set up to track remote ref refs/remotes/origin/b1.
Branch b2 set up to track remote ref refs/remotes/origin/b2.
Branch b3 set up to track remote ref refs/remotes/origin/b3.
Branch master set up to track remote ref refs/remotes/origin/master.

Сделайте master ветку по умолчанию для этого голого репо:
См. "Git: правильный способ изменения Active Branch в голом репозитории?" и " Как изменить git remote HEAD, чтобы указать на что-то, кроме" master "".

[email protected] ~/prog/git/tests/c/r4 (BARE:b3)
$ git symbolic-ref HEAD refs/heads/master
[email protected] ~/prog/git/tests/c/r4 (BARE:master)

Все, что ссылается на "origin", больше не требуется.
Позвольте избавиться от удаленных ветвей отслеживания:
См. "Удалить ветки, перечисленные git branch -a" и "Удаление удаленных веток?"

[email protected] ~/prog/git/tests/c/r4 (BARE:master)
$ remote=origin ; for brname in `git branch -r | grep $remote | grep -v HEAD | awk '{gsub(/[^\/]+\//,"",$1); print $1}'`; do git branch -r -d origin/$brname ; done
Deleted remote branch origin/b1 (was 1e64d01).
Deleted remote branch origin/b2 (was 4462b8f).
Deleted remote branch origin/b3 (was 7ada753).
Deleted remote branch origin/master (was 1ffe5c1).

Позвольте панику и проверьте, сохраняют ли наши локальные ветки то, что мы просто "удалили":
(См. "Отображение последнего фиксации каждой ветки в git" )

[email protected] ~/prog/git/tests/c/r4 (BARE:master)
$ git br -v
  b1     1e64d01 f1 in b1
  b2     4462b8f f2 in b2
  b3     7ada753 f3 in b3
* master 1ffe5c1 first commit

Yeap, все хорошо.