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
不允许你使用范围符号使用两个任意引用之间的范围。
如果无法采用这种方法,那么在一系列连续提交(分支历史中某处)上运行过滤器的最直接方法是什么。
答案 0 :(得分:25)
如@kan所说,你不能在历史中间应用过滤器分支。您必须从已知提交申请到历史记录的末尾
git filter-branch --env-filter '...' SHA1..HEAD
Filter-branch可以检查提交作者或其他信息,选择是否更改提交,因此有多种方法可以完成您想要的操作,请参阅http://git-scm.com/book/ch6-4.html,查找“更改电子邮件地址全局“
请记住:如果您已将提交推送到公共存储库,则不应使用filter-branch
答案 1 :(得分:23)
我发现最干净的解决方案是执行以下操作:
refb
创建临时分支。refa..temp
上应用分支过滤器。<强>即强>
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
答案 2 :(得分:10)
git filter-branch
确实接受范围表示法,但范围的结尾需要是引用,而不是提交的ID。
git checkout -b tofilter commitb
git filter-branch .... commita..tofilter
如果只是提交,它将不知道什么引用过滤分支更新。
答案 3 :(得分:6)
将过滤命令包含在检查该范围的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
答案 4 :(得分:4)
我是这样做的。
假设您要过滤名为branch-you-are-filtering的分支的内容。
假设有一个祖先提交到该分支,其中一个引用称为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或其他东西取决于你。
答案 5 :(得分:2)
您不能只在历史记录中覆盖提交,因为提交的sha1取决于父级。所以,git不知道在过滤后你想在哪里指向你的HEAD参考。所以,你应该重写HEAD。
示例:
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
答案 6 :(得分:0)
来自@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
答案 7 :(得分:0)
使用filter-branch的--setup
parm和一些shell功能:
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'