Firedrill:从开发人员克隆重新创建中央git存储库

时间:2012-08-20 08:27:00

标签: git

假设您有一个具有中央主git存储库的方案,开发人员和CI引擎可以从中进行克隆。即非常接近传统的非分布式版本控制系统设置,具有中央集线器和许多节点。

现在说服务器被闪电或任何其他可能导致中央存储库与其所有集中备份一起丢失的东西被盗或被攻击。您剩下的就是各种克隆,幸运的是其中一个已完全更新,因此您创建了一个空白的git存储库替换服务器,用作未来的中央存储库并开始处理克隆。

完全更新的克隆使用“git branch -a”知道所有“遥控器/原点”分支,但只有一个本地分支。 (这让我担心 - 失去分支机构信息)。

重新建立一个新的中央git存储库的步骤是什么,它会以旧的,分支和所有方式运行?

2 个答案:

答案 0 :(得分:20)

只需创建一个空的存储库,然后从完全更新的克隆中执行:

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

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

显然,如果新原点与原始网址位于同一网址,则必须小心从原点获取。

答案 1 :(得分:8)

首先,请不要安装gitosis:使用最新的V3+ Gitolite,更加完整authorization layer:请参阅“gitosis vs gitolite?”和“{{ 3}}”。

其次,您不会丢失任何分支信息。

这是同一问题的另一种方法,更长,但它说明了你如何保留所有分支。

您的任何克隆都可能没有所有本地分支,都是,但所有这些分支仍然在这些克隆的远程命名空间中,因为它们是从相同的(现在已经消失的)“中央”存储库克隆的。

一旦你在新的中央服务器上克隆回来(作为一个简单的回购)其中一个回购,你需要的只是清理一下,你可以将它作为新的祝福回购参考。

注意:如果您无法从服务器访问本地仓库,请捆绑所述本地仓库,并将表示该捆绑包的一个文件复制回您的服务器:您将能够从所述服务器克隆捆绑。
请参阅“Why do you need Gitosis or Gitolite?”以正确创建捆绑包。


短版

# Let's 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's make sure master is the current branch
# for that bare repo:
git symbolic-ref HEAD refs/heads/master

就是这样。准备好了。


长版(演示)

让我们创建一个包含4个分支的仓库:masterb1b2b3,每个分支都有自己的文件:

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 git bundle: bundle tags and heads ,因为remote tracking branches“):

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,我仍会获得所有分支机构。
有关原因,请参阅“there is no "local tracking branches”。

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

VonC@HOSTNAME ~/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):

VonC@HOSTNAME ~/prog/git/tests/c/r4 (BARE:b3)
$ cd ..
VonC@HOSTNAME ~/prog/git/tests/c
$ mv r1 r1.old
VonC@HOSTNAME ~/prog/git/tests/c
$ mv r2 r2.old
VonC@HOSTNAME ~/prog/git/tests/c
$ cd r4

现在我们可以恢复本地分支,方法是将它们指向远程跟踪分支:
请参阅“What's the difference between git clone --mirror and git clone --bare”:

VonC@HOSTNAME ~/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作为该裸仓的默认分支:
请参阅“Track all remote git branches as local branches”和“Git: Correct way to change Active Branch in a bare repository?”。

VonC@HOSTNAME ~/prog/git/tests/c/r4 (BARE:b3)
$ git symbolic-ref HEAD refs/heads/master
VonC@HOSTNAME ~/prog/git/tests/c/r4 (BARE:master)

不再需要任何引用“origin”的内容 让我们摆脱远程跟踪分支:
请参阅“How do I change a Git remote HEAD to point to something besides “master”和“Delete branches listed by git branch -a

VonC@HOSTNAME ~/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).

让我们恐慌并检查我们当地的分支机构是否仍然引用我们刚刚“删除”的内容:
(参见“Deleting remote branches?”)

VonC@HOSTNAME ~/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

是的,一切都很好。