Запуск 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 ответов


самым чистым решением, которое я нашел, было сделать следующее:

  1. создайте временную ветку в refb.
  2. применить фильтр ветви на refa..temp.
  3. 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, включая оба хэша:

  1. git tag master.bak
  2. git reset --hard refa
  3. git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="foo@example.com"' refa^..master
  4. git cherry-pick refb..master.bak
  5. 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'