1. ホーム
  2. ギット

[解決済み】Gitのコミットを過去にする方法とは?

2022-03-29 01:47:01

質問

個人的に使用するためにすべてを Git に変換しているのですが、あるファイルの古いバージョンがすでにリポジトリにあるのを見つけました。 ファイルの正確な履歴を残すために、ファイルの "date modified" に従って正しい順序で履歴にコミットするにはどうしたらよいでしょうか。

このようなことができると聞きました。

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all  

解決方法は?

あなたが受けたアドバイスには欠陥があります。GIT_AUTHOR_DATEを無条件で --env-filter は、すべてのコミットの日付を書き換えてしまいます。また ギットコミット 内部 --index-filter .

ここでは、複数の独立した問題を扱っているのですね。

"now "以外の日付の指定

各コミットには、作者日付とコミッター日付の2つの日付があります。環境変数 GIT_AUTHOR_DATE と GIT_COMMITTER_DATE を指定することで、新しいコミットを書き込む際にそれぞれの日付を上書きすることができます。以下を参照してください。 git-commit(1) の「日付の書式」です。 または下記をご参照ください。

Git internal format = <unix timestamp> <time zone offset>, e.g.  1112926393 +0200
RFC 2822            = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601            = e.g. 2005-04-07T22:13:13

通常使用時に新しいコミットを書き込む唯一のコマンドは ギットコミット . また --date オプションを使えば、作者の日付を直接指定することができます。想定される使い方は git filter-branch --env-filter は、上記の環境変数も使用します (これらは、このオプションの名前の由来となった "env" の一部です。 git-filter-branch(1) の「オプション」です。 と、その基礎となる "plumbing "コマンド git-commit-tree(1)です。 .

シングルへのファイルの挿入 レフ 歴史

リポジトリが非常にシンプルな場合 (すなわち、単一のブランチのみで、タグがない場合) は、おそらく git rebase を実行します。

以下のコマンドでは、"A "の代わりにコミットのオブジェクト名(SHA-1ハッシュ)を使用します。 を実行するときは、「日付の上書き」メソッドのいずれかを使用することを忘れないでください。 git commit .

---A---B---C---o---o---o   master

git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit

---A---N                      (was ",new-commit", but we delete the tag)
        \
         B'---C'---o---o---o   master

新しいファイルを含むように A を更新したい場合 (新しいコミットを作成してそこにファイルを追加するのではなく)、次のようにします。 git commit --amend の代わりに git commit . その結果は次のようになります。

---A'---B'---C'---o---o---o   master

上記は、新しいコミットの親となるべきコミットの名前を指定できる限り、動作します。もし、実際に新しいファイルを新しいルートコミット(親がいない)で追加したい場合は、少し異なる方法が必要です。

B---C---o---o---o   master

git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root

N                       (was new-root, but we deleted it)
 \
  B'---C'---o---o---o   master

git checkout --orphan は比較的新しいものですが (Git 1.7.2)、その中には 同じことをする他の方法 は、古いバージョンのGitでも動作します。

ファイルをマルチに挿入する レフ 歴史

リポジトリがより複雑な場合(つまり、複数の参照(ブランチ、タグなど)を持っている場合)、おそらくは git フィルタブランチ . を使用する前に git フィルタブランチ は、リポジトリ全体のバックアップコピーを作成する必要があります。 簡単な タール は、作業ツリー全体(.gitディレクトリを含む)のアーカイブで十分です。 gitフィルターブランチ はバックアップ参照を作成しますが、正しいフィルタリングでない場合、単に .git ディレクトリを作成し、バックアップから復元してください。

注:以下の例では、下位のコマンドである git update-index --add の代わりに git add . を使用することができます。 git add しかし、まずファイルを外部の場所から期待されるパスにコピーする必要があります ( --index-filter は、空の一時的な GIT_WORK_TREE 内でコマンドを実行します)。

もし、新しいファイルを既存のコミットごとに追加したい場合は、このようにします。

new_file=$(git hash-object -w path/to/file)
git filter-branch \
  --index-filter \
    'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
  --tag-name-filter cat \
  -- --all
git reset --hard

を使用して既存のコミットの日付を変更する理由は特に見当たりません。 --env-filter 'GIT_AUTHOR_DATE=…' . もし使うなら、コミットごとに日付を書き換えるような条件付きにするはずです。

もし、新しいファイルをある既存のコミット("A")の後のコミットだけに表示させたい場合は、このようにすればよいでしょう。

file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

もしファイルを履歴の途中に挿入する新しいコミットで追加したい場合は、新しいコミットを生成する前に git filter-branch を追加し --parent-filter git フィルターブランチ :

file_path=path/to/file
before_commit=$(git rev-parse --verify A)

git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -

git filter-branch \
  --parent-filter "sed -e s/$before_commit/$new_commit/g" \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

新しいルートコミットで最初にファイルを追加するように手配することもできます。 git rebase セクション(それを new_commit ) を使用する場合は、無条件に --index-filter を、そして --parent-filter のように "sed -e \"s/^$/-p $new_commit/\"" .