Odłączenie wielu podkatalogów do nowego, oddzielnego repozytorium Git
To pytanie opiera się na odłączeniu podkatalogu do osobnego repozytorium Git
Zamiast odłączać pojedynczy podkatalog, chcę odłączyć kilka. Na przykład moje obecne drzewo katalogów wygląda tak:
/apps
/AAA
/BBB
/CCC
/libs
/XXX
/YYY
/ZZZ
A ja wolałabym zamiast tego:
/apps
/AAA
/libs
/XXX
Argument --subdirectory-filter
do git filter-branch
nie zadziała, ponieważ pozbywa się wszystkiego poza podanym katalogiem przy pierwszym uruchomieniu. Myślałem, że używając argumentu --index-filter
dla wszystkich niechcianych pliki będą działać (choć żmudne), ale jeśli spróbuję uruchomić go więcej niż raz, dostaję następujący komunikat:
Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f
Jakieś pomysły? TIA 10 answers
Zamiast zajmować się subshellem i używać ext glob (jak zasugerował kynan), Spróbuj tego znacznie prostszego podejścia:
git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all
Jak wspomniano przez void.komentarz pointera , usunie wszystko oprócz apps/AAA
i libs/XXX
z bieżącego repozytorium.
Prune empty merge commits
To pozostawia wiele pustych połączeń. Można je usunąć za pomocą innego przejścia opisanego przez raphinesse w jego odpowiedź :
git filter-branch --prune-empty --parent-filter \
'sed "s/-p //g" | xargs -r git show-branch --independent | sed "s/\</-p /g"'
⚠️ Uwaga : powyższe musi używać wersji GNU sed
i xargs
w przeciwnym razie usunie wszystkie commity jako xargs
nie powiedzie się. brew install gnu-sed findutils
a następnie użyj gsed
i gxargs
:
git filter-branch --prune-empty --parent-filter \
'gsed "s/-p //g" | gxargs git show-branch --independent | gsed "s/\</-p /g"'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-06 17:09:52
Manual steps with simple Git commands
Plan polega na podzieleniu poszczególnych katalogów na własne repozytoria, a następnie połączeniu ich ze sobą. Poniższe kroki ręczne nie wykorzystywały geek-to-use skryptów, ale łatwe do zrozumienia polecenia i może pomóc scalić dodatkowe N podfolderów do innego pojedynczego repozytorium.
Divide
Załóżmy, że twój oryginalny repo to: original_repo
1 - Podział aplikacji:
git clone original_repo apps-repo
cd apps-repo
git filter-branch --prune-empty --subdirectory-filter apps master
2 - Split libs
git clone original_repo libs-repo
cd libs-repo
git filter-branch --prune-empty --subdirectory-filter libs master
Kontynuuj, jeśli masz więcej niż 2 foldery. Teraz będziesz mieć dwa nowe i tymczasowe repozytorium git.
Conquer poprzez łączenie aplikacji i bibliotek
3 - przygotuj nowy repo:
mkdir my-desired-repo
cd my-desired-repo
git init
I będziesz musiał zrobić co najmniej jeden commit. Jeśli następujące trzy linie powinny zostać pominięte, twój pierwszy repo pojawi się natychmiast pod rootem twojego repo:
touch a_file_and_make_a_commit # see user's feedback
git add a_file_and_make_a_commit
git commit -am "at least one commit is needed for it to work"
Z uruchomionym plikiem tymczasowym, merge
komenda w dalszej sekcji zatrzyma się jako oczekiwane.
Biorąc pod uwagę opinie użytkowników, zamiast dodawać losowy plik jak a_file_and_make_a_commit
, możesz dodać .gitignore
, lub README.md
itp.
4 - Merge apps repo first:
git remote add apps-repo ../apps-repo
git fetch apps-repo
git merge -s ours --no-commit apps-repo/master # see below note.
git read-tree --prefix=apps -u apps-repo/master
git commit -m "import apps"
Teraz powinieneś zobaczyć katalog apps w nowym repozytorium. git log
powinien pokazywać wszystkie istotne historyczne komunikaty commit.
Uwaga: Jak zauważył Chris poniżej w komentarzach, dla nowszej wersji(>=2.9) git, musisz podać --allow-unrelated-histories
za pomocą git merge
5-Merge libs repo następny w ten sam sposób:
git remote add libs-repo ../libs-repo
git fetch libs-repo
git merge -s ours --no-commit libs-repo/master # see above note.
git read-tree --prefix=libs -u libs-repo/master
git commit -m "import libs"
Kontynuuj, jeśli masz więcej niż 2 repo do scalenia.
Referencja: Połącz podkatalog innego repozytorium z git
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 20:11:55
Dlaczego chcesz uciekać filter-branch
więcej niż raz? Możesz to zrobić za jednym zamachem, więc nie musisz tego wymuszać (zauważ, że musisz włączyć extglob
w swojej powłoce, aby to działało): {]}
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all
To powinno pozbyć się wszystkich zmian w niechcianych podkatalogach i zachować wszystkie gałęzie i commity (chyba że wpływają one tylko na pliki w podkatalogach przycinanych, na mocy --prune-empty
) - nie ma problemu z duplikatami commitów itp.
Po tej operacji niechciane katalogi będą notowane jako untracked przez git status
.
$(ls ...)
jest konieczne s. t. extglob
jest oceniana przez powłokę zamiast filtra indeksu, który używa wbudowanego sh
eval
(gdzie extglob
nie jest dostępna). Zobacz Jak włączyć opcje powłoki w git? aby uzyskać więcej informacji na ten temat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05
Odpowiadam na moje pytanie... po wielu próbach i błędach.
Udało mi się to zrobić używając kombinacji git subtree
i git-stitch-repo
. Instrukcje te są oparte na:
- współdzielenie kodu pomiędzy projektami za pomocą Git subtree- http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree /
- odpowiednie narzędzie do pracy: git-stitch-repo – http://ifup.org/2009/02/07/the-right-tool-for-the-job-git-stitch-repo /
Najpierw wyciągnąłem katalogi, które chciałem zachować w osobnym repozytorium:
cd origRepo
git subtree split -P apps/AAA -b aaa
git subtree split -P libs/XXX -b xxx
cd ..
mkdir aaaRepo
cd aaaRepo
git init
git fetch ../origRepo aaa
git checkout -b master FETCH_HEAD
cd ..
mkdir xxxRepo
cd xxxRepo
git init
git fetch ../origRepo xxx
git checkout -b master FETCH_HEAD
Następnie utworzyłem nowe puste repozytorium i zaimportowałem/zszyłem do niego dwa ostatnie:
cd ..
mkdir newRepo
cd newRepo
git init
git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import
Tworzy to dwie gałęzie, master-A
i master-B
, z których każda zawiera zawartość jednego z szytych repo. Aby je połączyć i posprzątać:
git checkout master-A
git pull . master-B
git checkout master
git branch -d master-A
git branch -d master-B
Teraz nie jestem do końca pewien jak/kiedy dzieje się tak, ale po pierwszym checkout
i pull
kod magicznie łączy się z gałęzią master (każdy wgląd w to, co się tutaj dzieje, jest doceniany!)
Wszystko wydaje się działać zgodnie z oczekiwaniami, z wyjątkiem tego, że jeśli przejrzę historię zatwierdzeń newRepo
, pojawią się duplikaty, gdy zestaw zmian wpłynie zarówno na apps/AAA
, jak i libs/XXX
. Jeśli istnieje sposób na usunięcie duplikatów, byłoby to idealne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-20 18:40:19
Proste rozwiązanie: git-filter-repo
Miałem podobny problem i po przejrzeniu różnych podejść wymienionych tutaj, odkryłem git-filter-repo. Jest to zalecane jako alternatywa dla Git-filter-branch w oficjalnej dokumentacji git tutaj .
Aby utworzyć nowe repozytorium z podzbioru katalogów w istniejącym repozytorium, możesz użyć polecenia:
git filter-repo --path <file_to_keep>
Filtruj wiele plików / folderów, łącząc je w łańcuch:
git filter-repo --path keepthisfile --path keepthisfolder/
Więc do odpowiedz oryginalne pytanie, w git-filter-repo potrzebowałbyś następującego polecenia:
git filter-repo --path apps/AAA/ --path libs/XXX/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-19 17:40:06
Napisałem filtr Gita, aby rozwiązać dokładnie ten problem. Ma fantastyczną nazwę git_filter i znajduje się na github tutaj:
Https://github.com/slobobaby/git_filter
Opiera się na znakomitym libgit2.
Musiałem podzielić duże repozytorium z wieloma commitami (~100000), a uruchomienie rozwiązań opartych na git filter-branch trwało kilka dni. git_filter zajmuje minutę, aby zrobić to samo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-17 21:06:03
Use' Git splits ' Git extension
git splits
jest skryptem bash, który jest opakowaniem wokół git branch-filter
, który stworzyłem jako rozszerzenie git, bazując na jkeating ' s solution .
Został stworzony dokładnie do tej sytuacji. W przypadku błędu spróbuj użyć opcji git splits -f
, aby wymusić usunięcie kopii zapasowej. Ponieważ git splits
działa na nowej gałęzi, nie przepisuje bieżącej gałęzi, więc kopia zapasowa jest zbędna. Zobacz readme po więcej szczegółów i upewnij się, że używasz go na Kopia / Klon repo (na wszelki wypadek!).
- zainstaluj
git splits
. Podziel katalogi na lokalną gałąź
#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ apps/AAA libs/ZZZUtwórz gdzieś pusty repo. Założymy, że stworzyliśmy puste repo o nazwie
xyz
na Githubie, które ma path :[email protected]:simpliwp/xyz.git
/ align = "left" /
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz [email protected]:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master
Sklonuj nowo utworzony zdalny repo do nowego katalogu lokalnego
#change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone [email protected]:simpliwp/xyz.git
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:29
git clone [email protected]:thing.git
cd thing
git fetch
for originBranch in `git branch -r | grep -v master`; do
branch=${originBranch:7:${#originBranch}}
git checkout $branch
done
git checkout master
git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- dir1 dir2 .gitignore' --prune-empty -- --all
git remote set-url origin [email protected]:newthing.git
git push --all
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 13:37:51
Tak. Wymuś nadpisanie kopii zapasowej, używając znacznika -f
przy kolejnych wywołaniach filter-branch
, aby nadpisać to Ostrzeżenie. :) W przeciwnym razie myślę, że masz rozwiązanie (czyli wyeliminowanie niechcianego katalogu na raz za pomocą filter-branch
).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-05 20:59:57
Usuń kopię zapasową obecną pod .katalog git w refs / original, jak sugeruje wiadomość. Katalog jest ukryty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-07 04:07:54