Czy chcesz sprawdzić podkatalogi w Git?


160

Czy można sprawdzić podkatalogi repozytorium w Git?

Wyobraź sobie, że konfiguruję nową instalację WordPress. Utworzę dwa nowe katalogi dla mojej wtyczki i dostosowywania motywu:

  • wordpress/wp-content/plugins/myplugins/
  • wordpress/wp-content/themes/mytheme/

Chcę utrzymywać te katalogi przez Git. W Subversion osiągnąłbym to, mając trunk/myplugins/i trunk/mytheme/katalogi i sprawdzając podkatalogi. Czy Git ma sposób na wykonanie tego samego zadania przy użyciu jednego repozytorium?

Mogłem po prostu tęsknić za paradygmatem Git, jako długoletni użytkownik SVN z niewielkim kontaktem z Git.

Edycja: wiele gałęzi przechowujących różne treści to interesujący sposób na rozwiązanie tego problemu.


2
dlaczego nie sprawdzisz całego repozytorium i nie utworzysz symbolicznego łącza do podkatalogów, z którymi chcesz pracować?
losowość2077



Czy możliwe jest rzadkie pobieranie i odwoływanie się do repozytorium Git?
luka5z

Odpowiedzi:


121

Rzadkie płatnościteraz dostępne w Git 1.7 .

Zobacz także pytanie „ Czy można wykonać rzadkie pobieranie bez uprzedniego sprawdzenia całego repozytorium? ”.

Zwróć uwagę, że rzadkie wyewidencjonowania nadal wymagają pobrania całego repozytorium, mimo że niektóre pliki pobierane przez Git nie trafią do twojego drzewa roboczego.


1
Gdzie jest git cloneproste polecenie? Cóż, używam tej odpowiedzi , działa!
Peter Krauss

4
Czy jest sposób na zmianę nazw tych folderów? Jeśli rzadko płacę /foo/bar/foobar, czy można zobaczyć to tylko /foobarw moim lokalnym repozytorium?
graywolf

17

Nie ma prawdziwego sposobu, aby to zrobić w git. A jeśli nie będziesz wprowadzać zmian, które wpłyną na oba drzewa jednocześnie jako jedną jednostkę pracy, nie ma powodu, aby używać jednego repozytorium do obu. Pomyślałem, że przegapiłbym tę funkcję Subversion, ale odkryłem, że tworzenie repozytoriów wiąże się z tak niewielkim narzutem administracyjnym (po prostu z powodu faktu, że repozytoria są przechowywane tuż obok ich kopii roboczej, zamiast wymagać ode mnie wyraźnego wybrania miejsca poza kopia robocza), do których przyzwyczaiłem się po prostu tworzyć wiele małych repozytoriów o jednym przeznaczeniu.

Jeśli jednak nalegasz (lub naprawdę tego potrzebujesz), możesz utworzyć repozytorium git z tylko mythemei mypluginskatalogami i dowiązaniami symbolicznymi do tych z instalacji WordPress.


MDCore napisał:

zatwierdzenie np. mytheme zwiększy numer wersji dla myplugin

Zauważ, że nie jest to problemem dla gita, jeśli zdecydujesz się umieścić oba katalogi w jednym repozytorium, ponieważ git całkowicie eliminuje koncepcję monotonicznie rosnących numerów wersji w dowolnej formie.

Jedynym kryterium tego, co należy umieścić w jednym repozytorium w git, jest to, czy stanowi on pojedynczą jednostkę, tj. w twoim przypadku, czy są zmiany, w których nie ma sensu patrzeć na edycje w każdym katalogu oddzielnie. Jeśli masz zmiany, w których musisz edytować pliki w obu katalogach jednocześnie, a zmiany należą do siebie, powinny to być jedno repozytorium. Jeśli nie, nie łącz ich razem.

Git naprawdę chce, abyś używał oddzielnych repozytoriów dla oddzielnych jednostek.

podmoduły

Podmoduły nie są odpowiedzią na chęć utrzymywania obu katalogów w jednym repozytorium, ponieważ w rzeczywistości wymuszałyby posiadanie oddzielnego repozytorium dla każdego katalogu, które są następnie łączone w innym repozytorium za pomocą modułów podrzędnych. Gorzej, ponieważ katalogi wewnątrz instalacji WordPress nie są bezpośrednimi podkatalogami tego samego katalogu i są również częścią hierarchii z wieloma innymi plikami, używanie repozytoriów dla poszczególnych katalogów jako modułów podrzędnych w ujednoliconym repozytorium nie przyniosłoby żadnych korzyści, ponieważ ujednolicony repozytorium nie odzwierciedla żadnego przypadku użycia / potrzeby.


Gdzie de git cloneprosta sekwencja poleceń? Cóż, używam tej odpowiedzi , działa!
Peter Krauss

16

Jedną rzeczą, której nie lubię w rzadkich pobrań, jest to, że jeśli chcesz pobrać podkatalog, który jest głęboki na kilka katalogów, twoja struktura katalogów musi zawierać wszystkie katalogi do niego prowadzące.

Sposób obejścia tego polega na sklonowaniu repozytorium w miejscu, które nie jest moim obszarem roboczym, a następnie utworzeniu dowiązania symbolicznego w katalogu mojego obszaru roboczego do podkatalogu w repozytorium. Git działa w ten sposób całkiem nieźle, ponieważ rzeczy takie jak status git wyświetlają pliki zmian w stosunku do twojego bieżącego katalogu roboczego.


Działa to tylko w systemie operacyjnym obsługującym dowiązania symboliczne. Muszą zmienić sposób, w jaki działają rzadkie kasy.
Anders Lindén

1
+1 dla pomysłu z dowiązaniem symbolicznym w wyewidencjonowanym katalogu. Jednak rzadka płatność i symboliczne łącze nie wykluczają się wzajemnie: nie potrzebujesz pełnoprawnego klonu.
apitsch

10

W rzeczywistości „wąskie”, „częściowe” lub „rzadkie” testy są obecnie intensywnie rozwijane dla Git. Uwaga, nadal będziesz mieć pełne repozytorium pod .git. Tak więc pozostałe dwa posty są aktualne dla bieżącego stanu Git, ale wygląda na to, że ostatecznie będziemy w stanie wykonać rzadkie sprawdzenia. Sprawdź listy mailingowe, jeśli chcesz poznać więcej szczegółów - szybko się zmieniają.


Dobrze wiedzieć! Lubię mieć takie blisko powiązane katalogi w jednym repozytorium i zrobiłbym to, jeśli to w ogóle możliwe.
Annika Backstrom

5

git clone --filter z Git 2.19

Ta opcja faktycznie pominie pobieranie niepotrzebnych obiektów z serwera:

git clone --depth 1 --no-checkout --filter=blob:none \
  "file://$(pwd)/server_repo" local_repo
cd local_repo
git checkout master -- mdir/

Serwer powinien być skonfigurowany z:

git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

Od wersji 2.19.0 nie ma obsługi serwera, ale można ją już przetestować lokalnie.

file://$(path)jest wymagany do przezwyciężenia git cloneoszustw związanych z protokołem: jak płytko sklonować lokalne repozytorium git ze ścieżką względną?

Pamiętaj, że --depth 1już sugeruje --single-branch, zobacz także: Jak sklonować pojedynczą gałąź w Git?

TODO: --filter=blob:nonepomija wszystkie obiekty blob, ale nadal pobiera wszystkie obiekty drzewa. Ale w normalnym repozytorium powinno to być małe w porównaniu do samych plików, więc jest już wystarczająco dobre. Zapytany pod adresem : https://www.spinics.net/lists/git/msg342006.html Devs odpowiedział, --filter=tree:0że pracuje nad tym.

Format --filterjest udokumentowany man git-rev-list.

Do zdalnego protokołu Git wprowadzono rozszerzenie obsługujące tę funkcję.

Dokumenty w drzewie Git:

Wypróbuj to

#!/usr/bin/env bash
set -eu

list-objects() (
  git rev-list --all --objects
  echo "master commit SHA: $(git log -1 --format="%H")"
  echo "mybranch commit SHA: $(git log -1 --format="%H")"
  git ls-tree master
  git ls-tree mybranch | grep mybranch
  git ls-tree master~ | grep root
)

# Reproducibility.
export GIT_COMMITTER_NAME='a'
export GIT_COMMITTER_EMAIL='a'
export GIT_AUTHOR_NAME='a'
export GIT_AUTHOR_EMAIL='a'
export GIT_COMMITTER_DATE='2000-01-01T00:00:00+0000'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'

rm -rf server_repo local_repo
mkdir server_repo
cd server_repo

# Create repo.
git init --quiet
git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

# First commit.
# Directories present in all branches.
mkdir d1 d2
printf 'd1/a' > ./d1/a
printf 'd1/b' > ./d1/b
printf 'd2/a' > ./d2/a
printf 'd2/b' > ./d2/b
# Present only in root.
mkdir 'root'
printf 'root' > ./root/root
git add .
git commit -m 'root' --quiet

# Second commit only on master.
git rm --quiet -r ./root
mkdir 'master'
printf 'master' > ./master/master
git add .
git commit -m 'master commit' --quiet

# Second commit only on mybranch.
git checkout -b mybranch --quiet master~
git rm --quiet -r ./root
mkdir 'mybranch'
printf 'mybranch' > ./mybranch/mybranch
git add .
git commit -m 'mybranch commit' --quiet

echo "# List and identify all objects"
list-objects
echo

# Restore master.
git checkout --quiet master
cd ..

# Clone. Don't checkout for now, only .git/ dir.
git clone --depth 1 --quiet --no-checkout --filter=blob:none "file://$(pwd)/server_repo" local_repo
cd local_repo

# List missing objects from master.
echo "# Missing objects after --no-checkout"
git rev-list --all --quiet --objects --missing=print
echo

echo "# Git checkout fails without internet"
mv ../server_repo ../server_repo.off
! git checkout master
echo

echo "# Git checkout fetches the missing directory from internet"
mv ../server_repo.off ../server_repo
git checkout master -- d1/
echo

echo "# Missing objects after checking out d1"
git rev-list --all --quiet --objects --missing=print

GitHub upstream .

Dane wyjściowe w Git v2.19:

# List and identify all objects
c6fcdfaf2b1462f809aecdad83a186eeec00f9c1
fc5e97944480982cfc180a6d6634699921ee63ec
7251a83be9a03161acde7b71a8fda9be19f47128
62d67bce3c672fe2b9065f372726a11e57bade7e
b64bf435a3e54c5208a1b70b7bcb0fc627463a75 d1
308150e8fddde043f3dbbb8573abb6af1df96e63 d1/a
f70a17f51b7b30fec48a32e4f19ac15e261fd1a4 d1/b
84de03c312dc741d0f2a66df7b2f168d823e122a d2
0975df9b39e23c15f63db194df7f45c76528bccb d2/a
41484c13520fcbb6e7243a26fdb1fc9405c08520 d2/b
7d5230379e4652f1b1da7ed1e78e0b8253e03ba3 master
8b25206ff90e9432f6f1a8600f87a7bd695a24af master/master
ef29f15c9a7c5417944cc09711b6a9ee51b01d89
19f7a4ca4a038aff89d803f017f76d2b66063043 mybranch
1b671b190e293aa091239b8b5e8c149411d00523 mybranch/mybranch
c3760bb1a0ece87cdbaf9a563c77a45e30a4e30e
a0234da53ec608b54813b4271fbf00ba5318b99f root
93ca1422a8da0a9effc465eccbcb17e23015542d root/root
master commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
mybranch commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
040000 tree b64bf435a3e54c5208a1b70b7bcb0fc627463a75    d1
040000 tree 84de03c312dc741d0f2a66df7b2f168d823e122a    d2
040000 tree 7d5230379e4652f1b1da7ed1e78e0b8253e03ba3    master
040000 tree 19f7a4ca4a038aff89d803f017f76d2b66063043    mybranch
040000 tree a0234da53ec608b54813b4271fbf00ba5318b99f    root

# Missing objects after --no-checkout
?f70a17f51b7b30fec48a32e4f19ac15e261fd1a4
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb
?308150e8fddde043f3dbbb8573abb6af1df96e63

# Git checkout fails without internet
fatal: '/home/ciro/bak/git/test-git-web-interface/other-test-repos/partial-clone.tmp/server_repo' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

# Git checkout fetches the missing directory from internet
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.

# Missing objects after checking out d1
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb

Wnioski: brak wszystkich plamek z zewnątrz d1/.

Należy pamiętać, że root/rooti mybranch/mybranchsą również brakuje, ale --depth 1ukrywa, że z listy brakujących plików. Jeśli usuniesz --depth 1, zostaną one wyświetlone na liście brakujących plików.


1

Jak wskazuje Twoja edycja, możesz użyć dwóch oddzielnych gałęzi do przechowywania dwóch oddzielnych katalogów. Dzięki temu oba są w tym samym repozytorium, ale nadal nie możesz mieć zatwierdzeń obejmujących oba drzewa katalogów. Jeśli masz zmianę w jednym, która wymaga zmiany w drugim, będziesz musiał to zrobić jako dwa oddzielne zatwierdzenia i otworzysz możliwość, że para pobrań dwóch katalogów może stracić synchronizację.

Jeśli chcesz traktować parę katalogów jako jedną jednostkę, możesz użyć „wordpress / wp-content” jako katalogu głównego repozytorium i użyć pliku .gitignore na najwyższym poziomie, aby zignorować wszystko oprócz dwóch interesujących podkatalogów. Jest to prawdopodobnie najbardziej rozsądne rozwiązanie w tym momencie.

Rzadko wypisuje się rzekomo od dwóch lat, ale nadal nie ma śladu po nich w repozytorium rozwoju git, ani żadnych oznak, że niezbędne zmiany tam dotrą. Nie liczyłbym na nich.


1

Nie możesz pobrać pojedynczego katalogu repozytorium, ponieważ całe repozytorium jest obsługiwane przez pojedynczy folder .git w katalogu głównym projektu zamiast niezliczonych katalogów .svn subversion.

Problem z pracą nad wtyczkami w pojedynczym repozytorium polega na tym, że zatwierdzenie np. Mytheme zwiększy numer wersji myplugin , więc nawet w subversion lepiej jest używać oddzielnych repozytoriów.

Paradygmat subversion dla podprojektów to svn: externals, który tłumaczy się nieco na moduły podrzędne w git (ale nie do końca w przypadku, gdy wcześniej używałeś svn: externals).


0

Tu jest inspiracja. Po prostu użyj shell regexlub git regex.

git checkout commit_id */*.bat  # *.bat in 1-depth subdir exclude current dir, shell regex  
git checkout commit_id '*.bat'  # *.bat in all subdir include current dir, git regex

Użyj cudzysłowu, aby uniknąć interpretacji wyrażeń regularnych powłoki i przekazać symbole wieloznaczne do git.

Pierwsza nie jest rekurencyjna, tylko pliki o głębokości 1 subdir. Ale druga jest rekurencyjna.

Jeśli chodzi o twoją sytuację, poniższe mogą być wystarczające.

git checkout master */*/wp-content/*/*
git checkout master '*/wp-content/*'

Po prostu zhakuj linie zgodnie z wymaganiami.


0

Możesz cofnąć niezatwierdzone zmiany tylko do określonego pliku lub katalogu:

git checkout [some_dir|file.txt]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.