Domanda

Questa domanda si basa su Stacca sottodirectory in separata Git repository

Invece di staccare una singola sottodirectory, voglio staccare un paio. Ad esempio, il mio attuale aspetto degli alberi di directory come questo:

/apps
  /AAA
  /BBB
  /CCC
/libs
  /XXX
  /YYY
  /ZZZ

E vorrei questo, invece:

/apps
  /AAA
/libs
  /XXX

L'argomento --subdirectory-filter a git filter-branch non funzionerà perché si libera di tutto, tranne che per la directory data la prima volta che viene eseguito. Ho pensato che utilizzando l'argomento --index-filter per tutti i file indesiderati avrebbe funzionato (anche se noiosi), ma se provo correre più di una volta, ottengo il seguente messaggio:

Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f

Tutte le idee? TIA

È stato utile?

Soluzione 4

Rispondendo alla mia domanda proprio qui ... dopo un sacco di tentativi ed errori.

Sono riuscito a fare questo utilizzando una combinazione di git subtree e git-stitch-repo . Queste istruzioni sono basate su:

In primo luogo, ho tirato fuori le directory ho voluto mantenere nel proprio repository separati:

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

Ho poi creato un nuovo repository vuota, ed importato / cucito gli ultimi due in esso:

cd ..
mkdir newRepo
cd newRepo
git init
git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import

Questo crea due rami, master-A e master-B, ciascuno con il contenuto di uno dei pronti contro termine cucite. Per combinare loro e ripulire:

git checkout master-A
git pull . master-B
git checkout master
git branch -d master-A 
git branch -d master-B

Ora io non sono del tutto sicuro di come / quando questo accade, ma dopo il primo checkout e la pull, il codice magicamente si fonde nel ramo principale (una visione chiara su quello che sta succedendo qui è apprezzato!)

Tutto sembra aver funzionato come previsto, tranne che se guardo attraverso la newRepo commettere storia, ci sono duplicati quando il changeset influenzato sia apps/AAA e libs/XXX. Se c'è un modo per rimuovere i duplicati, allora sarebbe perfetto.

Altri suggerimenti

Invece di avere a che fare con una subshell e utilizzando ext glob (come Kynan suggerito), provate questo approccio molto più semplice:

git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all

Come accennato da void.pointer nel suo / la sua commento , questo sarà rimuovere tutto tranne apps/AAA e libs/XXX dal repository corrente.

passaggi manuali con semplici comandi git

Il piano è quello di dividere singole directory nelle proprie pronti contro termine, poi unirle insieme. I seguenti passaggi manuali non hanno fatto impiegare script geek-to-use, ma facile da capire i comandi e potrebbe aiutare unione N in più sotto-cartelle in un altro unico repository.

Divide

Supponiamo che il pronti contro termine originale è: original_repo

1 - Spalato apps:

git clone original_repo apps-repo
cd apps-repo
git filter-branch --prune-empty --subdirectory-filter apps master

2 - libs Split

git clone original_repo libs-repo
cd libs-repo
git filter-branch --prune-empty --subdirectory-filter libs master

Continua se avete più di 2 cartelle. Ora avrete due nuovi e temporaneo repository git.

Conquer dalla fusione di applicazioni e librerie

3 - Preparare il nuovo pronti contro termine:

mkdir my-desired-repo
cd my-desired-repo
git init

E dovrai fare almeno un commit. Se le seguenti tre righe dovrebbe essere saltato, apparirà immediatamente sotto root del vostro repo tua prima 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"

Con il file temporaneo commesso, il comando merge nella sezione successiva si fermerà come previsto.

Prendendo dal feedback degli utenti, invece di aggiungere un file casuale come a_file_and_make_a_commit, è possibile scegliere di aggiungere un .gitignore o README.md ecc.

4 - apps Merge Repo prima:

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"

Ora si dovrebbe vedere applicazioni cartella all'interno del vostro nuovo repository. git log dovrebbe mostrare tutte storico rilevanti messaggi di commit.

Nota: come Chris ha notato sotto nei commenti, per la versione più recente (> = 2.9) di git, è necessario specificare --allow-unrelated-histories con git merge

5 - librerie Unisci Repo prossimo nello stesso modo:

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"

Continua se si dispone di più di 2 repos unire.

Riferimento: unire una sottodirectory di un altro repository con git

Perché si vuole eseguire filter-branch più di una volta? Si può fare tutto in un sol colpo, quindi nessun bisogno di forzarlo (notare che è necessario extglob abilitato nella shell per questo lavoro):

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all

Questo dovrebbe sbarazzarsi di tutti i cambiamenti nelle sottodirectory indesiderate e mantenere tutti i tuoi rami e commit (a meno che non riguardano solo i file nelle sottodirectory potati, in virtù della --prune-empty) - nessun problema con il duplicato commit etc

.

Dopo questa operazione le directory indesiderate saranno elencati come non tracciata dal git status.

Il $(ls ...) è necessaria S.T. la extglob viene valutata dalla shell al posto del filtro indice, che utilizza il sh incorporato eval (dove extglob non è disponibile). Vedere Come faccio ad attivare le opzioni di shell a git? per ulteriori dettagli su questo.

Ho writen un filtro git per risolvere proprio questo problema. Ha il nome del fantastico git_filter e si trova a github qui:

https://github.com/slobobaby/git_filter

Si basa sulla eccellente libgit2.

ho bisogno di dividere un grande repository con molti commit (~ 100000) e le soluzioni basate su git filter-branch sono voluti diversi giorni per l'esecuzione. git_filter vuole un minuto per fare la stessa cosa.

estensione git Usare 'divide' git

git splits è uno script bash che è un wrapper git branch-filter che ho creato come git estensione, basata su di jkeating soluzione .

E 'stato fatto proprio per questa situazione. Per il vostro errore, provare a utilizzare l'opzione git splits -f alla rimozione forza del backup. Perché git splits opera su un nuovo ramo, non riscrivere la vostra filiale corrente, in modo che il backup è estranea. Vedere il readme per maggiori dettagli e essere sicuri di usarlo su una copia / clone del pronti contro termine (solo nel caso!) .

  1. git splits .
  2. Spalato 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 apps/AAA libs/ZZZ

  3. Crea un qualche repo vuota. 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. Clone 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

Sì. Forza sovrascrivendo il backup utilizzando il flag -f sulle chiamate successive alla filter-branch per ignorare questo avvertimento. :) In caso contrario, penso che si ha la soluzione (che è, sradicare una directory indesiderato alla volta con filter-branch).

git clone git@example.com: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 git@example.com:newthing.git
git push --all

Elimina presente di backup sotto la directory .git nei rif / originale come il messaggio suggerisce. La directory è nascosta.

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