ファイルに対してさまざまなコミットを行う方法はありますか。ファイルを 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 を起動した後で行うこともできます。ビューのオプションの 1 つは、含めるパスのリストです。
どちらの方法でも、必要なファイルのバージョンでコミットの 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 は非常に柔軟です。求めていることを実行するのに何百ものブランチは必要ありません。状態を 2 番目の変更 (実際には既にコミットおよびプッシュされた変更) まで戻したい場合は、 を使用しますgit revert
。何かのようなもの:
git revert a4r9593432
a4r9593432 は、取り消したいコミットのハッシュの先頭文字です。
コミットに多くのファイルへの変更が含まれているが、そのうちの 1 つのファイルだけを元に戻したい場合は、次を使用できますgit reset
(2 番目または 3 番目の形式):
git reset a4r9593432 -- path/to/file.txt
# the reverted state is added to the staging area, ready for commit
git diff --cached path/to/file.txt # view the changes
git commit
git checkout HEAD path/to/file.txt # make the working tree match HEAD
しかし、これはかなり複雑で、git reset は危険です。git checkout <hash> <file path>
Jefromiが提案するように、代わりに使用してください。
コミット x でファイルがどのように見えるかを表示したいだけの場合は、次を使用できますgit show
。
git show a4r9593432:path/to/file.txt
すべてのコマンドについて、コミット ハッシュ以外にコミットを参照する多くの方法があります ( Git ユーザー マニュアルの「コミットの命名」を参照)。
Git はファイル バージョンの観点からは考えません。git のバージョンは、ツリー全体のスナップショットです。
これを考えると、あなたが本当に欲しいのは、ほとんどのファイルの最新の内容を持つツリーですが、1 つのファイルの内容は 5 コミット前と同じです。これは、古いものの上に新しいコミットの形を取り、ツリーの最新バージョンには必要なものが含まれます。
単一のファイルを 5 コミット前の内容に戻すワンライナーがあるかどうかはわかりませんが、lo-fi ソリューションは機能するはずです: checkout master~5
、ファイルを別の場所にコピーし、 checkout master
、ファイルをコピーして戻します。専念。
必要な変更を元に戻す差分を取り、それをコミットできます。
たとえば、範囲内の変更を元に戻したい場合from..to
は、次のようにします。
git diff to..from > foo.diff # get a reverse diff
patch < foo.diff
git commit -a -m "Undid changes from..to".