Les conseils que vous avez reçus sont viciés. La définition inconditionnelle de GIT_AUTHOR_DATE dans an --env-filter
réécrirait la date de chaque validation. De plus, il serait inhabituel d'utiliser git commit à l' intérieur --index-filter
.
Vous traitez ici de multiples problèmes indépendants.
Spécification de dates autres que «maintenant»
Chaque commit a deux dates: la date de l'auteur et la date du committer. Vous pouvez les remplacer en fournissant des valeurs via les variables d'environnement GIT_AUTHOR_DATE et GIT_COMMITTER_DATE pour toute commande qui écrit un nouveau commit. Voir «Formats de date» dans git-commit (1) ou ci-dessous:
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
La seule commande qui écrit un nouveau commit pendant une utilisation normale est git commit . Il dispose également d'une --date
option qui vous permet de spécifier directement la date de l'auteur. Votre utilisation prévue comprend git filter-branch --env-filter
également les variables d'environnement mentionnées ci-dessus (elles font partie de «env» après lequel l'option est nommée; voir «Options» dans git-filter-branch (1) et la commande sous-jacente «plumbing» git-commit -arbre (1) .
Insertion d'un fichier dans un historique de références unique
Si votre référentiel est très simple (c'est-à-dire que vous n'avez qu'une seule branche, pas de balises), vous pouvez probablement utiliser git rebase pour faire le travail.
Dans les commandes suivantes, utilisez le nom d'objet (hachage SHA-1) de la validation au lieu de «A». N'oubliez pas d'utiliser l'une des méthodes de «remplacement de date» lorsque vous exécutez 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
Si vous souhaitez mettre à jour A pour inclure le nouveau fichier (au lieu de créer un nouveau commit là où il a été ajouté), utilisez git commit --amend
plutôt à la place de git commit
. Le résultat ressemblerait à ceci:
---A'---B'---C'---o---o---o master
Ce qui précède fonctionne tant que vous pouvez nommer le commit qui devrait être le parent de votre nouveau commit. Si vous voulez réellement que votre nouveau fichier soit ajouté via un nouveau commit racine (pas de parents), alors vous avez besoin de quelque chose d'un peu différent:
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
est relativement nouveau (Git 1.7.2), mais il existe d' autres façons de faire la même chose qui fonctionnent sur les anciennes versions de Git.
Insertion d'un fichier dans un historique multi- références
Si votre référentiel est plus complexe (c'est-à-dire qu'il a plus d'une référence (branches, balises, etc.)), alors vous devrez probablement utiliser git filter-branch . Avant d'utiliser git filter-branch , vous devez faire une copie de sauvegarde de l'ensemble de votre référentiel. Une simple archive tar de l'ensemble de votre arborescence de travail (y compris le répertoire .git) est suffisante. git filter-branch crée des références de sauvegarde, mais il est souvent plus facile de récupérer à partir d'un filtrage pas tout à fait correct en supprimant simplement votre .git
répertoire et en le restaurant à partir de votre sauvegarde.
Remarque: Les exemples ci-dessous utilisent la commande de niveau inférieur git update-index --add
au lieu de git add
. Vous pouvez utiliser git add , mais vous devez d'abord copier le fichier d'un emplacement externe vers le chemin prévu ( --index-filter
exécute sa commande dans un GIT_WORK_TREE temporaire qui est vide).
Si vous souhaitez que votre nouveau fichier soit ajouté à chaque commit existant, vous pouvez le faire:
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
Je ne vois pas vraiment de raison de changer les dates des commits existants avec --env-filter 'GIT_AUTHOR_DATE=…'
. Si vous l'utilisiez, vous l'auriez rendu conditionnel pour qu'il réécrive la date de chaque commit.
Si vous souhaitez que votre nouveau fichier n'apparaisse que dans les validations après une validation existante («A»), vous pouvez le faire:
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
Si vous souhaitez que le fichier soit ajouté via un nouveau commit qui doit être inséré au milieu de votre historique, vous devrez générer le nouveau commit avant d'utiliser git filter-branch et l'ajouter --parent-filter
à 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
Vous pouvez également prendre des dispositions pour que le fichier soit d' abord ajouté dans un commit racine: créer votre nouvelle racine engagement via la méthode « orphelin » de la rebasage git section (capture en new_commit
), utiliser l'inconditionnel --index-filter
, et --parent-filter
comme "sed -e \"s/^$/-p $new_commit/\""
.