Ciò che si desidera fare coinvolgerà due fasi: aggiungere una nuova radice con un opportuno .gitignore
e scrub la cronologia per rimuovere i file che non avrebbero dovuto essere aggiunti. Il comando git filter-branch
può eseguire entrambe le operazioni.
Impostazione
Considera un rappresentante della tua cronologia.
$ git lola --name-status
* f1af2bf (HEAD, bar-feature) Add bar
| A .gitignore
| A bar.c
| D main.o
| D module.o
| * 71f711a (master) Add foo
|/
| A foo.c
| A foo.o
* 7f1a361 Commit 2
| A module.c
| A module.o
* eb21590 Commit 1
A main.c
A main.o
Per chiarezza, i file *.c
rappresentano file sorgente C e *.o
sono compilati file oggetti che dovrebbero essere stati ignorati.
Sul ramo della funzione barra, è stato aggiunto un file .gitignore
appropriato e file oggetto eliminati che non avrebbero dovuto essere tracciati, ma si desidera che tale criterio venga riflesso ovunque nell'importazione.
Nota che git lola
è un non-standard ma alias utile.
git config --global alias.lola \
'log --graph --decorate --pretty=oneline --abbrev-commit --all'
nuova radice Commit
creare la nuova radice commit come segue.
$ git checkout --orphan new-root
Switched to a new branch 'new-root'
La documentazione git checkout
nota una possibile stato imprevisto della nuova filiale orfano.
Se si vuole iniziare una storia disconnessa che registra una serie di percorsi che è totalmente diverso da quello di start_point, allora si dovrebbe cancellare l'indice e l'albero a lavorare subito dopo la creazione della filiale orfano eseguendo git rm -rf .
dal livello superiore dell'albero di lavoro.Successivamente sarete pronti per preparare i nuovi file, ripopolare l'albero di lavoro, copiandoli da altrove, l'estrazione di un archivio, ecc
Continuando il nostro esempio:
$ git rm -rf .
rm 'foo.c'
rm 'foo.o'
rm 'main.c'
rm 'main.o'
rm 'module.c'
rm 'module.o'
$ echo '*.o' >.gitignore
$ git add .gitignore
$ git commit -m 'Create .gitignore'
[new-root (root-commit) 00c7780] Create .gitignore
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
Ora la storia si presenta come
$ git lola
* 00c7780 (HEAD, new-root) Create .gitignore
* f1af2bf(bar-feature) Add bar
| * 71f711a (master) Add foo
|/
* 7f1a361 Commit 2
* eb21590 Commit 1
che è leggermente fuorviante perché rende nuovo look-root come esso è un discendente di bar-funzione, ma non ha davvero nessun genitore.
$ git rev-parse HEAD^
HEAD^
fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Prendere nota dello SHA per l'orfano perché sarà necessario in seguito. In questo esempio, è
$ git rev-parse HEAD
00c778087723ae890e803043493214fb09706ec7
riscrivere la storia
Vogliamo git filter-branch
per fare tre grandi cambiamenti.
- Giuntura nel nuovo commit radice.
- Elimina tutti i file temporanei.
- Utilizzare il
.gitignore
dalla nuova radice, a meno che non sia già esistente.
Nella riga di comando, che è incanted come
git filter-branch \
--parent-filter '
test $GIT_COMMIT = eb215900cd15ca2cf9ded74f1a0d9d25f65eb2bf && \
echo "-p 00c778087723ae890e803043493214fb09706ec7" \
|| cat' \
--index-filter '
git rm --cached --ignore-unmatch "*.o"; \
git ls-files --cached --error-unmatch .gitignore >/dev/null 2>&1 ||
git update-index --add --cacheinfo \
100644,$(git rev-parse new-root:.gitignore),.gitignore' \
--tag-name-filter cat \
-- --all
Spiegazione:
- I
--parent-filter
ganci opzione nel tuo nuova radice commettono.
eb215...
è lo SHA completo del vecchio commit radice, cf.git rev-parse eb215
- L'opzione
--index-filter
ha due parti:
- corso
git rm
come sopra eliminazioni nulla corrispondenza *.o
dall'intero albero perché il modello glob è citato ed interpretato da git piuttosto che il guscio.
- Verificare la presenza di uno
.gitignore
esistente con git ls-files
e, se non è presente, puntare a quello nella nuova radice.
- Se si dispone di tag, questi verranno mappati con l'operazione di identità,
cat
.
- Il solo
--
termina le opzioni e --all
è una scorciatoia per tutti gli arbitri.
L'output che si vede somiglierà
Rewrite eb215900cd15ca2cf9ded74f1a0d9d25f65eb2bf (1/5)rm 'main.o'
Rewrite 7f1a361ee918f7062f686e26b57788dd65bb5fe1 (2/5)rm 'main.o'
rm 'module.o'
Rewrite 71f711a15fa1fc60542cc71c9ff4c66b4303e603 (3/5)rm 'foo.o'
rm 'main.o'
rm 'module.o'
Rewrite f1af2bf89ed2236fdaf2a1a75a34c911efbd5982 (5/5)
Ref 'refs/heads/bar-feature' was rewritten
Ref 'refs/heads/master' was rewritten
WARNING: Ref 'refs/heads/new-root' is unchanged
gli originali sono ancora al sicuro. Il ramo principale ora vive sotto refs/original/refs/heads/master
, per esempio. Rivedi le modifiche nei tuoi rami appena riscritti.Quando si è pronti per eliminare il backup, eseguire
git update-ref -d refs/original/refs/heads/master
si poteva cucinare un comando a coprire tutte le arbitri di backup in un unico comando, ma vi consiglio di attento riesame per ciascuno di essi.
Conclusione
Infine, la nuova storia è
$ git lola --name-status
* ab8cb1c (bar-feature) Add bar
| M .gitignore
| A bar.c
| * 43e5658 (master) Add foo
|/
| A foo.c
* 6469dab Commit 2
| A module.c
* 47f9f73 Commit 1
| A main.c
* 00c7780 (HEAD, new-root) Create .gitignore
A .gitignore
Si osservi che tutti i file oggetto sono andati. La modifica a .gitignore
in bar-feature è perché ho usato contenuti diversi per assicurarmi che venissero conservati. Per completezza:
$ git diff new-root:.gitignore bar-feature:.gitignore
diff --git a/new-root:.gitignore b/bar-feature:.gitignore
index 5761abc..c395c62 100644
--- a/new-root:.gitignore
+++ b/bar-feature:.gitignore
@@ -1 +1,2 @@
*.o
+*.obj
L'arbitro nuova-root non è più utile, in modo da smaltire con
$ git checkout master
$ git branch -d new-root
Sei il mio eroe flippin! – Aren
@Aren Prego! Felice di aiutare. –