Il consiglio che ti è stato dato è imperfetto. L'impostazione incondizionata di GIT_AUTHOR_DATE in --env-filter
riscriverebbe la data di ogni commit. Inoltre, sarebbe insolito usare git commit all'interno --index-filter
.
Qui hai a che fare con più problemi indipendenti.
Specificare date diverse da "adesso"
Ogni commit ha due date: la data dell'autore e la data del committer. È possibile sovrascrivere ciascuno fornendo valori tramite le variabili di ambiente GIT_AUTHOR_DATE e GIT_COMMITTER_DATE per qualsiasi comando che scrive un nuovo commit. Vedi "Formati di data" in git-commit (1) o sotto:
Git internal format = <unix timestamp> <time zone offset>, e.g. 1112926393 +0200
RFC 2822 = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601 = e.g. 2005-04-07T22:13:13
L'unico comando che scrive un nuovo commit durante l'uso normale è git commit . Ha anche --date
un'opzione che ti consente di specificare direttamente la data dell'autore. L'utilizzo previsto include git filter-branch --env-filter
anche l'utilizzo delle variabili di ambiente sopra menzionate (fanno parte del "env" dopo il quale l'opzione è denominata; vedere "Opzioni" in git-filter-branch (1) e il comando "idraulico" sottostante git-commit -tree (1) .
Inserimento di un file in un singolo ref Storia
Se il tuo repository è molto semplice (cioè hai un solo ramo, nessun tag), allora puoi probabilmente usare git rebase per fare il lavoro.
Nei seguenti comandi, utilizzare il nome dell'oggetto (hash SHA-1) del commit anziché "A". Non dimenticare di usare uno dei metodi di "sostituzione data" quando esegui git commit .
---A---B---C---o---o---o master
git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit
---A---N (was ",new-commit", but we delete the tag)
\
B'---C'---o---o---o master
Se si desidera aggiornare A per includere il nuovo file (anziché creare un nuovo commit nel punto in cui è stato aggiunto), utilizzare git commit --amend
invece di git commit
. Il risultato sarebbe simile al seguente:
---A'---B'---C'---o---o---o master
Quanto sopra funziona finché puoi nominare il commit che dovrebbe essere il genitore del tuo nuovo commit. Se vuoi davvero che il tuo nuovo file venga aggiunto tramite un nuovo commit root (senza genitori), allora hai bisogno di qualcosa di leggermente diverso:
B---C---o---o---o master
git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root
N (was new-root, but we deleted it)
\
B'---C'---o---o---o master
git checkout --orphan
è relativamente nuovo (Git 1.7.2), ma ci sono altri modi per fare la stessa cosa che funzionano con le versioni precedenti di Git.
Inserimento di un file in un Multi- ref Storia
Se il tuo repository è più complesso (cioè ha più di un ref (rami, tag, ecc.)), Probabilmente dovrai usare git filter-branch . Prima di utilizzare git filter-branch , è necessario creare una copia di backup dell'intero repository. È sufficiente un semplice archivio tar dell'intero albero di lavoro (inclusa la directory .git). git filter-branch crea riferimenti di backup, ma spesso è più facile recuperare da un filtro non proprio corretto semplicemente cancellando la .git
directory e ripristinandola dal backup.
Nota: gli esempi seguenti utilizzano il comando di livello inferiore git update-index --add
anziché git add
. Potresti usare git add , ma prima devi copiare il file da una posizione esterna nel percorso previsto ( --index-filter
esegue il suo comando in un GIT_WORK_TREE temporaneo che è vuoto).
Se vuoi che il tuo nuovo file venga aggiunto a ogni commit esistente, puoi farlo:
new_file=$(git hash-object -w path/to/file)
git filter-branch \
--index-filter \
'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
--tag-name-filter cat \
-- --all
git reset --hard
Non vedo davvero alcun motivo per cambiare le date degli commit esistenti --env-filter 'GIT_AUTHOR_DATE=…'
. Se lo avessi usato, lo avresti reso condizionale in modo da riscrivere la data per ogni commit.
Se vuoi che il tuo nuovo file appaia solo nei commit dopo alcuni commit esistenti ("A"), puoi farlo:
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
Se si desidera aggiungere il file tramite un nuovo commit da inserire nel mezzo della cronologia, sarà necessario generare il nuovo commit prima di utilizzare git filter-branch e aggiungere --parent-filter
a git filter-branch :
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -
git filter-branch \
--parent-filter "sed -e s/$before_commit/$new_commit/g" \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
Puoi anche organizzare che il file venga aggiunto per la prima volta in un nuovo commit di root: crea il tuo nuovo commit di root tramite il metodo "orfano" dalla sezione git rebase (acquisiscilo in new_commit
), usa l'incondizionato --index-filter
e --parent-filter
simili "sed -e \"s/^$/-p $new_commit/\""
.