git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="foo@example.com"
export GIT_AUTHOR_NAME="foo"' -- commita..commitb
在“你想重写哪个ref?”中获得结果。
因此,似乎filter-branch
不允许您在两个任意refs之间使用范围符号。
如果这种方法不可行,那么运行过滤器以覆盖一系列连续提交的最直接方法是什么?
git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="foo@example.com"
export GIT_AUTHOR_NAME="foo"' -- commita..commitb
在“你想重写哪个ref?”中获得结果。
因此,似乎filter-branch
不允许您在两个任意refs之间使用范围符号。
如果这种方法不可行,那么运行过滤器以覆盖一系列连续提交的最直接方法是什么?
@kan说过,你不能在历史的中间应用filter-branch。你必须从已知提交开始应用,一直到历史的结束。
git filter-branch --env-filter '...' SHA1..HEAD
Filter-branch可以检查提交者或其他信息,选择更改或不更改提交内容,因此有方法可以实现你想要的目标,请参见https://git-scm.com/book/zh/v2/Git-工具-重写历史,查找“全局更改电子邮件地址”。
请记住:如果你已经把提交推送到公共代码库,就不应该使用filter-branch。
我找到的最干净的解决方案是:
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
refa..temp
上运行,而你的 rebase 命令应该是 git rebase --onto temp refa refb
。 - Chronialgit filter-branch
可以 接受范围表示法,但是范围的结尾需要是引用,而不是提交的ID。
git checkout -b tofilter commitb
git filter-branch .... commita..tofilter
在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
我用以下方式进行操作。
假设你想要过滤名为“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),因为提交(commit)的SHA1值取决于其父级。因此,Git不知道在过滤后你想将HEAD引用指向哪里。所以,你需要重写所有直到HEAD。
例如:
A---B---C---D---E---F master
\
\--G---H branch
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
C
之后的提交,你认为最好的方法是什么?我可以创建一个临时标签吗? - AcornC'
),你必须至少过滤所有这些提交,以便将它们的祖先从 C
更改为 C'
,否则,只需将主分支移动到 C'
并放弃它们。没有其他选择。每个提交都在其 SHA1 ID 中加密了其之前的所有历史记录,因此每个提交都受到密码保护,你不能在不被察觉的情况下更改历史记录。 - kangit rev-list commita..commitb
获取您感兴趣的提交列表,然后在脚本中检查当前提交是否在列表中。此外,这可能会有所帮助:https://dev59.com/aXA75IYBdhLWcg3w9-Sx - kan使用 filter-branch 的 --setup
参数和一些 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'
我认为@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