Odłącz (przenieś) podkatalog do oddzielnego repozytorium Git

Mam repozytorium Git , które zawiera wiele podkatalogów. Teraz odkryłem, że jeden z podkatalogów jest niezwiązany z drugim i powinien być odłączony do osobnego repozytorium.

Jak mogę to zrobić, zachowując historię plików w podkatalogu?

Myślę, że mógłbym zrobić klon i usunąć niechciane części każdego klona, ale przypuszczam, że to da mi pełne drzewo podczas sprawdzania starszej wersji itp. To może być akceptowalne, ale wolałbym móc udawać, że oba repozytoria nie mają wspólnej historii.

Żeby było jasne, mam następującą strukturę:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

Ale wolałabym zamiast tego:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/
Author: Nick Volynkin, 2008-12-11

22 answers

Update: ten proces jest tak powszechny, że zespół git znacznie uprościł go za pomocą nowego narzędzia, git subtree. Zobacz tutaj: odłącz (przenieś) podkatalog do oddzielnego repozytorium Git


Chcesz sklonować swoje repozytorium, a następnie użyć git filter-branch, aby oznaczyć wszystko poza podkatalogiem, który chcesz w nowym repo, aby został usunięty.

  1. Aby sklonować lokalne repozytorium:

    git clone /XYZ /ABC
    

    (Uwaga: repozytorium zostanie sklonowane za pomocą twardych linków, ale nie jest to problemem, ponieważ połączone pliki nie będą same w sobie modyfikowane-będą tworzone nowe.)

  2. Teraz zachowajmy interesujące gałęzie, które chcemy również przepisać, a następnie usuńmy origin, aby uniknąć popychania i upewnić się, że stare commity nie będą odwoływane przez origin: {]}

    cd /ABC
    for i in branch1 br2 br3; do git branch -t $i origin/$i; done
    git remote rm origin
    

    Lub dla wszystkich odległych gałęzi:

    cd /ABC
    for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
    git remote rm origin
    
  3. Teraz możesz również usunąć tagi, które nie mają związku z podprojekt; możesz to zrobić również później, ale być może będziesz musiał ponownie przyciąć repo. Nie zrobiłem tego i dostałem WARNING: Ref 'refs/tags/v0.1' is unchanged dla wszystkich tagów (ponieważ wszystkie były niezwiązane z podprojektem); dodatkowo, po usunięciu takich tagów więcej miejsca zostanie odzyskane. Najwyraźniej git filter-branch powinno być w stanie przepisać inne tagi, ale nie mogłem tego zweryfikować. Jeśli chcesz usunąć wszystkie tagi, użyj git tag -l | xargs git tag -d.

  4. Następnie użyj filter-branch i reset, aby wykluczyć inne pliki, aby można je było przycinać. Let ' s also dodaj --tag-name-filter cat --prune-empty, aby usunąć puste commity i przepisać znaczniki (zauważ, że będzie to wymagało usunięcia ich podpisu):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    
    Można też zmienić tylko gałąź nagłówka i zignorować znaczniki i inne gałęzie:
    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
    
  5. Następnie usuń Backup reflogs, aby przestrzeń mogła zostać odzyskana (chociaż teraz Operacja jest destrukcyjna)]}
    git reset --hard
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --aggressive --prune=now
    

    A teraz masz lokalne repozytorium Git podkatalogu ABC z zachowaną historią.

Uwaga: dla większości zastosowań, {[7] } rzeczywiście powinien mieć dodany parametr -- --all. Tak, to naprawdę --spacja-- all. To muszą być ostatnie parametry polecenia. Jak odkrył Matli, to utrzymuje gałęzie projektu i tagi zawarte w nowym repo.

Edit: różne sugestie z poniższych komentarzy zostały włączone, aby upewnić się, na przykład, że repozytorium jest rzeczywiście skurczone (co nie było zawsze tak było wcześniej).

 1159
Author: Paul,
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-06-20 22:57:50

The Easy Way™

Okazuje się, że jest to tak powszechna i użyteczna praktyka, że władcy Gita sprawili, że było to naprawdę łatwe, ale musisz mieć nowszą wersję Gita (>= 1.7.11 maj 2012). Zobacz dodatek aby dowiedzieć się jak zainstalować najnowszy git. Poniżej znajduje się przykład z prawdziwego świata w artykule .

  1. Przygotuj stare repo

    pushd <big-repo>
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    Uwaga: <name-of-folder> nie może zawierać znaków początkowych ani końcowych. Na przykład, folder o nazwie subproject musi być przekazany jako subproject, a nie ./subproject/

    Uwaga dla użytkowników systemu windows: gdy głębokość folderu wynosi > 1, {[17] } musi mieć separator folderów w stylu *Nix ( / ). Na przykład, folder o nazwie {[22] } musi być przekazany jako path1/path2/subproject

  2. Utwórz nowy repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. [[38]}Połącz nowe repo z Github lub gdziekolwiek
    git remote add origin <[email protected]:my-user/new-repo.git>
    git push origin -u master
    
  4. Czyszczenie, w razie potrzeby

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    Uwaga: To pozostawia wszystkie odniesienia Historyczne w repozytorium.Zobacz dodatek poniżej, jeśli naprawdę obawiasz się, że popełniłeś hasło lub musisz zmniejszyć rozmiar pliku folderu .git.

...

Walkthrough

Są to te same kroki jak powyżej , ale wykonując dokładne kroki dla mojego repozytorium zamiast używać <meta-named-things>.

Oto projekt, który mam do implementacji modułów przeglądarki JavaScript w węzeł:

tree ~/Code/node-browser-compat

node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator
Chcę podzielić pojedynczy folder, btoa, na osobne repozytorium git
pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd

Mam teraz nową gałąź, btoa-only, która posiada commity tylko dla btoa i chcę utworzyć nowe repozytorium.

mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only
[20]} następnie tworzę nowe repo na Githubie lub bitbucket, lub cokolwiek i dodaję to origin (btw, "origin" to tylko konwencja , a nie część polecenia - można by to nazwać "remote-server" lub jak tam chcesz)
git remote add origin [email protected]:node-browser-compat/btoa.git
git push origin -u master

Happy dzień!

Uwaga: jeśli utworzyłeś repo z README.md, .gitignore i LICENSE, musisz najpierw pociągnąć:

git pull origin -u master
git push origin -u master

Na koniec chcę usunąć folder z większego repo

git rm -rf btoa

...

Dodatek

Najnowszy git na OS X

Aby pobrać najnowszą wersję git:

brew install git

Aby uzyskać brew dla OS X:

Http://brew.sh

Najnowszy git na Ubuntu

sudo apt-get update
sudo apt-get install git
git --version

If that doesn ' t work (you mieć bardzo starą wersję ubuntu), spróbuj

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

Jeśli to nadal nie działa, spróbuj

sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree
Dzięki rui.araujo z komentarzy.

Czyszczenie historii

Domyślnie usunięcie plików z git nie usuwa ich z git, po prostu potwierdza, że już ich nie ma. Jeśli chcesz rzeczywiście usunąć odniesienia historyczne( tzn. masz popełnione hasło), musisz to zrobić: {]}

git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD

Po tym możesz sprawdzić, że Twój plik lub folder w ogóle nie pojawia się w historii Gita

git log -- <name-of-folder> # should show nothing
Jednak nie możesz "wcisnąć" usunięć do Githuba i tym podobnych. Jeśli spróbujesz, dostaniesz błąd i będziesz musiał git pull, zanim będziesz mógł git push - a potem wrócisz do wszystkiego w swojej historii.

Więc jeśli chcesz usunąć historię z "origin" - czyli usunąć ją z github, bitbucket, itp - Musisz usunąć repo i ponownie wcisnąć przyciętą kopię repo. Ale czekaj - Jest więcej! - Jeśli naprawdę martwisz się o pozbycie się hasła lub czegoś podobnego, musisz przyciąć kopię zapasową (patrz poniżej).

Making .git smaller

Wspomniane polecenie delete history wciąż pozostawia po sobie kilka plików kopii zapasowych - ponieważ git jest zbyt miły, pomagając Ci nie zrujnować twojego repo przez przypadek. Ostatecznie usunie osierocone pliki w ciągu dni i miesięcy, ale pozostawia je tam na jakiś czas, jeśli zdasz sobie sprawę że przypadkowo usunąłeś coś, czego nie chciałeś.

Więc jeśli naprawdę chcesz opróżnić kosz aby zmniejszyć rozmiar klonu repo natychmiast musisz zrobić te wszystkie naprawdę dziwne rzeczy:

rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune=now

git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune

To powiedziawszy, polecam nie wykonywać tych kroków, chyba że wiesz, że musisz - na wypadek, gdybyś nie przyciął złego podkatalogu, wiesz? Pliki kopii zapasowych nie powinny być sklonowane po naciśnięciu repo, będą po prostu w Twoim lokalnym przyjąłem.

Kredyt

 1138
Author: CoolAJ86,
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:26

Odpowiedź Paula tworzy nowe repozytorium zawierające / ABC, ale nie usuwa /ABC z / XYZ. Następujące polecenie usunie /ABC z wewnątrz / XYZ:

git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD

Oczywiście najpierw przetestuj go w repozytorium 'clone --no-hardlinks' i wykonaj go poleceniami reset, gc i prune.

 131
Author: pgs,
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:18:26

Odkryłem, że aby poprawnie usunąć starą historię z nowego repozytorium, musisz wykonać trochę więcej pracy po kroku filter-branch.

  1. Zrób klon i filtr:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. Usuń wszystkie odniesienia do starej historii. "origin" śledził Twój klon, a "original" to miejsce, w którym filter-branch zapisuje stare rzeczy: {]}

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. Nawet teraz twoja historia może utknąć w pliku packfile, którego fsck nie dotknie. Rozedrzyj to na strzępy, tworzenie nowego pliku packfile i usuwanie nieużywanych obiektów:

    git repack -ad
    

Istnieje wyjaśnienie tego w instrukcji dla filter-branch .

 94
Author: Josh Lee,
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
2011-01-05 18:18:29

Edycja: dodano skrypt Bash.

Odpowiedzi podane tutaj zadziałały tylko częściowo dla mnie; wiele dużych plików pozostało w pamięci podręcznej. Co w końcu zadziałało (po godzinach w #git na freenode):

git clone --no-hardlinks file:///SOURCE /tmp/blubb
cd blubb
git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT  --prune-empty --tag-name-filter cat -- --all
git clone file:///tmp/blubb/ /tmp/blooh
cd /tmp/blooh
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now

W przypadku poprzednich rozwiązań rozmiar repozytorium wynosił około 100 MB. Ten zmniejszył go do 1,7 MB. Może to komuś pomoże:)


Następujący skrypt bash automatyzuje zadanie:

!/bin/bash

if (( $# < 3 ))
then
    echo "Usage:   $0 </path/to/repo/> <directory/to/extract/> <newName>"
    echo
    echo "Example: $0 /Projects/42.git first/answer/ firstAnswer"
    exit 1
fi


clone=/tmp/${3}Clone
newN=/tmp/${3}

git clone --no-hardlinks file://$1 ${clone}
cd ${clone}

git filter-branch --subdirectory-filter $2  --prune-empty --tag-name-filter cat -- --all

git clone file://${clone} ${newN}
cd ${newN}

git reflog expire --expire=now --all
git repack -ad
git gc --prune=now
 38
Author: Simon A. Eugster,
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-04-11 14:00:08

To nie jest już tak skomplikowane, że możesz użyć komendy git filter-branch na klonie twojego repo, aby pobrać podkatalogi, których nie chcesz, a następnie wcisnąć do nowego pilota.

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .
 21
Author: jeremyjjbrown,
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-04-20 18:43:21

Update : moduł Git-subtree był tak przydatny, że zespół git wciągnął go do core i stworzył git subtree. Zobacz tutaj: odłącz (przenieś) podkatalog do oddzielnego repozytorium Git

Git-subtree może być przydatne do tego

Http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (deprecated)

Http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/

 19
Author: D W,
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:18:26

Oto mała modyfikacja CoolAJ86 ' S "the Easy Way™" answer w celu podzielenia wielu podfolderów (powiedzmy sub1i sub2) do nowego repozytorium git.

The Easy Way™ (wiele podkatalogów)

  1. Przygotuj stare repo

    pushd <big-repo>
    git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD
    git subtree split -P <name-of-folder> -b <name-of-new-branch>
    popd
    

    Uwaga: <name-of-folder> nie może zawierać znaków początkowych ani końcowych. Na przykład, folder o nazwie {[7] } musi być przekazany jako subproject, a nie ./subproject/

    Uwaga dla użytkownicy systemu windows: gdy głębokość folderu wynosi > 1, {[6] } musi mieć separator folderów w stylu * Nix ( / ). Na przykład, folder o nazwie {[11] } musi być przekazany jako path1/path2/subproject. Ponadto nie używaj komendy mv, lecz move.

    Ostatnia uwaga: unikalną i dużą różnicą od odpowiedzi podstawowej jest druga linia skryptu "git filter-branch..."

  2. Utwórz nowy repo

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Połącz nowe repo z Github lub wherever

    git remote add origin <[email protected]:my-user/new-repo.git>
    git push origin -u master
    
  4. Czyszczenie, W razie potrzeby

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

    Uwaga : pozostawia to wszystkie historyczne odniesienia w repozytorium.Zobacz dodatek w oryginalnej odpowiedzi, jeśli rzeczywiście obawiasz się popełnienia hasła lub musisz zmniejszyć rozmiar pliku folderu .git.

 13
Author: Anthony O.,
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:26:37

Oryginalne pytanie chce, aby xyz/ABC/(*files) stał się ABC/ABC / (*files). Po zaimplementowaniu zaakceptowanej odpowiedzi do własnego kodu zauważyłem, że faktycznie zmienia on XYZ/ABC/(*files) na ABC/(*files). Strona podręcznika filter-branch mówi nawet:

Wynik będzie zawierał ten katalog (i tylko ten) jako główny projekt ."

Innymi słowy, Promuje folder najwyższego poziomu " up " o jeden poziom. To ważne rozróżnienie, bo np. w moim historia nazwałem folder najwyższego poziomu. Poprzez promowanie folderów "w górę" o jeden poziom, git traci ciągłość w commicie, w którym dokonałem zmiany nazwy.

Straciłem contiuity po filter-branch

Moja odpowiedź na to pytanie to zrobić 2 kopie repozytorium i ręcznie usunąć folder(y), które chcesz zachować w każdym. Strona man wspiera mnie tym:

[...] unikaj używania [tej komendy], jeśli pojedynczy commit wystarczy, aby rozwiązać twój problem

 11
Author: MM.,
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
2012-04-17 05:12:06

Aby dodać do odpowiedź Paula , odkryłem, że aby ostatecznie odzyskać przestrzeń, muszę wcisnąć głowę do czystego repozytorium, a to zmniejsza rozmiar .katalog git/objects/pack.

Tzn.

$ mkdir ...ABC.git
$ cd ...ABC.git
$ git init --bare

Po śliwce gc również zrób:

$ git push ...ABC.git HEAD

Wtedy możesz zrobić

$ git clone ...ABC.git

I wielkość ABC/.git jest zredukowany

Git gc) nie są potrzebne przy czyszczeniu repozytorium, np.:
$ git clone --no-hardlinks /XYZ /ABC
$ git filter-branch --subdirectory-filter ABC HEAD
$ git reset --hard
$ git push ...ABC.git HEAD
 7
Author: Case Larsen,
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:10:41

Właściwa droga teraz jest następująca:

git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub ma teraz nawet mały artykuł o takich przypadkach.

Ale pamiętaj, aby najpierw sklonować oryginalne repo do oddzielnego katalogu(ponieważ usunęłoby to wszystkie pliki i inne katalogi i prawdopodobnie będziesz musiał z nimi pracować).

Więc twój algorytm powinien być:

  1. Sklonuj zdalne repo do innego katalogu
  2. używając git filter-branch pozostawia tylko pliki pod jakimś podkatalogiem, wciśnij do new remote
  3. Utwórz commit, aby usunąć ten podkatalog z oryginalnego zdalnego repo
 5
Author: Olexandr Shapovalov,
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-11-12 13:22:04

Wydaje się, że większość(wszystkie?) odpowiedzi tutaj opierają się na jakiejś formie git filter-branch --subdirectory-filter i jej podobieństwie. Może to działać "najczęściej", jednak w niektórych przypadkach, na przykład w przypadku zmiany nazwy folderu, np.]}

 ABC/
    /move_this_dir # did some work here, then renamed it to

ABC/
    /move_this_dir_renamed

Jeśli wykonasz zwykły styl filtra Gita, aby wyodrębnić "move_me_renamed", stracisz historię zmian pliku, która miała miejsce Od początku, gdy był to move_this_dir (ref ).

Wydaje się więc, że jedynym sposobem, aby naprawdę zachować całą historię zmian (jeśli twój przypadek jest taki jak ten), jest, w istocie, skopiować repozytorium( utworzyć nowy repo, ustawić, że jest źródłem), następnie nuke Wszystko inne I zmienić nazwę podkatalogu do rodzica w następujący sposób:

  1. Klonuj projekt wielomodułowy lokalnie
  2. gałęzie-sprawdź co tam jest: git branch -a
  3. wykonaj zamówienie dla każdej gałęzi, która zostanie uwzględniona w podziale, aby uzyskać lokalną kopię na swojej stacji roboczej: git checkout --track origin/branchABC
  4. zrób kopię w nowym katalogu: cp -r oldmultimod simple
  5. idź do nowa kopia projektu: cd simple
  6. pozbądź się innych modułów, które nie są potrzebne w tym projekcie:
  7. git rm otherModule1 other2 other3
  8. teraz pozostaje tylko subdir modułu docelowego
  9. pozbądź się subdir modułu, aby główny moduł stał się nowym korzeniem projektu
  10. git mv moduleSubdir1/* .
  11. Usuń subdir relikwii: rmdir moduleSubdir1
  12. Sprawdź zmiany w dowolnym momencie: git status
  13. Utwórz nowy Git repo i skopiuj jego adres URL, aby skierować ten projekt do it:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. zweryfikuj to dobrze: git remote -v
  16. Przesuń zmiany do zdalnego repo: git push
  17. idź do zdalnego repo i sprawdź, czy wszystko tam jest
  18. powtórz dla każdej innej gałęzi: git checkout branch2

To wynika z dokumentu github "dzielenie podfolderu na nowe repozytorium" kroków 6-11, aby wypchnąć moduł do nowego repozytorium.

To nie pozwoli Ci zaoszczędzić miejsca w Twoim .folder git, ale zachowa on wszystkie Twoje Zmień historię tych plików nawet w trakcie zmiany nazw. A to może nie być tego warte, jeśli nie ma" dużo " utraconej historii itp. Ale przynajmniej masz gwarancję, że nie stracisz starszych commitów!

 5
Author: rogerdpack,
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-10-31 10:41:55

Miałem dokładnie taki problem, ale wszystkie standardowe rozwiązania bazujące na git filter-branch były bardzo wolne. Jeśli masz małe repozytorium, to może nie być to problem, to było dla mnie. Napisałem kolejny program filtrujący git oparty na libgit2, który w pierwszym kroku tworzy gałęzie dla każdego filtrowania repozytorium podstawowego, a następnie wypycha je do czyszczenia repozytoriów jako następny krok. W moim repozytorium (500MB 100000 commitów) standardowe metody Git filter-branch zajmowały kilka dni. Mój program zajmuje minut, aby zrobić to samo filtrowanie.

Ma bajeczną nazwę git_filter i mieszka tutaj:

Https://github.com/slobobaby/git_filter

Na GitHubie.

Mam nadzieję, że komuś się przyda.

 4
Author: slobobaby,
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-03-10 17:39:13

Jeśli to coś warte, oto jak używać Githuba na komputerze z systemem Windows. Załóżmy, że masz sklonowany repo w C:\dir1. Struktura katalogów wygląda następująco: C:\dir1\dir2\dir3. Katalog dir3 jest Tym, który chcę być nowym oddzielnym repo.

Github:

  1. Utwórz nowe repozytorium: MyTeam/mynewrepo

Bash Prompt:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
    Returned: Ref 'refs/heads/master' was rewritten (fyi: dir2/dir3 is case wrażliwa.)

  3. $ git remote add some_name [email protected]:MyTeam/mynewrepo.git
    git remote add origin etc. nie działał, wrócił "remote origin already exists"

  4. $ git push --progress some_name master

 4
Author: James Lawruk,
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-03-06 01:26:14

Jak wspomniałem powyżej , musiałem użyć odwrotnego rozwiązania (usunięcie wszystkich commitów nie dotykających mojego dir/subdir/targetdir), które wydawało się działać całkiem dobrze usuwając około 95% commitów (zgodnie z życzeniem). Pozostały jednak dwie małe kwestie.

Pierwszy, filter-branch zrobił świetną robotę usuwania commitów, które wprowadzają lub modyfikują kod, ale najwyraźniej merge commity znajdują się pod jego stacją w Gitiverse.

Jest to kwestia kosmetyczna, z którą prawdopodobnie mogę żyć (mówi...cofając się powoli z odwróconymi oczami) .

Po drugie nieliczne commity, które pozostały, są w zasadzie wszystkie zduplikowane! Wydaje mi się, że nabyłem drugą, zbędną oś czasu, która obejmuje całą historię projektu. Ciekawostką (co widać na poniższym zdjęciu) jest to, że moje trzy lokalne oddziały nie są na tej samej osi czasu (czyli, na pewno, dlaczego istnieje i nie jest tylko śmieci zbierane).

Jedyne, co mogę sobie wyobrazić, to to, że jednym z usuniętych commitów był, być może, pojedynczy commit scalający, który filter-branch faktycznie usunąłem , A To stworzyło równoległą linię czasową, ponieważ każda teraz niezergowana część przyjęła własną kopię commitów. (shrug gdzie jest moja TARDiS?) Jestem prawie pewien, że mogę to naprawić problem, choć naprawdę chciałbym zrozumieć, jak to się stało.

W przypadku szalonego mergefest-O-RAMA, prawdopodobnie zostawię go samego, ponieważ tak mocno zakorzenił się w mojej historii commitów-groźny dla mnie za każdym razem, gdy się zbliżam -, nie wydaje się, aby w rzeczywistości powodował problemy nie kosmetyczne i ponieważ jest całkiem ładny w Tower.app.

 3
Author: Jay Allen,
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:18:26

Użyj tego polecenia filter, aby usunąć podkatalog, zachowując swoje tagi i gałęzie:

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
 3
Author: cmcginty,
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-05-26 14:51:21

The Easier Way

  1. zainstaluj git splits. Stworzyłem go jako rozszerzenie git, oparte na rozwiązaniu jkeating.
  2. 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 XY1 XY2

  3. Utwó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

  4. / 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

  5. Sklonuj nowo utworzony zdalny repo do nowego lokalnego katalog
    #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

 3
Author: AndrewD,
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:18:26

Możesz potrzebować czegoś w rodzaju "git reflog expire -- expire=now --all" przed garbage collectingiem, aby wyczyścić pliki. git filter-branch usuwa tylko odniesienia w historii, ale nie usuwa wpisów reflog, które zawierają dane. Oczywiście najpierw przetestuj to.

Moje użycie dysku drastycznie spadło przy tym, chociaż moje początkowe warunki były nieco inne. Być może --subdirectory-filter neguje tę potrzebę, ale wątpię.

 2
Author: ,
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
2009-06-12 08:28:42

Sprawdź projekt git_split na https://github.com/vangorra/git_split

Zamień katalogi Gita w ich własne repozytoria w ich własnej lokalizacji. Bez podtekstów. Skrypt pobierze istniejący katalog w repozytorium git i zamieni go w niezależne repozytorium. Po drodze skopiuje całą historię zmian w podanym katalogu.

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to push to.
 2
Author: vangorra,
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
2016-01-06 02:42:05

Włóż to do gitconfig:

reduce-to-subfolder = !sh -c 'git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter cookbooks/unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --prune=now && git remote rm origin'
 1
Author: grosser,
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
2013-03-29 20:18:09

Jestem pewien, że subtree git jest w porządku i wspaniałe, ale moje podkatalogi kodu zarządzanego git, które chciałem przenieść, były w eclipse. Więc jeśli używasz egit, jest to boleśnie łatwe. Weź projekt, który chcesz przenieść i zespół - > odłącz go, a następnie zespół- > udostępnij go w nowej lokalizacji. Domyślnie będzie próbować użyć starej lokalizacji repo, ale możesz odznaczyć zaznaczenie use-existing i wybrać nowe miejsce, aby je przenieść. Chwała egitowi.

 1
Author: stu,
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
2016-02-10 16:57:12

Polecam GitHub ' s guide do podziału podfolderów na nowe repozytorium. Kroki są podobne do Paul ' s answer , ale okazało się, że ich instrukcje są łatwiejsze do zrozumienia.

Zmodyfikowałem instrukcje tak, że dotyczą lokalnego repozytorium, a nie hostowanego na Githubie.


Podział podfolderu na nowe repozytorium

  1. Otwórz Git Bash.

  2. Zmień prąd working directory to the location where you want to create your new repozytorium.

  3. Sklonuj repozytorium zawierające podfolder.

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
  1. Zmień bieżący katalog roboczy na sklonowane repozytorium.

cd REPOSITORY-NAME
  1. aby odfiltrować podfolder z pozostałych plików w repozytorium, Uruchom git filter-branch, dostarczając te informacje:
    • FOLDER-NAME: folder w Twoim projekcie z którego chcesz utworzyć osobne repozytorium.
      • Wskazówka: użytkownicy systemu Windows powinni używać / do rozdzielania folderów.
    • BRANCH-NAME: domyślna gałąź dla bieżącego projektu, na przykład master lub gh-pages.

git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME  BRANCH-NAME 
# Filter the specified branch in your directory and remove empty commits
Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89)
Ref 'refs/heads/BRANCH-NAME' was rewritten
 1
Author: Steven Vascellaro,
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-08-31 14:02:49