git 在一系列提交上运行 filter-branch

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15250070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 08:16:19  来源:igfitidea点击:

Running filter-branch over a range of commits

gitgit-filter-branch

提问by Acorn

git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="[email protected]"
export GIT_AUTHOR_NAME="foo"' -- commita..commitb

Results in Which ref do you want to rewrite?

结果是 Which ref do you want to rewrite?

So it seems that filter-branchdoesn't allow you to use range notationuse a range between two arbitrary refs.

因此,似乎filter-branch不允许您使用范围表示法使用两个任意参考之间的范围。

What is the most straight forward way of running a filter over a range of consecutive commits (somewhere within the history of a branch) if this approach isn't possible.

如果这种方法不可行,那么在一系列连续提交(分支历史中的某处)上运行过滤器的最直接方法是什么。

采纳答案by Acorn

The cleanest solution I found was to do the following:

我找到的最干净的解决方案是执行以下操作:

  1. Create a temporary branch at refb.
  2. Apply the branch filter on refa..temp.
  3. Rebase onto the temporary branch and delete it.
  1. 在 处创建一个临时分支refb
  2. 在 上应用分支过滤器refa..temp
  3. 变基到临时分支并删除它。

ie.

IE。

git branch temp refb

git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="[email protected]"' refa..temp

git rebase temp
git branch --delete temp

回答by Pedro San??o

You cannot apply the filter-branch in the middle of the history, as said by @kan. You must apply from your known commit to the end of the history

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

git filter-branch --env-filter '...' SHA1..HEAD

Filter-branch can check for the commit author or other information, to chose to change or not the commit, so there are ways to accomplish what you want, see https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History, look for "Changing Email Addresses Globally"

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

Remember: if you have pushed the commits to a public repository you should not user filter-branch

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

回答by qqx

git filter-branchdoesaccept range notation, but the end of the range needs to be a reference, not the ID of a commit.

git filter-branch确实接受范围表示法,但范围的结尾需要是引用,而不是提交的 ID。

git checkout -b tofilter commitb
git filter-branch .... commita..tofilter

If given just commits, it would not know what ref to update with the filtered branch.

如果只给出提交,它不会知道用过滤的分支更新什么引用。

回答by Chronial

Enclose you filter commands in an if-statement that checks for that range. You can check whether a commit is within a given range with this command:

将过滤命令括在检查该范围的 if 语句中。您可以使用以下命令检查提交是否在给定范围内:

git rev-list start..end | grep **fullsha**

The current commit will be stored in $GIT_COMMITin your filter. So your filter becomes:

当前提交将存储$GIT_COMMIT在您的过滤器中。所以你的过滤器变成:

git filter-branch --env-filter '
  if git rev-list commita..commitb | grep $GIT_COMMIT; then
    export GIT_AUTHOR_EMAIL="[email protected]"
    export GIT_AUTHOR_NAME="foo"
  fi' -- ^commita --all

If you want to only rewrite your current branch, replace --allwith HEAD

如果您只想重写当前分支,请替换--allHEAD

回答by kan

You cannot just override commits in a middle of a history, because sha1 of a commit depends on a parent's. So, the git doesn't know where do you want point your HEAD reference after the filtration. So, you should rewrite all up to the HEAD.

您不能只覆盖历史中间的提交,因为提交的 sha1 取决于父项。所以,git 不知道过滤后你想把你的 HEAD 引用指向哪里。因此,您应该将所有内容重写为 HEAD。

Example:

例子:

A---B---C---D---E---F   master
            \
             \--G---H   branch

if you want filter commits B and C you should also filter all commits after: D, E, F, G, H. So, that's why git tells you to use a ref at the end of the range, so that it just not finishes up with a detached head.

如果您想过滤提交 B 和 C,您还应该过滤以下所有提交:D、E、F、G、H。所以,这就是为什么 git 告诉您在范围末尾使用 ref,这样它就不会完成一个独立的头。

After you modify B and C commits and stop will look like this:

修改 B 和 C 提交和停止后将如下所示:

A---B---C---D---E---F   master
\           \
 \           \--G---H   branch
  \-B'--C'      (HEAD or a temporary TAG?..)      

So, the masterand branchwill be untouched. I don' think this is that you want. It means you must override all commits. The history will be then:

因此,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

回答by Mark F Guerra

I do it this way.

我是这样做的。

Let's say you want to filter the content of a branch called branch-you-are-filtering.

假设您要过滤名为 branch-you-are-filtering 的分支的内容。

Assume that there's an ancestor commit to that branch, with a ref called ref-for-commit-to-stop-at.

假设有一个祖先提交到那个分支,有一个名为 ref-for-commit-to-stop-at 的引用。

git filter-branch --commit-filter 'YOUR_FILTER_COMMANDS' branch-you-are-filtering...ref-for-commit-to-stop-at

After executing, the commit at ref-for-commit-to-stop-at will not be altered. All the filtered\changed commits in branch branch-you-are-filtering will be based on ref-for-commit-to-stop-at.

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

Whether or not you're using --commit-filter or something else is up to you.

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

回答by niels

The solution from @Acron seems wrong to me. I would suggest following to change between refa and refb including both hashes:

@Acron 的解决方案对我来说似乎是错误的。我建议按照以下步骤在 refa 和 refb 之间进行更改,包括两个哈希值:

  1. git tag master.bak
  2. git reset --hard refa
  3. git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="[email protected]"' refa^..master
  4. git cherry-pick refb..master.bak
  5. git tag -d master.bak
  1. git tag master.bak
  2. git reset --hard refa
  3. git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="[email protected]"' refa^..master
  4. git cherry-pick refb..master.bak
  5. git tag -d master.bak

回答by jthill

Use filter-branch's --setupparm and some shell power:

使用 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"
        [email protected]
}
' --env-filter 'eval $filterfor_$GIT_COMMIT'