在一系列提交上运行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似乎不允许你使用范围表示法使用两个任意参考之间的范围

在连续提交的范围内(在分支的历史记录中)运行过滤器的最直接的方法是什么?

正如@kan所说,您不能在历史记录的中间应用过滤器分支。您必须从已知的提交应用到历史记录

的末尾。
git filter-branch --env-filter '...' SHA1..HEAD

Filter-branch可以检查提交作者或其他信息,选择更改或不提交,所以有方法来完成你想要的,见https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History,寻找"全局更改电子邮件地址"

请记住:如果您已经将提交推送到公共存储库,则不应该使用filter-branch

我发现最干净的解决方案是这样做:

  1. 创建refb临时分支
  2. refa..temp上应用分支滤波器
  3. 将base重新配置到临时分支并删除。

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

git filter-branch 接受范围表示法,但范围的末尾必须是引用,而不是提交的ID。

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

如果你只想重写你的当前分支,用HEAD替换--all

你不能在历史记录的中间重写提交,因为每个提交的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?..)      

因此,masterbranch将保持不变。我觉得这不是你想要的。这意味着您必须覆盖所有提交。历史记录将会是:

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

我是这样做的。

假设您想要过滤名为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

执行后,commit at ref-for-commit-to-stop-at将不会被更改。分支branch-you-are-filtering中所有被过滤的更改的提交都将基于ref-for- committostopat。

您是否使用——commit-filter或其他东西取决于您。

@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

使用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'

最新更新