Domanda

Ho un Idiota repository che contiene una serie di sottodirectory.Ora ho scoperto che una delle sottodirectory non è correlata all'altra e dovrebbe essere scollegata in un repository separato.

Come posso farlo mantenendo la cronologia dei file all'interno della sottodirectory?

Immagino che potrei creare un clone e rimuovere le parti indesiderate di ciascun clone, ma suppongo che questo mi darebbe l'albero completo quando controllo una revisione precedente, ecc.Questo potrebbe essere accettabile, ma preferirei poter fingere che i due repository non abbiano una cronologia condivisa.

Giusto per essere più chiaro, ho la seguente struttura:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

Ma preferirei invece questo:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/
È stato utile?

Soluzione

Aggiorna : questo processo è così comune, che la squadra git ha reso molto più semplice con un nuovo strumento, git subtree. Vedi qui: Staccare (spostare) sottodirectory in separata repository Git


Si desidera clonare il vostro repository e quindi utilizzare git filter-branch per marcare tutto, ma la sottodirectory che si desidera nel vostro nuovo repo di essere garbage collection.

  1. Per clonare il vostro repository locale:

    git clone /XYZ /ABC
    

    (Nota:. Il repository sarà clonato usando hard-link, ma che non è un problema dal momento che i file collegati non saranno modificati in se stessi - verranno creati nuovi)

  2. Ora, cerchiamo di preservare i rami interessanti che vogliamo riscrivere così, e quindi rimuovere l'origine per evitare di spingere lì e fare in modo che i vecchi si impegna a non farà riferimento per l'origine:

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

    o per tutte le filiali remote:

    cd /ABC
    for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
    git remote rm origin
    
  3. Ora si potrebbe desiderare di rimuovere anche i tag che non hanno alcuna relazione con il sottoprogetto; si può anche fare che più tardi, ma potrebbe essere necessario potare nuovamente la repo. Non l'ho fatto così e ottenuto un WARNING: Ref 'refs/tags/v0.1' is unchanged per tutti i tag (in quanto erano tutti estranei a sottoprogetto); Inoltre, dopo la rimozione di tali tag più spazio sarà recuperato. A quanto pare git tag -l | xargs git tag -d dovrebbe essere in grado di riscrivere altri tag, ma non ho potuto verificare questo. Se si desidera rimuovere tutti i tag, utilizzare --tag-name-filter cat --prune-empty.

  4. Quindi utilizzare il filtro-ramo e azzerato per escludere gli altri file, in modo che possano essere potati. Diamo anche aggiungere -- --all per rimuovere commit vuoti e di riscrivere i tag (si noti che questo avrà per mettere a nudo la loro firma):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    

    o, in alternativa, di riscrivere solo ramo HEAD e ignorare tag e altri rami:

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
    
  5. Quindi eliminare i reflogs di backup in modo dallo spazio può essere veramente recuperato (anche se ora l'operazione è distruttiva)

    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
    

    e ora si dispone di un repository git locale del sotto-directory ABC con tutta la sua storia preservata.

Nota: Per la maggior parte degli utilizzi, all dovrebbe effettivamente avere il parametro aggiunto <=>. Sì questo è davvero - - spazio - - <=>. Questo deve essere gli ultimi parametri per il comando. Come ha scoperto Matli, questo mantiene i rami e tag di progetto inclusi nella nuova pronti contro termine.

Modifica:. Vari suggerimenti da commenti qui sotto sono stati incorporati per assicurarsi che, per esempio, che il repository è in realtà si sono ristretti (che non era sempre il caso prima)

Altri suggerimenti

Il modo facile™

Si scopre che questa è una pratica così comune e utile che i signori di git l'hanno resa davvero semplice, ma devi avere una versione più recente di git (>= 1.7.11 maggio 2012).Vedi il appendice per sapere come installare l'ultimo git.Inoltre, c'è un esempio del mondo reale nel Procedura dettagliata sotto.

  1. Preparare il vecchio repository

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

    Nota: <name-of-folder> NON deve contenere caratteri iniziali o finali.Ad esempio, la cartella denominata subproject DEVE essere passato come subproject, NON ./subproject/

    Nota per gli utenti Windows: quando la profondità della cartella è > 1, <name-of-folder> deve avere un separatore di cartella in stile *nix (/).Ad esempio, la cartella denominata path1\path2\subproject DEVE essere passato come path1/path2/subproject

  2. Crea il nuovo repository

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Collega il nuovo repository a Github o ovunque

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. Ripulire, se desiderato

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

    Nota:Questo lascia tutti i riferimenti storici nel repository.Vedi il Appendice di seguito se sei effettivamente preoccupato di aver inserito una password o hai bisogno di ridurre le dimensioni del file .git cartella.

...

Procedura dettagliata

Queste sono le stessi passaggi di cui sopra, ma seguendo i miei passaggi esatti per il mio repository invece di utilizzare <meta-named-things>.

Ecco un progetto che ho per implementare i moduli del browser JavaScript nel nodo:

tree ~/Code/node-browser-compat

node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator

Voglio dividere una singola cartella, btoa, in un repository git separato

pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd

Ora ho una nuova filiale, btoa-only, che ha solo impegni per btoa e voglio creare un nuovo repository.

mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only

Successivamente creo un nuovo repository su Github o bitbucket o qualsiasi altra cosa e aggiungo che è il file origin (a proposito, "origin" è solo una convenzione, non parte del comando: potresti chiamarlo "server remoto" o come preferisci)

git remote add origin git@github.com:node-browser-compat/btoa.git
git push origin -u master

Giorno felice!

Nota: Se hai creato un repository con a README.md, .gitignore E LICENSE, dovrai prima tirare:

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

Infine, vorrò rimuovere la cartella dal repository più grande

git rm -rf btoa

...

Appendice

L'ultimo Git su OS X

Per ottenere l'ultima versione di git:

brew install git

Per ottenere brew per OS X:

http://brew.sh

L'ultimo git su Ubuntu

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

Se non funziona (hai una versione molto vecchia di Ubuntu), prova

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

Se ancora non funziona, prova

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

Grazie a rui.araujo dai commenti.

cancellando la cronologia

Per impostazione predefinita, la rimozione di file da git non li rimuove effettivamente da git, ma conferma semplicemente che non sono più presenti.Se vuoi rimuovere effettivamente i riferimenti storici (ad es.hai una password impegnata), devi fare questo:

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

Successivamente puoi verificare che il tuo file o cartella non venga più visualizzato nella cronologia git

git log -- <name-of-folder> # should show nothing

Tuttavia, tu non è possibile "spingere" le eliminazioni su github e simili.Se provi, riceverai un errore e dovrai farlo git pull prima che tu possa git push - e poi torni ad avere tutto nella tua storia.

Quindi, se desideri eliminare la cronologia dall'"origine", ovvero eliminarla da github, bitbucket, ecc., dovrai eliminare il repository e reinserire una copia eliminata del repository.Ma aspetta - C'è più!- Se sei veramente preoccupato di sbarazzarti di una password o qualcosa del genere dovrai sfoltire il backup (vedi sotto).

fabbricazione .git più piccola

Il suddetto comando di eliminazione della cronologia lascia ancora un mucchio di file di backup, perché git è fin troppo gentile nell'aiutarti a non rovinare il tuo repository per sbaglio.Alla fine cancellerà i file orfani nel corso dei giorni e dei mesi, ma li lascerà lì per un po' nel caso in cui ti rendi conto di aver cancellato accidentalmente qualcosa che non volevi.

Quindi, se lo vuoi davvero svuota il cestino A ridurre la dimensione del clone di un repository devi immediatamente fare tutte queste cose davvero strane:

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

Detto questo, ti consiglio di non eseguire questi passaggi a meno che tu non sappia che è necessario, nel caso in cui tu abbia eliminato la sottodirectory sbagliata, sai?I file di backup non dovrebbero essere clonati quando esegui il push del repository, saranno semplicemente nella tua copia locale.

Credito

di Paul risposta crea un nuovo repository contenente / ABC, ma non rimuove / ABC dal di dentro / XYZ. Il seguente comando rimuove / ABC dal di dentro / XYZ:

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

Naturalmente, testare in un 'clone --no-hardlinks' repository prima, e seguire con il reset, GC e comandi prugna elenca Paul.

ho scoperto che, al fine di eliminare correttamente la vecchia storia del nuovo repository, si deve fare un po 'di lavoro dopo la filter-branch passo.

  1. Fare il clone e il filtro:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. Rimuovi ogni riferimento alla storia antica. “Origine” è stato tenere traccia del proprio clone, e “originale” è dove filtro-ramo salva la roba vecchia:

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. Anche ora, la vostra storia potrebbe essere bloccato in un packfile che fsck non toccherà. Strapparlo a brandelli, la creazione di una nuova packfile ed eliminando gli oggetti non utilizzati:

    git repack -ad
    

una spiegazione di questo nel href="http://git-scm.com/docs/git-filter-branch#_checklist_for_shrinking_a_repository" per filtro-ramo .

Modifica: script Bash aggiunto

.

Le risposte qui riportati hanno lavorato solo in parte per me; Un sacco di file di grandi dimensioni sono rimaste nella cache. Che fine ha funzionato (dopo ore in #git su 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

Con le soluzioni precedenti, la dimensione del repository era di circa 100 MB. Questo ha portato verso il basso a 1,7 MB. Forse aiuta qualcuno:)


Il seguente script bash automatizza il compito:

!/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

Questa non è più così complessa si può semplicemente utilizzare il filtro-ramo git comando su un clone di voi repo di abbattere le sottodirectory che non si desidera e poi spingere al nuovo telecomando.

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .

Aggiorna : il modulo git-sotto-albero era così utile che il team git tirato in anima e ne ha fatto git subtree. Vedi qui: Staccare (spostare) sottodirectory in separata repository Git

git-sotto-albero può essere utile per questo

http://github.com/apenwarr/git -subtree / blob / master / git-subtree.txt (deprecato)

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

Ecco una piccola modifica a CoolAJ86'S La risposta "The Easy Way™". per dividersi più sottocartelle (diciamo sub1E sub2) in un nuovo repository git.

The Easy Way™ (più sottocartelle)

  1. Preparare il vecchio repository

    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
    

    Nota: <name-of-folder> NON deve contenere caratteri iniziali o finali.Ad esempio, la cartella denominata subproject DEVE essere passato come subproject, NON ./subproject/

    Nota per gli utenti Windows: quando la profondità della cartella è > 1, <name-of-folder> deve avere un separatore di cartella in stile *nix (/).Ad esempio, la cartella denominata path1\path2\subproject DEVE essere passato come path1/path2/subproject.Inoltre non utilizzare mvcomando ma move.

    Nota finale: l'unica e grande differenza con la risposta base è la seconda riga dello script "git filter-branch..."

  2. Crea il nuovo repository

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Collega il nuovo repository a Github o ovunque

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. Ripulire, se desiderato

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

    Nota:Questo lascia tutti i riferimenti storici nel repository.Vedi il Appendice nella risposta originale se sei effettivamente preoccupato di aver inserito una password o hai bisogno di ridurre la dimensione del file .git cartella.

La domanda iniziale vuole XYZ / ABC / (* file) per diventare ABC / ABC / (file *). Dopo aver implementato la risposta accettata per il mio codice, ho notato che in realtà cambia (file *) XYZ / ABC / in (file *) ABC /. La pagina man di filtro-ramo, dice ancora,

  

Il risultato conterrà quella directory (e solo quella) come radice del progetto ".

In altre parole, essa promuove la cartella di primo livello "alto" di un livello. Questa è una distinzione importante perché, ad esempio, nella mia storia avevo rinominato una cartella di livello superiore. Promuovendo le cartelle "up" di un livello, git perde la continuità al commit dove ho fatto la ridenominazione.

Ho perso contiuity dopo filtro-ramo

La mia risposta alla domanda è quindi di fare 2 copie del repository e eliminare manualmente la cartella (s) che si desidera conservare in ciascuno. La pagina di uomo mi esegue il backup con questo:

  

[...] evitare l'uso di [questo comando] se un semplice singolo impegnarsi sarebbe sufficiente a risolvere il problema

Per aggiungere a di Paul risposta , ho scoperto che per recuperare in ultima analisi, lo spazio, devo spingere la testa di un repository pulito e che trim verso il basso la dimensione della directory .git / oggetti / pack.

cioè.

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

Dopo la prugna gc, anche fare:

$ git push ...ABC.git HEAD

Poi si può fare

$ git clone ...ABC.git

e la dimensione della ABC / .git si riduce

In realtà, alcuni dei passi in termini di tempo (per esempio git gc) non sono necessari con la spinta per pulire repository, cioè:.

$ git clone --no-hardlinks /XYZ /ABC
$ git filter-branch --subdirectory-filter ABC HEAD
$ git reset --hard
$ git push ...ABC.git HEAD

Modo corretto ora è la seguente:

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

GitHub ora nemmeno piccolo articolo su tali casi.

Ma essere sicuri di clonare il vostro repo originale alla directory separata prima (come sarebbe eliminare tutti i file e le altre directory e si probabile necessità di lavorare con loro).

Quindi, l'algoritmo dovrebbe essere:

  1. clonare il repository remoto a un altro directory
  2. utilizzando git filter-branch lasciato solo i file sotto qualche sottodirectory, spingere al nuovo telecomando
  3. Crea impegnarsi per rimuovere questa sottodirectory dal repo telecomando originale

Sembra che la maggior parte (tutte?) Le risposte qui si basano su una qualche forma di git filter-branch --subdirectory-filter e suoi simili. Questo può funzionare "il più delle volte" Tuttavia, per alcuni casi, ad esempio il caso di quando è stata rinominata la cartella, es:

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

ABC/
    /move_this_dir_renamed

Se fate un normale stile di filtro git per estrarre "move_me_renamed" si perde la storia di modifica del file che si è verificato da quando era inizialmente move_this_dir ( ref ).

Risulta quindi che l'unico modo per mantenere davvero tutti cronologia delle modifiche (se il vostro è un caso come questo), è, in sostanza, per copiare il repository (creare un nuovo pronti contro termine, set che essere l'origine), poi bombardare tutto il resto e rinominare la sottodirectory al genitore in questo modo:

  1. Clonare il progetto multi-modulo localmente
  2. Settori - controllare quello che c'è: git branch -a
  3. Fare un checkout per ogni ramo da inserire nella divisione per ottenere una copia locale sulla workstation: git checkout --track origin/branchABC
  4. Fare una copia in una nuova directory: cp -r oldmultimod simple
  5. Entrate nella nuova copia del progetto: cd simple
  6. Sbarazzarsi degli altri moduli che non sono necessari in questo progetto:
  7. git rm otherModule1 other2 other3
  8. Ora solo la sottodirectory del modulo di destinazione rimane
  9. Liberati del subdir modulo in modo che la radice del modulo diventa la nuova radice del progetto
  10. git mv moduleSubdir1/* .
  11. Eliminare la sottodirectory reliquia: rmdir moduleSubdir1
  12. Verifica modifiche in qualsiasi punto: git status
  13. Creare il nuovo repository git e copiare l'URL per puntare questo progetto in esso:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. Verificare questo è buono: git remote -v
  16. Spingere i cambiamenti fino al repo remoto: git push
  17. Vai repo remoto e controllare è tutto lì
  18. Ripeti per qualsiasi altro ramo necessaria: git checkout branch2

il doc github " la suddivisione di una sottocartella fuori in un nuovo repository " i passaggi 6-11 per spingere il modulo a un nuovo pronti contro termine.

Questo non vi farà risparmiare spazio nella tua cartella .git, ma conserverà tutta la tua cronologia delle modifiche per i file anche attraverso rinomina. E questo non può essere vale la pena, se non v'è "un sacco" di storia perduta, ecc, ma almeno si sono garantiti di non perdere più vecchio commette!

Ho avuto esattamente questo problema, ma tutte le soluzioni standard basate su git filter-branch erano estremamente lento. Se si dispone di un piccolo repository allora questo non può essere un problema, è stato per me. Ho scritto un altro programma di filtraggio git sulla base di libgit2 che come primo passo crea rami per ogni filtraggio del repository primario e poi spinge questi a pulire repository come il passo successivo. Sul mio repository (500MB 100000 commit) i metodi di filtro git-ramo standard, hanno preso giorni. Il mio programma prende minuti per fare lo stesso filtraggio.

E 'il nome favolosa git_filter e vive qui:

https://github.com/slobobaby/git_filter

su GitHub.

Spero che sia utile a qualcuno.

Per quello che vale, ecco come utilizzare GitHub su una macchina Windows. Diciamo che si dispone di un pronti contro termine clonato in residente in C:\dir1. La struttura di directory simile a questo: C:\dir1\dir2\dir3. L'dir3 directory è quello che voglio essere un nuovo repo separata.

Github:

  1. Crea un nuovo repository: MyTeam/mynewrepo

Bash Prompt:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
    Restituito: Ref 'refs/heads/master' was rewritten (FYI:. Dir2 / dir3 maiuscole e minuscole)

  3. $ git remote add some_name git@github.com:MyTeam/mynewrepo.git
    git remote add origin etc. non ha funzionato, è tornato "remote origin already exists"

  4. $ git push --progress some_name master

, ho dovuto usare il contrario soluzione (l'eliminazione di tutti non impegna toccare il mio dir/subdir/targetdir) che sembrava funzionare abbastanza bene rimuovere circa il 95% dei commit (se lo desideri). Ci sono, tuttavia, due piccole questioni in sospeso.

prima , filter-branch ha fatto un lavoro bang di rimuovere commit che introducono o modificano il codice, ma a quanto pare, Unisci commit sono sotto la sua stazione nel Gitiverse.

Questo è un problema cosmetico che probabilmente posso vivere con (che dice ... indietreggiare lentamente con gli occhi bassi) .

secondo le poche commit che rimangono sono praticamente tutti duplicato! Mi sembra di aver acquisito una seconda linea temporale, ridondante che attraversa quasi tutta la storia del progetto. La cosa interessante (che si può vedere dalla foto qui sotto), è che i miei tre sezioni locali non sono tutti sulla stessa timeline (che è, certamente perché esiste e non è solo garbage collection).

L'unica cosa che posso immaginare è che uno dei commit cancellati è stata, forse, l'unico merge commit che <=> in realtà ha eliminare , e che ha creato la linea temporale parallela come ogni ora-unmerged Strand ha preso la propria copia dei commit. ( spallucce Dove è la mia TARDIS?) Sono abbastanza sicuro di poter risolvere questo problema, anche se mi piacerebbe davvero Amore per capire come sia successo.

Nel caso del folle mergefest-O-RAMA, io probabilmente partirò che uno solo dal momento che è così saldamente radicata nel mio commettere storia minaccioso verso di me ogni volta che vengo vicino-, esso non sembra essere in realtà causare alcun problema non cosmetici e perché è piuttosto bella in Tower.app.

Utilizzare questo comando filtro per rimuovere una sottodirectory, preservando i tag e rami:

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all

Il modo più Facile

  1. git splits . L'ho creato come estensione di git, sulla base di una soluzione di jkeating .
  2. Split le directory in una filiale locale #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. Crea un repo vuota da qualche parte. Si suppone che abbiamo creato un repository vuoto chiamato xyz su GitHub che ha percorso: git@github.com:simpliwp/xyz.git

  4. Push-to il nuovo pronti contro termine. #add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz git@github.com:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master

  5. Clonare il repo remoto appena creata in una nuova directory locale
    #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 git@github.com:simpliwp/xyz.git

guida di GitHub alla scissione sottocartelle in un nuovo repository . La procedura è simile a di Paul risposta , ma ho trovato le loro istruzioni più facili da capire.

Ho modificato le istruzioni in modo che si applicano per un repository locale, piuttosto che uno ospitato su GitHub.


  

Divisione di una sottocartella fuori in un nuovo repository

     
      
  1. Apri Git Bash.

  2.   
  3. Cambiare la directory di lavoro corrente nella posizione in cui si desidera creare il nuovo repository.

  4.   
  5. clonare il repository che contiene la sottocartella.

  6.   
     

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
     
      
  1. Cambiare la directory di lavoro corrente alla repository clonato.
  2.   
     

cd REPOSITORY-NAME
     
      
  1. Per filtrare la sottocartella dal resto dei file nel repository, eseguire git filter-branch, fornendo le seguenti informazioni:      
        
    • FOLDER-NAME: la cartella all'interno del vostro progetto che si desideri creare un repository separato dalla.      
          
      • . Suggerimento: gli utenti Windows devono utilizzare / per delimitare le cartelle
      •   
    •   
    • BRANCH-NAME:. Il ramo di default per il progetto corrente, ad esempio, master o gh-pages
    •   
  2.   
     

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

Potrebbe essere necessario qualcosa come "git reflog scade --expire = ora --all" prima che la raccolta dei rifiuti per pulire in realtà i file fuori. git filter-branch rimuove solo i riferimenti nella storia, ma non rimuove le voci reflog che contengono i dati. Naturalmente, verificare questa prima.

Il mio utilizzo del disco è sceso drasticamente in questo modo, anche se le mie condizioni iniziali erano un po 'diversa. Forse --subdirectory-filtro nega questa necessità, ma ne dubito.

Scopri progetto git_split a https://github.com/vangorra/git_split

directory Accendere git nei loro molto proprio repository nella propria posizione. No sottostruttura divertente business. Questo script avrà una directory esistente nel proprio repository git e trasformare questa directory in un repository indipendente dalla propria. Lungo la strada, si copierà su tutta la cronologia delle modifiche per la directory che hai fornito.

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

Mettere questo nella vostra 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'

Sono sicuro che git sottostruttura è tutto bene e meraviglioso, ma le mie sottodirectory di git codice gestito che volevo andare era tutto in Eclipse. Quindi, se si sta utilizzando egit, è dolorosamente semplice. Prendere il progetto che si desidera spostare e SQUADRA-> Disconnetti, quindi SQUADRA-> condividerlo nella nuova posizione. Questo verrà impostato a cercare di utilizzare il vecchio percorso dei pronti contro termine, ma è possibile deselezionare la selezione utilizzo esistente e scegliere il nuovo posto per spostarlo. Tutti grandine egit.

ho trovato la soluzione in avanti abbastanza dritto, L'idea è quella di copiare repository e poi basta rimuovere parti non necessarie. Ecco come funziona:

1) Clonare un repository vuoi dividere

git clone git@git.thehost.io:testrepo/test.git

2) Sposta nella cartella git

cd test/

2) Rimuovere le cartelle inutili e commetterlo

rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'

3) Rimuovere inutili cartella (s) cronologia dei moduli con BFG

cd ..
java -jar bfg.jar --delete-folders "{ABC}" test
cd test/
git reflog expire --expire=now --all && git gc --prune=now --aggressive
  

per le cartelle si moltiplicano è possibile utilizzare una virgola

java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git

4) Verificare che la storia non contiene i file / cartelle appena cancellato

git log --diff-filter=D --summary | grep delete

5) Ora avete repository pulita senza ABC, quindi basta spingerla nella nuova origine

remote add origin git@github.com:username/new_repo
git push -u origin master

Questo è tutto. È possibile ripetere la procedura per ottenere un altro repository,

è sufficiente rimuovere XY1, XY2 e rinominare XYZ -> ABC il punto 3

Si può facilmente provare il https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/

Questo ha funzionato per me. I problemi che ho dovuto affrontare nei passaggi di cui sopra sono

  1. In questo comando git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME Il BRANCH-NAME è Master

  2. Se l'ultimo passaggio non riesce quando impegnandosi a causa di problema di protezione follow - https://docs.gitlab.com/ee/user/project/protected_branches.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top