Поради, які вам дали, є хибними. Безумовне встановлення GIT_AUTHOR_DATE в а --env-filter
може переписати дату кожного вчинення. Крім того, було б незвично використовувати git commit всередині --index-filter
.
Тут ви маєте справу з численними незалежними проблемами.
Вказання дат, відмінних від "зараз"
Кожне зобов’язання має дві дати: дата автора та дата здійснення. Ви можете змінити їх, подавши значення через змінні середовища GIT_AUTHOR_DATE та GIT_COMMITTER_DATE для будь-якої команди, яка записує нову команду. Див. "Формати дати" в git-commit (1) або нижче:
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
Єдина команда, яка пише нове фіксування під час звичайного використання, - це git počin . Він також має --date
опцію, яка дозволяє безпосередньо вказати дату автора. Передбачуване використання включає git filter-branch --env-filter
також використання згаданих вище змінних оточуючих середовищ (вони є частиною "env", після якої названа опція; див. "Параметри" у гіт-фільтр-гілці (1) та основна команда "сантехніка" git-commit -три (1) .
Вставлення файлу в єдину історію посилання
Якщо ваш сховище дуже просте (тобто у вас є лише одна гілка, немає тегів), ви, ймовірно, можете використовувати git rebase для виконання роботи.
У наступних командах використовуйте назву об'єкта (хеш SHA-1) комітки замість "A". Не забувайте використовувати один із методів “переопрацювання дат” під час запуску програми git .
---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
Якщо ви хочете оновити A, щоб він включив новий файл (замість створення нового комітету там, де він був доданий), тоді використовуйте git commit --amend
замість git commit
. Результат виглядатиме так:
---A'---B'---C'---o---o---o master
Вищезазначене працює до тих пір, поки ви можете назвати команду, яка повинна бути батьківською вашою новою комісією. Якщо ви дійсно хочете, щоб ваш новий файл був доданий через нову кореневу комісію (немає батьків), вам знадобиться щось трохи інше:
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
є відносно новим (Git 1.7.2), але є й інші способи зробити те саме, що працює і на старих версіях Git.
Вставлення файлу в історію багаторазового використання
Якщо ваш репозиторій складніший (тобто він має більше одного посилання (гілки, теги тощо)), вам, ймовірно, доведеться використовувати фільтр-гілку git . Перш ніж використовувати гіт-фільтр-гілку , слід зробити резервну копію всього вашого сховища. Досить простого архіву tar для всього вашого робочого дерева (включаючи каталог .git). git filter-branch робить резервні копії, але часто простіше відновитись із не зовсім правильної фільтрації, просто видаливши .git
каталог та відновивши його із резервної копії.
Примітка. Наведені нижче приклади використовують команду нижчого рівня git update-index --add
замість git add
. Ви можете використовувати git add , але спочатку потрібно буде скопіювати файл з якогось зовнішнього місця на очікуваний шлях ( --index-filter
виконує його команду у тимчасовому GIT_WORK_TREE, який порожній).
Якщо ви хочете, щоб ваш новий файл був доданий до кожної існуючої комісії, ви можете зробити це:
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
Я дійсно не бачу причин змінювати дати існуючих комісій --env-filter 'GIT_AUTHOR_DATE=…'
. Якби ви його використовували, ви зробили б це умовно, щоб він переписав дату для кожного вчинення.
Якщо ви хочете, щоб ваш новий файл відображався лише в комітетах після деяких існуючих фіксованих файлів ("A"), ви можете зробити це:
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
Якщо ви хочете, щоб файл був доданий за допомогою нового комітету, який потрібно вставити в середину вашої історії, вам потрібно буде генерувати новий комітет перед використанням git filter-branch та додати --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
Крім того, можна організувати файл , щоб бути першим доданий в новому корені фіксації: створити новий корінь здійснювати через «сирітський» метод з мерзотник Rebase секції (захоплення його в new_commit
), використовувати безумовний --index-filter
і --parent-filter
як "sed -e \"s/^$/-p $new_commit/\""
.