web-dev-qa-db-ja.com

過去にGitをコミットするにはどうすればよいですか?

私は個人的な使用のためにすべてをGitに変換していますが、すでにリポジトリにある古いバージョンのファイルをいくつか見つけました。ファイルの正確な履歴があるように、ファイルの「変更日」に従って正しい順序で履歴にコミットするにはどうすればよいですか?

私はこのような何かがうまくいくと言われました:

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

あなたが与えられたアドバイスには欠陥があります。 --env-filterにGIT_AUTHOR_DATEを無条件に設定すると、すべてのコミットの日付が書き換えられます。また、--index-filter内でgit commitを使用することはまれです。

ここでは、複数の独立した問題に対処しています。

「今」以外の日付の指定

各コミットには、作成者の日付とコミッターの日付の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

通常の使用中に新しいコミットを書き込む唯一のコマンドは、git commitです。また、作成者の日付を直接指定できる--dateオプションもあります。予想される使用法にはgit filter-branch --env-filterも含まれ、上記の環境変数も使用されます(これらは「env」の一部であり、その後にオプションに名前が付けられます。 「Options」in git-filter-branch(1) および基礎となる「配管」コマンド git-commit-tree(1)

単一のref履歴へのファイルの挿入

リポジトリが非常に単純な場合(つまり、タグが1つしかブランチがない場合)、おそらくgit rebaseを使用して作業を行うことができます。

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

---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の古いバージョンで動作する 同じことを行う他の方法 があります。

Multi-ref履歴へのファイルの挿入

リポジトリがより複雑な場合(つまり、複数の参照(ブランチ、タグなど)がある場合)、おそらくgit filter-branchを使用する必要があります。 git filter-branchを使用する前に、リポジトリ全体のバックアップコピーを作成する必要があります。単純なtar作業ツリー全体(.gitディレクトリを含む)のアーカイブで十分です。 git filter-branchはバックアップ参照を作成しますが、多くの場合、.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-filtergit filter-branchに追加します:

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セクションから「Orphan」メソッドを使用して新しいルートコミットを作成します(new_commitでキャプチャします)。無条件の--index-filter、および--parent-filterのような"sed -e \"s/^$/-p $new_commit/\""を使用します。

180
Chris Johnsen

通常どおりコミットを作成できますが、コミットするときに、環境変数GIT_AUTHOR_DATEおよびGIT_COMMITTER_DATEを適切な日時に設定します。

もちろん、これによりブランチの先端でコミットが行われます(つまり、現在のHEADコミットの前)。レポジトリでさらにプッシュバックする場合は、少し凝ったものにする必要があります。この歴史があるとしましょう:

o--o--o--o--o

そして、新しいコミット( "X"としてマーク)を表示したいsecond

o--X--o--o--o--o

最も簡単な方法は、最初のコミットから分岐し、新しいコミットを追加してから、新しいコミットの上に他のすべてのコミットをリベースすることです。そのようです:

$ git checkout -b new_commit $desired_parent_of_new_commit
$ git add new_file
$ GIT_AUTHOR_DATE='your date' GIT_COMMITTER_DATE='your date' git commit -m 'new (old) files'
$ git checkout master
$ git rebase new_commit
$ git branch -d new_commit
108
mipadi

私はこの質問がかなり古いことを知っていますが、それは実際に私のために働いたものです:

git commit --date="10 day ago" -m "Your commit message" 
86
Hyder B.

私の場合、時間の経過とともにmyfileのバージョンをmyfile_bak、myfile_old、myfile_2010、backups/myfileなどとして保存していました。変更日を使用してgitにmyfileの履歴を入れたいと思いました。したがって、最も古いものをgit add myfile、次にgit commit --date=(modification date from ls -l) myfileに名前を変更し、次に古いものをmyfileに名前を変更し、別のgitコミットを--dateで繰り返し、...

これをある程度自動化するには、Shell-fooを使用してファイルの変更時間を取得します。 ls -lcutで始めましたが、stat(1)の方がより直接的です

 git commit --date = "` stat -c%y マイファイル`" マイファイル
32
skierpage

私の場合、-dateオプションを使用しているときに、gitプロセスがクラッシュしました。恐ろしいことをしたかもしれません。その結果、index.lockファイルがいくつか出現しました。だから私は手動で.lockファイルを.gitフォルダーから削除して実行しました。すべての変更されたファイルは渡された日付にコミットされ、今回は機能しました。ここにすべての答えをありがとう。

git commit --date="`date --date='2 day ago'`" -am "update"
16
JstRoRR

以下は、過去fooからN=1日までの変更をコミットするために使用するものです。

git add foo
git commit -m "Update foo"
git commit --amend --date="$(date -v-1d)"

3日前など、さらに古い日付にコミットする場合は、date引数を変更します:date -v-3d

たとえば、昨日何かをコミットするのを忘れたとき、それは本当に便利です。

UPDATE--dateは、--date "3 days ago"または--date "yesterday"などの式も受け入れます。したがって、1行のコマンドに減らすことができます。

git add foo ; git commit --date "yesterday" -m "Update"
15
Vilson Vieira

いつでもコンピューターの日付を変更し、コミットしてから、日付を変更してプッシュすることができます。

3
Nik

過去に行われたように見えるコミットを行うには、GIT_AUTHOR_DATEGIT_COMMITTER_DATEの両方を設定する必要があります。

GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'

date -d'...'は、2019-01-01 12:00:00のような正確な日付、または5 months ago 24 days agoのような相対的な日付にすることができます。

Gitログで両方の日付を表示するには、次を使用します。

git log --pretty=fuller
3
mx0

または、コマンドラインツールhttps://github.com/artiebits/fake-git-historyを使用して、特定のデータ範囲用に生成します

1
rel1x