Запуск filter-branch по диапазону коммитов
git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="foo@example.com"
export GIT_AUTHOR_NAME="foo"' -- commita..commitb
результаты Which ref do you want to rewrite?
получается, что filter-branch
не позволяет использовать обозначение диапазона используйте диапазон между двумя произвольными ссылками.
каков наиболее прямой способ запуска фильтра по диапазону последовательных коммитов (где-то в истории ветви), если этот подход невозможен.
8 ответов
самым чистым решением, которое я нашел, было сделать следующее:
- создайте временную ветку в
refb
. - применить фильтр ветви на
refa..temp
. - Rebase на временную ветку и удалить его.
ie.
git branch temp refb
git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="foo@example.com"' refa..temp
git rebase temp
git branch --delete temp
вы не можете применить ветвь фильтра в середине истории, как сказал @kan. Вы должны подать заявку с вашего известного фиксации до конца истории
git filter-branch --env-filter '...' SHA1..HEAD
Filter-branch может проверить автора фиксации или другую информацию, чтобы выбрать изменение или не фиксацию, поэтому есть способы выполнить то, что вы хотите, см. http://git-scm.com/book/ch6-4.html, Ищите "изменение адресов электронной почты по всему миру"
помните: если вы нажали фиксации в публичном репозитории вы не должны фильтровать пользователя-ветвь
git filter-branch
тут принять обозначение диапазона, но конец диапазона должен быть ссылкой, а не идентификатором фиксации.
git checkout -b tofilter commitb
git filter-branch .... commita..tofilter
Если даны только коммиты, он не будет знать, какой ref обновить с отфильтрованной веткой.
заключите команды фильтрации в Оператор if, который проверяет этот диапазон. Вы можете проверить, является ли фиксация в заданном диапазоне с помощью этой команды:
git rev-list start..end | grep **fullsha**
текущая фиксация будет сохранена в $GIT_COMMIT
в фильтре. Таким образом, ваш фильтр становится:
git filter-branch --env-filter '
if git rev-list commita..commitb | grep $GIT_COMMIT; then
export GIT_AUTHOR_EMAIL="foo@example.com"
export GIT_AUTHOR_NAME="foo"
fi' -- ^commita --all
если вы хотите переписать только текущую ветку, замените --all
С HEAD
Я делаю это так.
предположим, вы хотите отфильтровать содержимое ветви под названием Ветвь-вы-фильтруете.
предположим, что есть фиксация предка для этой ветви с ref-именем ref-for-commit-to-stop-at.
git filter-branch --commit-filter 'YOUR_FILTER_COMMANDS' branch-you-are-filtering...ref-for-commit-to-stop-at
после выполнения фиксация в ref-for-commit-to-stop-at не будет изменена. Все отфильтрованные \ измененные коммиты в ветви ветви-вы-фильтруете будут основаны на ref-for-commit-to-stop-at.
ли вы используете -- commit-filter или что-то еще зависит от вас.
вы не можете просто переопределить коммиты в середине истории, потому что sha1 коммита зависит от родительского. Таким образом, git не знает, где вы хотите указать свою головную ссылку после фильтрации. Так что перепиши все по порядку.
пример:
A---B---C---D---E---F master
\
\--G---H branch
если вы хотите фильтровать коммиты B и C, вы также должны фильтровать все коммиты после: D, E, F, G, H. Итак, вот почему git говорит вам использовать ref в конце диапазона, чтобы он просто не заканчивался с отрешенной головой.
после изменения коммитов B и C и остановки будет выглядеть так:
A---B---C---D---E---F master
\ \
\ \--G---H branch
\-B'--C' (HEAD or a temporary TAG?..)
Итак,master
и branch
останутся нетронутыми. Не думаю, что ты этого хочешь.
Это означает, что вы должны переопределить все коммиты. История будет тогда:
A---B---C---D---E---F (loose end, will be garbage collected one day)
\ \
\ \--G---H (loose end, will be garbage collected one day)
\-B'--C'--D'--E'--F' master
\
\--G'--H' branch
решение от @Acron кажется мне неправильным. Я бы предложил следующее, чтобы изменить между refa и refb, включая оба хэша:
git tag master.bak
git reset --hard refa
git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="foo@example.com"' refa^..master
git cherry-pick refb..master.bak
git tag -d master.bak
используйте фильтр-ветвь --setup
parm и некоторая мощность оболочки:
git filter-branch --setup '
for id in `git rev-list commitA..commitB`; do
eval filterfor_$id=rewrite
done
rewrite() {
GIT_AUTHOR_NAME="Frederick. O. Oosball"
GIT_AUTHOR_EMAIL=foobar@example.org
}
' --env-filter 'eval $filterfor_$GIT_COMMIT'