Angenommen, Sie haben ein Szenario mit einem zentralen Master-Git-Repository, aus dem Entwickler und CI-Engines klonen. Das heißt, sehr nah an einem traditionellen, nicht verteilten Versionskontrollsystem-Setup, mit einem zentralen Hub und vielen Knoten. Dies kann ein Cloud-Dienst wie Github (Gitlab/Savannah/Azure usw.) oder eine Synology mit Git-Server oder ein anderes internes Setup sein.
Nehmen wir nun an, dass der Server gestohlen oder vom Blitz getroffen wurde oder etwas anderes, was dazu führen würde, dass das zentrale Repository mit all seinen zentralisierten Backups verschwunden ist. Alles, was Sie noch haben, sind die verschiedenen Klone, und glücklicherweise wurde einer davon vollständig aktualisiert, also erstellen Sie einen leeren Git-Repository-Ersatzserver, der als zukünftiges zentrales Repository verwendet werden soll, und machen sich an die Arbeit an dem Klon.
Der vollständig aktualisierte Klon kennt alle “remotes/origin”-Zweige mit “git branch -a”, hat aber nur einen einzigen lokalen Zweig. (Das ist es, was mich beunruhigt – der Verlust von Zweiginformationen).
Was wären die Schritte, um ein neues zentrales Git-Repository wiederherzustellen, das sich in irgendeiner Weise wie das alte verhält, Zweige und alles?
Erstellen Sie einfach ein leeres Repository und führen Sie vom vollständig aktualisierten Klon aus Folgendes aus:
git remote add new-origin url://to/new/origin
git push --tags new-origin refs/remotes/origin/*:refs/heads/*
Wenn der neue Ursprung dieselbe URL wie der ursprüngliche hat, müssen Sie natürlich darauf achten nicht vom Ursprung abrufen.
Installieren Sie bitte zuerst kein Gitosis: Nehmen Sie die neueste Version V3+ Gitolitein viel vollständiger Autorisierungsschicht: siehe “Gitosis vs Gitolite?” und “Warum brauchen Sie Gitosis oder Gitolite?”.
Zweitens verlieren Sie keine Verzweigungsinformationen.
Hier ist ein anderer Ansatz für das gleiche Problem, länger, aber der zeigt, wie Sie immer noch alle Zweige behalten.
Jeder Ihrer Clone hat möglicherweise nicht alle lokalen Zweige, aber alle diese Zweige befinden sich immer noch im Remote-Namespace dieser Klone, da sie aus demselben (jetzt verschwundenen) “zentralen” Repo geklont wurden.
Sobald Sie eines dieser Repos (als Bare Repo) auf den neuen zentralen Server geklont haben, brauchen Sie es nur noch ein wenig aufzuräumen, und Sie können es als Ihr neues gesegnetes Repo referenzieren.
Hinweis: Wenn Sie von Ihrem Server aus nicht auf ein lokales Repo zugreifen können, bündeln Sie dieses lokale Repo und kopieren Sie die eines Datei, die dieses Bundle darstellt, zurück auf Ihren Server: Sie können aus diesem Bundle klonen.
Sehen “git bundle
: Bundle-Tags und Heads”, um das Bundle richtig zu erstellen.
Kurzfassung
# 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
Das ist es. Bereit zu gehen.
Langversion (Demo)
Lassen Sie uns ein Repo mit 4 Zweigen erstellen: master
, b1
, b2
, b3
jeweils mit eigenen Dateien:
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
Wenn ich jetzt klonen r1
hinein r2
und r2
hinein r3
Jawohl, r3
würde Zweiginformationen verlieren:
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
Aber in Ihrem Fall sind die meisten Repos da draußen das direkte Ergebnis eines Klons aus dem gesegneten Repo.
r2
hat alle notwendigen Filialen (eine lokale, 4 Remote-Tracking-Zweigeda es keine “lokalen Tracking-Zweige” gibt):
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
Wenn ich kann clone --mirror r2
in ein bloßes Repo r4
ich werde noch alle Zweige bekommen.
Siehe „Was ist der Unterschied zwischen git clone --mirror
und git clone --bare
” warum.
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
Seine Fernbedienung zeigt noch auf 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)
Aber das ist nicht mehr nötig.
Stellen wir sicher r2
(oder r1
übrigens) ist nicht mehr zugänglich:
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
Jetzt können wir Stellen Sie die lokalen Zweige wieder herindem Sie sie auf die Remote-Tracking-Zweige verweisen:
Siehe “Alle Remote-Git-Zweige als lokale Zweige verfolgen”:
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.
Lasst uns machen master
der Standard-Zweig für dieses Bare-Repo:
Siehe „Git: Korrekte Methode zum Ändern von Active Branch in einem Bare-Repository?“ und „Wie ändere ich eine Git-Remote HEAD
auf etwas anderes hinweisen als „master
“”.
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)
Alles, was sich auf ‘origin
‘ wird nicht mehr benötigt.
Lassen Sie uns die Remote-Tracking-Zweige loswerden:
Siehe „Zweige löschen aufgelistet von git branch -a
” und “Entfernte Branches löschen?”
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).
Lassen Sie uns in Panik geraten und überprüfen, ob unsere lokalen Zweigstellen immer noch auf das verweisen, was wir gerade “gelöscht” haben:
(Siehe „Den neusten Commit jedes Branches in Git anzeigen“)
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
Ja, alles gut.