あるファイルの異なるコミットをさかのぼる方法はありますか? 例えば、あるファイルを5回変更した後、コミットしてリポジトリにプッシュした後に、変更点2に戻りたいとします。
私の理解では、唯一の方法は多くのブランチを維持することですが、これは正しいでしょうか? もし私の理解が正しければ、数日のうちに何百ものブランチを持つことになるでしょうから、たぶん本当に理解していないのだと思います。
どなたか教えてください。
まず、私たちがやりたいことを定性的に説明しましょう(多くはBen Straub'の回答に書かれています)。いくつかのコミットを行い、そのうちの5つがあるファイルを変更したので、そのファイルを以前のバージョンに戻したいと考えています。まず第一に、git は個々のファイルのバージョン番号を記録しません。つまり、コミットは基本的に作業ツリーのスナップショットであり、いくつかのメタデータ (コミットメッセージなど) も含まれています。そのため、どのコミットに目的のファイルのバージョンがあるのかを知る必要があります。それがわかれば、ファイルをその状態に戻すための新しいコミットを作成する必要があります。(履歴をいじることはできません。なぜなら、私たちはすでにこのコンテンツをプッシュしており、履歴を編集すると他の人たちに迷惑がかかるからです)
では、正しいコミットを見つけることから始めましょう。あるファイルに変更を加えたコミットは、とても簡単に見ることができます。
git log path/to/file
コミットメッセージでは不十分で、各コミットでファイルに何が行われたかを確認する必要がある場合は、-p/--patch
オプションを使用します。
git log -p path/to/file
あるいは、gitk のグラフィカルな表示のほうが好きなら
gitk path/to/file
これは、gitk を起動した後でビューメニューから行うこともできます。ビューのオプションのひとつに、インクルードするパスのリストが用意されています。
どちらにしても、あなたが欲しいファイルのバージョンを含むコミットの SHA1 (ハッシュ) を見つけることができます。あとは、これだけです。
# get the version of the file from the given commit
git checkout <commit> path/to/file
# and commit this modification
git commit
(checkoutコマンドは、まずファイルをインデックスに読み込んでから作業ツリーにコピーしますので、git add
を使ってコミットの準備としてインデックスに追加する必要はありません)
ファイルに単純な履歴がない場合(リネームやコピーなど)は、VonC'さんの素晴らしいコメントを参照してください。git` は、速度を犠牲にしても、そのようなものをより注意深く検索するように指示することができます。履歴が単純であると確信しているのであれば、気にする必要はありません。
Gitは、ファイルのバージョンという観点からは考えません。gitのバージョンとは、ツリー全体のスナップショットです。
そう考えると、あなたが本当に欲しいのは、ほとんどのファイルの内容が最新のものになっていて、かつあるファイルの内容が5コミット前と同じものになっているツリーです。これは、古いコミットの上に新しいコミットをするという形で行われ、ツリーの最新バージョンはあなたが望むものになります。
1つのファイルを5コミット前の内容に戻すワンライナーがあるかどうかはわかりませんが、「master~5
をチェックアウトして、ファイルをどこかにコピーして、master
をチェックアウトして、ファイルをコピーして、コミットする」というローファイな解決策は機能するはずです。