Porada, którą otrzymałeś, jest wadliwa. Bezwarunkowe ustawienie GIT_AUTHOR_DATE w --env-filter
spowoduje przepisanie daty każdego zatwierdzenia. Poza tym użycie git commit w środku byłoby niezwykłe --index-filter
.
Masz tutaj do czynienia z wieloma niezależnymi problemami.
Określanie dat innych niż „teraz”
Każde zatwierdzenie ma dwie daty: datę autora i datę osoby zatwierdzającej. Możesz zastąpić każdą z nich, podając wartości za pomocą zmiennych środowiskowych GIT_AUTHOR_DATE i GIT_COMMITTER_DATE dla każdego polecenia, które zapisuje nowe zatwierdzenie. Zobacz „Formaty daty” w git-commit (1) lub poniżej:
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
Jedynym poleceniem, które zapisuje nowe zatwierdzenie podczas normalnego użytkowania, jest polecenie git . Posiada również --date
opcję, która pozwala bezpośrednio określić datę autora. Twoje przewidywane użycie obejmuje git filter-branch --env-filter
również wykorzystanie wyżej wymienionych zmiennych środowiskowych (są one częścią „env”, po której nazwa jest nazwana; patrz „Opcje” w git-filter-branch (1) i leżące u jej podstaw polecenie „hydrauliczne” git-commit -drzewo (1) .
Wstawianie pliku do historii pojedynczego odwołania
Jeśli twoje repozytorium jest bardzo proste (tzn. Masz tylko jedną gałąź, bez tagów), prawdopodobnie możesz użyć git rebase do wykonania tej pracy.
W poniższych poleceniach użyj nazwy obiektu (skrót SHA-1) zatwierdzenia zamiast „A”. Nie zapomnij użyć jednej z metod „przesłonięcia daty” podczas uruchamiania 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
Jeśli chcesz zaktualizować A, aby zawierał nowy plik (zamiast tworzenia nowego zatwierdzenia w miejscu, w którym został dodany), użyj git commit --amend
zamiast git commit
. Wynik wyglądałby następująco:
---A'---B'---C'---o---o---o master
Powyższe działa tak długo, jak można nazwać zatwierdzenie, które powinno być rodzicem nowego zatwierdzenia. Jeśli naprawdę chcesz, aby nowy plik został dodany za pomocą nowego zatwierdzenia głównego (bez rodziców), potrzebujesz czegoś innego:
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
jest stosunkowo nowy (Git 1.7.2), ale istnieją inne sposoby robienia tego samego, co działa na starszych wersjach Gita.
Wstawianie pliku do historii wielu referencji
Jeśli twoje repozytorium jest bardziej złożone (tzn. Ma więcej niż jeden odnośnik (gałęzie, tagi itp.)), Prawdopodobnie będziesz musiał użyć git filter-branch . Przed użyciem git filter-branch powinieneś wykonać kopię zapasową całego repozytorium. Wystarczy proste archiwum tar całego działającego drzewa (w tym katalogu .git). git filter-branch wykonuje kopie zapasowe kopii zapasowej, ale często łatwiej jest odzyskać dane po niezupełnie właściwym filtrowaniu, po prostu usuwając .git
katalog i przywracając go z kopii zapasowej.
Uwaga: Poniższe przykłady używają polecenia niższego poziomu git update-index --add
zamiast git add
. Możesz użyć git add , ale najpierw musisz skopiować plik z jakiejś lokalizacji zewnętrznej do oczekiwanej ścieżki ( --index-filter
uruchamia polecenie w tymczasowym drzewie GIT_WORK_TREE, które jest puste).
Jeśli chcesz, aby nowy plik był dodawany do każdego istniejącego zatwierdzenia, możesz to zrobić:
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
Naprawdę nie widzę powodu, by zmieniać daty istniejących zatwierdzeń --env-filter 'GIT_AUTHOR_DATE=…'
. Gdybyś go użył, uczyniłbyś to warunkowym, aby przepisał datę każdego zatwierdzenia.
Jeśli chcesz, aby nowy plik pojawiał się tylko w zatwierdzeniach po pewnym istniejącym zatwierdzeniu („A”), możesz to zrobić:
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
Jeśli chcesz, aby plik został dodany za pomocą nowego zatwierdzenia, które ma być wstawione w środku twojej historii, musisz wygenerować nowy zatwierdzenie przed użyciem git filter-branch i dodać --parent-filter
do 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
Możesz również zaaranżować, aby plik był dodawany po raz pierwszy w nowym głównym zatwierdzeniu: utwórz nowy główny zatwierdzenie za pomocą metody „osieroconej” z sekcji git rebase (przechwyć new_commit
), użyj bezwarunkowego --index-filter
i --parent-filter
podobnego "sed -e \"s/^$/-p $new_commit/\""
.