Jak przekonwertować czyste repozytorium Git na normalne (lokalne)?

81

Mam czyste repozytorium git, ale muszę uzyskać dostęp i przeglądać jego zawartość przez ssh (w menedżerze plików, takim jak doświadczenie użytkownika).

Zakładam, że mógłbym to sklonować:

git clone -l <path_to_bare_repo> <new_normal_repo>

Jednak moje repozytorium ma około 20 GB i nie mam miejsca na jego skopiowanie. Czy istnieje sposób na konwersję czystego repozytorium na miejscu, aby uzyskać w nim kopię roboczą?

nyi
źródło
5
Nietestowane, ale jeśli przeniesiesz zawartość czystego repozytorium do .gitkatalogu i ustawisz bareparametr w konfiguracji na false, powinno zachowywać się jak zwykłe repozytorium, z którego możesz po prostu git checkoutpobrać pliki.
Noufal Ibrahim
W zależności od tego, co masz na myśli, mówiąc „przeglądaj zawartość”, prawdopodobnie możesz zrobić wszystko, co chcesz, w czystym repozytorium, używając git showigit cat-file
William Pursell
Dzięki za podpowiedź, przydatna. Potrzebuję jednak bardziej doświadczonego menedżera plików (zredagowałem pytanie).
nyi
Jeśli twój system plików obsługuje dowiązania twarde i klonujesz do tego samego systemu plików, clone -l nie zajmuje więcej miejsca na dysku, ponieważ łączy twardo wszystkie obiekty. Będziesz jednak potrzebować miejsca na kasę, jak zauważyli inni.
Neil Mayhew,
1
Jeśli Twoje czyste repozytorium zajmuje 20 GB miejsca na dysku, ile więcej będzie potrzebować drzewo robocze? Czy naprawdę masz tyle miejsca?
ADTC

Odpowiedzi:

113

Uwaga : przetestowałem to na bardzo prostym repozytorium z jednym zatwierdzeniem. Sprawdź to dokładnie, przeczytaj strony podręcznika i zawsze bądź szczęśliwy, że wykonałeś kopię zapasową, zanim skorzystasz z porad znalezionych w StackOverflow. (Ty się cofasz, prawda?)

Aby przekonwertować --barerepozytorium na nie-bare:

  1. Utwórz .gitfolder na najwyższym poziomie repozytorium.
  2. Przenieś elementy zarządzania repozytorium ( HEAD branches config description hooks info objects refsitp.) Do .gitwłaśnie utworzonego.
  3. Uruchom, git config --local --bool core.bare falseaby przekonwertować lokalne repozytorium git na non-bare.
  4. (przez komentarz Tamása Papa ) Po kroku # 3 zobaczysz, że jesteś w oddziale master(lub gdziekolwiek jest twoja główna gałąź) i wszystkie twoje pliki są usuwane, a usuwanie jest etapowane. To normalne. Po prostu ręcznie zapłać masterlub zrób git reset --hardi gotowe.
  5. (aby rozwiązać problem zgłoszony przez Royi ) Edytuj .git/configwiersz dodawania pliku fetch = +refs/heads/*:refs/remotes/origin/*po url = <...>w [remote "origin"]sekcji. W przeciwnym razie git fetchnie zobaczy origin/masteri innych gałęzi pochodzenia.

Te kroki są w odwrotnym kierunku od tego pytania , „git-convert normal to bare repository” - w szczególności zwróć uwagę na tę odpowiedź , która stwierdza, że ​​powyższe kroki (w, jak przypuszczam, w dowolnym kierunku) różnią się od zrobienia pliku git-clone. Nie jestem jednak pewien, czy to dotyczy Ciebie, ale wspomniałeś o tym git clonew pytaniu.

simont
źródło
2
Napisałem wszystko, ale nadal, kiedy przesyłam pliki, nie pojawiają się. Co to może być (przełączyłem również denyCurrentBranch na ignorowanie)?
Royi
Dziękuję Ci! Pewnego dnia wszedłem do pracy i stwierdziłem, że moje główne repozytorium - z którego miałem kilka innych drzew roboczych - zgłaszało się jako „nagie”. Wszystkie inne drzewa robocze były w porządku. Nie miałem pojęcia, jak się uwolnić, ale znalazłem tę odpowiedź i zadziałało świetnie.
davidbak
17

Miałem nieco inny scenariusz:

Rozwiązanie:

  • sklonuj nagie repozytorium w tej zawartości, w .gitkatalogu:
    git clone --bare https://github.com/user/project .git
  • Oznacz to jako repozytorium non-bare:
    git config --local --bool core.bare false
  • zresetuj indeks (w przeciwnym razie uważa, że ​​wszystko zostało usunięte, ponieważ .git nagie repozytorium nie zawiera pliku ' index').
    git reset HEAD -- .
    To przywraca plik .git/index.

Skutecznie przekształciłem gołe repozytorium w nie-nagie, zachowując zawartość, którą otrzymałem wcześniej. Pełny skrypt używam od lat obejmuje etapy:

cd /path/to/current/worktree

# That creates a .git directly at the right place
git clone --bare /url/of/repo .git

# restore the link between the local repo and its upstream remote repo
git config --local --bool core.bare false
git config --local remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
git fetch origin
git branch -u origin/master master

# reset the index (not the working tree)
git reset HEAD -- .

Ale rozumiem, że zaakceptowane rozwiązanie (z pomocnym git resetkrokiem dodanym przez ADTC ) jest prostsze.

VonC
źródło
Warto również zauważyć, że jeśli nagie repozytorium zostało utworzone na komputerze z różnymi zakończeniami linii, nadal możesz zobaczyć zmodyfikowane pliki, nawet po wykonaniu tych kroków. Uważam, że to normalne; git próbuje naprawić wysunięcia linii. Nie pewny dlaczego.
Juno Woods
Więc w zasadzie sklonowałeś repozytorium GitHub jako gołe, przełączyłeś się na nie-bare, ręcznie umieściłeś cały plik z twojego „non-repo” i zresetowałeś indeks? Czym to się różni od zwykłego sklonowania repozytorium jako nie nagiego w pierwszej kolejności? Nie-nagi proces klonowania i tak pobierze wszystkie pliki. A jeśli naprawdę chcesz, możesz po prostu zastąpić wyewidencjonowane pliki tymi z „non-repo”.
ADTC
@ADTC celem jest uzyskanie .gitpodfolderu w drzewie roboczym (o którym wiesz, że jest twoim repozytorium), początkowo utworzonego z archiwum (non-git). Nie mogłem wyewidencjonować non-bare repo, ponieważ folder, w którym robiłem transakcję, nie jest pusty. Wykonywanie czynności nie-gołych git clone --no-checkoutw podfolderze zmusiłoby mnie do przejścia o .gitjeden poziom wyżej. Zrobienie samego klona pozwoliło mi bezpośrednio utworzyć .gitpodfolder tam, gdzie chciałem. Możesz zobaczyć skrypt tutaj: github.com/VonC/compileEverything/blob/ ...
VonC
„Nie mogłem wyewidencjonować non-bare repo, ponieważ folder, w którym dokonywałem płatności, nie jest pusty”. Masz na myśli, że masz drzewo robocze inne niż git, które zawiera zmiany, które nie zostały jeszcze zatwierdzone, i zamierzasz zatwierdzić je po przekonwertowaniu go na drzewo robocze z obsługą Git? Tak, myślę, że działa w takim przypadku użycia. Osobiście sklonowałbym do pustego folderu i najpierw porównałbym oba (za pomocą zewnętrznego narzędzia). Ale to tylko ja.
ADTC
@ADTC nr: ja nie mam „non-git drzewo roboczej, która zawiera zmiany, które nie zostały popełnione”. Ja nie chce popełnić niczego. To, co mam, to dokładne drzewo robocze repozytorium: brakuje tylko jego .git. Przychodzę .gitprzez nagiego klona, ​​przekształcam ten .gitfolder w nie-nagi i robię, git resetaby git zorientował się, że drzewo robocze już tam jest. Dokładnie to robi github.com/VonC/compileEverything/blob/… .
VonC
11

Aby uprościć i połączyć informacje w odpowiedziach:

Istnieją trzy różnice, które sprawiają, że nagie repozytorium różni się od zwykłego folderu .git:

  • core.bare jest ustawiony na true w pliku konfiguracyjnym
  • Plik indeksu i drzewo robocze nie istnieją
  • domyślna specyfikacja refspec dla pilota zdalnego sterowania „pochodzenia” nie jest generowana

Możesz więc po prostu przenieść swoje gołe repozytorium do podfolderu .git nowego folderu,

mkdir clone
mv bare.git clone/.git

Zmień core.bare:

cd clone
git config --local --bool core.bare false

Dodaj domyślną referencję źródłową, aby utworzyć git fetchi git pushwybierz te same wartości domyślne, co zwykle:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

I wygeneruj plik indeksu i drzewo robocze:

git checkout master

Zalecam git checkoutraczej niż git resetgenerowanie plików, na wypadek gdyby zostały przypadkowo wpisane w niewłaściwym miejscu.

fuzzyTew
źródło
10

Pytanie pierwotnego autora plakatu dotyczy braku miejsca, aby robić rzeczy w prosty sposób. Dla tych, którzy mają wystarczająco dużo miejsca, odpowiedź jest znacznie prostsza:

git clone foo.git foo
sarnold
źródło
Powodem, dla którego chcę tego uniknąć, jest to, że repozytorium staje się duże, a klon git czasami umiera. Chcę wykonać rsync gołego repozytorium, a następnie przekonwertować go.
Sridhar Sarnobat
@SridharSarnobat, a następnie rozważ wykonanie zadań opisanych w zaakceptowanej odpowiedzi: stackoverflow.com/a/10637882/377270 - tutaj umieściłem tę jednowierszową odpowiedź, aby osoby z wystarczającą ilością wolnego miejsca mogły robić rzeczy w łatwy sposób.
sarnold
6

Jeśli masz mało miejsca na dysku, rozszerzenie drzewa roboczego przez konwersję do normalnego repozytorium będzie problemem, ale możesz przeglądać zawartość samego repozytorium bez konwersji. Użyj git cat-file -p <commit-sha>na dowolnym zatwierdzeniu, aby zobaczyć drzewo, do którego się odnosi. Służy git cat-file -p <blob-sha>do wyświetlania zawartości pliku, do którego odwołuje się obiekt BLOB. Użyj, git show <sha>:pathgdzie sha jest zatwierdzeniem lub drzewem, aby zobaczyć zawartość obiektu BLOB na ścieżce.

William Pursell
źródło
1
Masz rację, ale muszę go wygodniej przeglądać (w menedżerze plików przez ssh). Muszę więc żyć ze zwiększoną przestrzenią dyskową.
nyi
1
Właściwie to jest prawdziwy problem (+1). Działające drzewa często zajmują aż połowę miejsca na dysku; częściowo dlatego, że historie git są agresywnie kompresowane.
jpaugh
4

cd do samego repozytorium i zrób

  1. Zarówno:
git config core.bare false
git reset --hard
  1. Lub
git clone X.git X

(da ci regularne repozytorium git o nazwie X)

nPcomp
źródło
To najprostsze rozwiązanie i mogę potwierdzić w 2019 roku, że działa (pierwsze podejście).
Sridhar Sarnobat
Tylko jedna mała uwaga, o której zapomniałem (dotyczy wszystkich odpowiedzi): musisz edytować plik konfiguracyjny, gdy po raz pierwszy naciśniesz, aby ustawić zdalny adres URL.
Sridhar Sarnobat
2

Jeśli nie masz nic przeciwko pracy na innym drzewie roboczym, to

git worktree add ../repo2
cd ..
git status # now works fine

Należy pamiętać, że to nie jest klon.

Boaz Nahum
źródło
To wspaniale, nie jestem pewien, dlaczego nie jest to wyżej na liście
Nickolai,
0

Wypchnij do wdrożenia

Zamiast konwertować samego pilota do standardowego repozytorium, możesz użyć skryptu po odbiorze w katalogu hooks, aby rozszerzyć repozytorium do katalogu wdrażania.

Oto dobry przykład konfiguracji Push-to-Deploy

Dla ułatwienia jest to przykład zawartości skryptu z powyższego linku. Wdraża tylko wypychanie z gałęzi „master” do katalogu o nazwie „deploy”, który znajduje się na tym samym poziomie, co katalog nadrzędny repozytorium:

#!/usr/bin/env ruby
# post-receive

# 1. Read STDIN (Format: "from_commit to_commit branch_name")
from, to, branch = ARGF.read.split " "

# 2. Only deploy if master branch was pushed
if (branch =~ /master$/) == nil
    puts "Received branch #{branch}, not deploying."
    exit
end

# 3. Copy files to deploy directory
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"
Isaac Brown
źródło