日が経過しています。情報の鮮度にご注意ください
はじめに
Gitを頻繁に使っていますが、ずっと書く時間がありませんでした。今やっと時間ができたので、よく使うコマンドをまとめてみます。
本文
新しいブランチを作成し、そのブランチに切り替える:
1 | |
ブランチを切り替える:
1 | |
ブランチを削除する(先に別のブランチにcheckoutする必要がある):
1 | |
注意:ローカルで新しいブランチを作成したが、git pushしていない場合、以下のコマンドでブランチを削除しようとすると警告が表示されます
1 | |
本当に不要な場合は、指示に従って強制削除してください。
ファイルをコミットする流れは:
1 | |
git addでよく使うパラメータは3つあります:
git add -Aすべての変更記録(新規追加、削除、変更)をステージングエリアに追加します。git add .ファイルの追加記録と変更をステージングエリアに追加しますが、削除されたファイルは含まれません。git add -uファイルの削除と変更記録をステージングエリアに追加しますが、新規追加されたファイルは含まれません。
人生に後悔薬はありませんが、gitにはあります。誤ったファイルをコミットしてしまった場合やコミットメッセージを間違えた場合は、状況に応じて以下のコマンドを実行できます。
まずgit statusでバージョン状態を確認します(私はzshを使っています)。赤いファイルはステージングエリアにgit addされていない状態、緑のファイルはすでにgit addされており、git commitを待っている状態です。
この時、git addをキャッシュエリアに行きたくない場合は、git reset HEADですべてのファイルを未git addの元の状態に戻せます。特定のファイルだけgit addをキャッシュエリアに行きたくない場合は、ファイル名を指定します:
1 | |
時には、変更したファイルをgit addキャッシュエリアに移動したくないだけでなく、そのファイルに行ったすべての変更を無視したい(つまり未変更状態に戻したい)場合もあります。その場合は再チェックアウトすればよいです:
1 | |
ここでスペルミスがないことに注意してください。checkoutとfilenameの間には左右にスペースを挟んだハイフンがあります。
git addの後はgit commitです。-mパラメータを付けてコミットメッセージを書くことができます。これは良い習慣であり、強制されています。-mパラメータがない場合は、vim編集モードに入り、メッセージを追加するよう促されます:
1 | |
この時、コミットメッセージを間違えたことに気づき、commitしたくない場合(HEADはすでに変更されています)、2つの方法があります:
1つはcommitを削除することです(これはまだpushされておらず、ローカルリポジトリにcommitされているだけです):
まずgit logし、誤ってcommitする前のcommit idをメモします。これはhash(SHA)で、例えば73cf3bfc3419a85e959d7ecfcb917d9cdc24b3c9、または直近のpushのHEADでも構いません:
1 | |
(この時はgit addの時にgit reset HEADを使うことができません。git commitの後HEADはすでに変更されているため(つまりgit logでコミット履歴を確認できる状態になっているため)です)
ここでgit resetコマンドの3つのパラメータについて補足します:--mixed,--soft,--hard:
ネット上には多くのチュートリアルがあり、図解や公式ブランチ説明の引用などがありますが、複雑です。私は簡単に説明します。
シンプルに、例を挙げて簡単に説明しましょう。 —Xheldon
git resetのデフォルトはmixedパラメータで、git reset xxxxを実行します(xxxはSHAまたは未commitの場合はHEADを表します)。これはgit reset --mixed xxxxを実行するのと同じで、ファイルを変更した後、gitコマンドを実行していない状態(ファイルが赤い状態)に戻します。
--softパラメータは、ファイルを単にコミット前の状態に戻すだけで、ファイルはまだgit addされています(緑のままです)。
--hardはより強力で、指定したコミット記録の状態に完全にファイルを復元します。addしたかcommitしたか、ファイルを変更したかに関係なく、すべて無視します。git reset --hard xxxを実行するのはある程度危険で、現在の変更がローカルから削除されることに注意してください。
git reset --hard xxxの後、ファイルはローカルから削除され、すべての変更も削除されていますが、hardで削除したファイルの変更記録を復元したい場合はどうすればよいでしょうか?git reflogを使います
あなたが行ったすべてのcommitとreset操作は、gitによって記録が生成されます。この記録はgit reflogで見つけることができ、各記録の前に短いhashがあります。この短いhashをコピーして、git reset --hard short_hashを再度実行すればよいです。
注意:git commitを実行した後、HEADはすでにコミットしたファイルの変更状態になっています。そのため、git reset --mixed HEADやgit reset --soft HEADを実行しても効果がありません(現在のHEADはcommit後のポイントだからです(pushしていなくても))。git add後の状態に戻りたい場合、git commit前の状態に戻るにはgit reset --soft commit_idが必要です。git add前の状態に戻るにはgit reset --mixed commit_id、または直接git reset commit_idします。
git commit後悔薬の別名は--amendです。コミット後に後悔し、メッセージを間違えたことに気づいた、またはファイルをさらに変更した場合、commit記録を生成したくない(見た目が悪く、あなたがコミットメッセージを間違えるような初心者に見えるため)、次のコマンドを実行します:
1 | |
これで完了です。
後悔薬を飲んだ後、git commitして問題がなければgit pushできます。この時、現在のブランチから分岐したリモートブランチに他の人が更新をコミットしていない場合は、fast forwardモード(ファストフォワードモード)を使用して直接マージできます。マージ状況を視覚的に確認するには:
1 | |
ブランチを分岐している間に他の誰かもブランチをコミットした場合、衝突がなければそのままマージできます。まずgit pullを行い、その後git pushを実行する必要があります。
衝突がある場合、他の人の変更とあなたの変更の間にどのような衝突があるかが通知されます。これは手動で解決する必要があり、解決後はgit add、git commitを行います。
ブランチのマージ:
1 | |
ここでの状況は非fast forwardモードです。つまり、ブランチBがブランチAから分岐した後、親ブランチであるAブランチが変更され、ブランチBも何らかの変更を加えた状態で、再度Aブランチにマージしようとした場合に現在の状況が発生します。
注意:あなたがブランチAにいる場合、mergeする必要があるのはブランチBです。この場合、mergされるブランチBはgit pushされている必要があります。ブランチBが単にgit commitされているだけではマージされません。なぜなら、git merge branch_nameのbranch_nameはbranch_nameのリモートoriginからmergeされており、commitはローカルのHEADのみを変更し、pushがないためリモートoriginは変更されていないからです。
ブランチBがすでにgit pushをリモートにプッシュし、ローカルのブランチAもgit addをローカルリポジトリにコミットしている場合、ブランチAでgit merge Bを実行すると(変更されたファイルがconfig.jsだと仮定して)以下のようになります:
1 | |
これは、2つのブランチをマージする際にエラーが発生して中断されたことを意味します。現在のブランチの変更を一時保存(git stash)するか、変更をコミット(git commit)するように促されます。その後、git mergeを行い、衝突が発生したら手動で修正して再度コミットします。
では、まず現在の変更をgit commitし、再度git merge Bを実行します。この時(衝突ファイルがconfig.jsだと仮定して)以下のようになります:
1 | |
手動で解決した後、再度git add、git commitを行います。
注意:あるブランチでファイルを変更し、checkoutで別のブランチに移動する際に衝突が発生しなかった場合、何の通知もなくファイルの変更は保持されます。したがって、ファイルを1つのブランチで変更した後、別のブランチにコミットすることができます。しかし、1つのブランチでファイルを変更した後、checkoutで他のブランチに移動する際に衝突が発生した場合(例えば他のブランチがgit pullされた、または他のブランチが同じファイルの同じ部分をgit commitした場合):
1 | |
この場合、まずgit stashで変更を一時保存(このstash储藏はgit add暂存ではありません。stashはファイルを特定の領域に保存し、ブランチを切り替えた後、パッチのようにこのstashを切り替えたcheckoutブランチに適用するか、またはstashを適用せず、切り替えたブランチでの作業が終わってから再度このstashを適用することができます。もちろん、stashをずっと適用したくない場合は適用しなくても問題ありません)。
ここでgit stashについて説明します。このコマンドは、2つのブランチの変更を同時に行う必要がある場合に使用されます。1つのブランチで作業を途中まで進めた状態で、別のブランチも変更する必要がある場合、途中までの作業を破棄することはできず、またcommitすることもできません。なぜなら、checkoutするとconflictが発生する可能性があるため、stashを一時保存する必要があります。
まず現在の状態を確認します。git status:
1 | |
変更を一時保存します。git stash:
1 | |
その後、再度git statusを確認します:
1 | |
これで安心して他のブランチに切り替えることができます。ここで注意すべきは、他のブランチに切り替える際に、保存したブランチの変更を現在のブランチに適用することもできるということです(衝突を恐れなければ)。保存リストを確認します。git stash list:
1 | |
これは先ほどstashした変更です。git stash applyを使用してこの最新の変更を適用できます。stashの変更が複数ある場合は、stashの名前を指定します:
1 | |
適用後、このstashは保存領域から削除されます。削除したくない場合は:
1 | |
後で削除したい場合は:
1 | |
上記の2つのコマンドでstash_nameを指定しない場合、デフォルトで最新のstashが削除されます。
とりあえず思いつくのはこれくらいです。慣れていない場合は、Sourcetreeを使用することをお勧めします。
更新
git revert/reset/rebase 説明を読むだけでは理解できません。自分でコマンドを入力してテストする必要があります。
私はクリーンで整理されたコミット履歴のためにgit rebaseを使用するのが好きですが、このコマンドは危険で、いくつかの使用シナリオに注意が必要です。git rebaseよりもさらに危険なのはgit resetで、これは現在のプロジェクトを特定のコミットにリセットします。git revertは比較的安全ですが、revertする前にキャッシュ領域が空であることを確認する必要があります。そうでないとエラーメッセージが表示されます。
もちろん、gitコマンドは数え切れないほどあります(誇張)。いくつかのコマンドは特定のシナリオ向けであり、遭遇するまでその使用方法を理解できないこともあります。これは正常です。
例えば、git reset commitIdはHEADをcommitIdの場所に移動します。これを見て「HEADを移動して何の意味があるのか?このコマンドの目的は何か?」と疑問に思うかもしれません。また、git revert commitIdはcommitIdのコミットを削除しますが、HEADのポインタは移動しません。
コードを見る(d0b9def は commit -m 'reset/revert test 3' のコミットに対応、現在 HEAD は 'reset/revert test 4' 上):
git revert d0b9def の後、あなたのコードはこのようになっているかもしれません:
1 | |
同じ HEAD 上で git reset d0b9def を実行した後、あなたのワークスペースはこのようになっているかもしれません:
1 | |
HEAD を移動させるかどうかの違いが分かりましたか? revert は必ず手動でコンフリクトを解決させるよう要求します。なぜなら、それは commitId 前の親 commit から現在の HEAD までの、d0b9def を除くすべての変更を保持するからです。一方 reset はコンフリクトを解決させず、黙って HEAD を移動させ、d0b9def 以降のすべての変更をファイル変更として表示し、手動で git add/commit する必要があります。もちろん push --force も欠かせません。
したがって、revert は 公开 のコミットを安全に取り消すように設計されており、reset は 本地 の変更をリセットするように設計されています。両コマンドの目的が異なるため、実装も異なります: リセットは一連の変更を完全に削除しますが、取り消しは元の変更を保持し、新しいコミットで取り消しを実現します。
人生の重要な選択に直面したとき、最善の方法を誰かが教えてくれて、貴重な時間を無駄にせずに済めばと、私はよく願っています。だからこそ、自分の経験を踏まえて頻繁にブログを書き、広大なインターネットのこの小さな片隅に、私にとって一度きりの人生経験を記録し、助けを求める人々の力になれればと思っています。