web-dev-qa-db-ja.com

一連のコミットでフィルターブランチを実行する

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

Which ref do you want to rewrite?の結果

filter-branchでは、 範囲表記を使用する 2つの任意の参照間の範囲を使用します。

このアプローチが不可能な場合、一連の連続したコミット(ブランチの履歴内のどこか)に対してフィルターを実行する最も簡単な方法は何ですか。

47
Acorn

私が見つけた最もきれいな解決策は次のことをすることでした:

  1. refbに一時的なブランチを作成します。
  2. refa..tempにブランチフィルターを適用します。
  3. 一時的なブランチにリベースして削除します。

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
23
Acorn

@kanが言うように、フィルターブランチを履歴の途中で適用することはできません。あなたはあなたの既知のコミットから歴史の終わりまで適用しなければなりません

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

フィルターブランチはコミットの作者やその他の情報をチェックして、変更するかしないかを選択できるので、あなたが望むことを達成する方法があります、 https://git-scm.com/book/en)を参照してください/ v2/Git-Tools-Rewriting-History 、「メールアドレスをグローバルに変更」を探します

覚えておいてください:コミットをパブリックリポジトリにプッシュした場合、filter-branchを使用しないでください

29
Pedro Sanção

git filter-branchdoes範囲表記を受け入れますが、範囲の終わりは、コミットのIDではなく、参照である必要があります。

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

コミットのみが与えられた場合、フィルタリングされたブランチで更新する参照がわかりません。

11
qqx

その範囲をチェックする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="[email protected]"
    export GIT_AUTHOR_NAME="foo"
  fi' -- ^commita --all

現在のブランチのみを書き換える場合は、--allHEADに置き換えます

6
Chronial

コミットの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
4
kan

私はこのようにします。

たとえば、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を使用するかどうかは、あなた次第です。

4
Mark F Guerra

フィルターブランチの--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"
        [email protected]
}
' --env-filter 'eval \$filterfor_$GIT_COMMIT'
0
jthill

@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
0
niels