シーン別 Git チートシート

目次

チートシート

初期化と複製

現在のディレクトリで Git を利用開始する

git init

既存のレポジトリを手元に複製して利用する

git clone <repository>

ファイル操作

現在のワーキングツリーとインデックスの状態の確認

git status

ファイルの最新の状態をインデックスに追加(ステージング)する。<path>がディレクトリの場合はディレクトリ内のすべてのファイルが対象となる。

git add <path>

ディレクトリの中のすべてのファイルをインデックスに追加する

git add <dir>

ステージングをキャンセルする

git reset <path>

ファイルを編集前の状態(HEAD)に復元する

git checkout HEAD <path>

ファイルをインデックスの状態に復元する

git checkout <path>

ファイルを削除する

git rm <path>

ファイルを移動する

git mv <src> <dst>

トラックされていないファイルを消す

git clean -f

Git レポジトリの作成と複製

現在のレポジトリで Git の利用を開始するにはgit initを実行します

$ git init
Initialized empty Git repository in /home/yunabe/src/myrepository/.git/

既存のレポジトリを手元に複製(クローン)するにはgit cloneを実行します。

git clone <repository> [<directory>]

<repository>は多くの場合 GitHub などのリモートサーバー上のレポジトリを指しますが、ローカルディスク上のレポジトリを指定することも可能です。複製先のディレクトリ名<direcotyr>は省略可能です。

$ git clone https://github.com/yunabe/codelab mylab
Cloning into 'mylab'...
remote: Enumerating objects: 34, done.
remote: Counting objects: 100% (34/34), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 2624 (delta 6), reused 32 (delta 5), pack-reused 2590
Receiving objects: 100% (2624/2624), 1.71 MiB | 1.39 MiB/s, done.
Resolving deltas: 100% (1069/1069), done.

init, clone ともに --bare というオプションを持っており、--bareを指定した場合にはgit pushが行える裸のレポジトリ(bare repository)が作成されます。

ワーキングツリーとインデックスの操作

Git ではファイルは、ローカルで編集済み → ステージ済み → コミット済みという手順を経てレポジトリに記録されます。まずはじめにコミットするまえにローカルでファイルを編集したり、それをインデックスにステージするためのコマンド類をまとめます。

git status: ワーキングツリーとインデックスの状態を表示

どのファイルがワーキングツリー上で編集されているか、どのファイルがインデックスにステージングされているかなどはgit statusで表示します。

git status

git add: ワーキングツリーのファイルをインデックスに反映する(ステージング)

Git ではコミットする前に、変更を「インデックス」に対してアップロードする必要があります。ワーキングツリー(作業ツリー)上の現在のファイルの状態をインデックスに反映する(ステージする)にはgit addを使います。

git add <path>

addという名前のコマンドですが、ワーキングツリー上のファイルの状態をインデックスに反映するコマンドなので、削除されたファイルをgit addするとインデックスからもファイルが削除されます。「ファイルが削除された状態」をインデックスにaddするのです。

$ rm hello.txt && git status
On branch master
Changes not staged for commit:  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    hello.txt

$ git add hello.txt && git status
On branch master
Changes to be committed:  (use "git reset HEAD <file>..." to unstage)

        deleted:    hello.txt

<path>にディレクトリを指定するとディレクトリ内のすべてのファイルがgit addされます。git add以外のコマンドもディレクトリを指定するとそのディレクトリ内のすべてのファイルを指定したことになることが多いです。現在のディレクトリ内のすべてのファイルの追加、削除、変更操をgit addするにはgit add .を実行します。

.の代わりに--allあるいは-Aを渡すとレポジトリ内のすべてのファイルがgit addされます (レポジトリのルートでgit add .したのと同等の結果)。Git1.x の名残git add --allをみかけることのほうが多いかもしれませんが、Git2.x 系列においてわざわざ--allを覚えておく必要はあまりないように思います。

git reset: ステージングをキャンセルする

git addで行ったインデックスへのステージングを取り消すにはgit resetを使います。--<path>がワーキングツリーに存在する場合は省略可能です。

git reset [--] <path>

先程、git addでインデックスから削除した hello.txt を復元してみましょう。このケースではhello.txtがローカルに存在しないので--は省略できません。

$ git reset -- hello.txt
Unstaged changes after reset:
D       hello.txt
$ git status
On branch master
Changes not staged for commit:  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    hello.txt

no changes added to commit (use "git add" and/or "git commit -a")

インデックスに登録されていたhello.txtの削除がキャンセルされているのがgit statusで確認できます。

git rese<path>にディレクトリを指定した場合にはディレクトリ内のすべてのファイルがgit resetされます。それと、後述するようにgit resetにはHEADを移動するという全く別の機能も割り当てられているので、やはり混乱しないように違いに気をつけてください。

git checkout: ファイルを復元する

ファイルを編集前の状態に戻すにはgit checkoutを使用します。まずインデックス上のファイルの状態を復元するには

git checkout [--] <path>

を実行します。対象のファイルが特にインデックス上で編集されていなければ、そのファイルのインデックス上の状態はHEADと同じなので直前のコミットからファイルが復元されます。

コミットされたファイルの状態を復元するときには、git checkoutをコミットとともに実行します。

git checkout <commit> [--] <path>

一番良く使うのは git checkout HEAD <path>でしょう。このコマンドコミットを実行するとファイルの状態がワーキングツリーに復元されるだけでなく、インデックスにも復元されます。つまり、インデックスされている変更ももとに戻されてしますので注意してください。インデックスは変更せずにローカルにだけファイルを復元する方法はなぜか用意されていません。ちなみにインデックスにだけファイルを復元したい場合、言い換えればステージングをなかったことにしたい場合には前述したようにgit resetを使用してください。

またgit checkoutコマンドはファイル名を省略することで、全く異なる処理(git checkout masterなど)に利用されるので混乱しないよう違いをしっかりと覚えてください。

git rm: ファイルを削除する

Git にはファイルをワーキングツリーから削除し、それをインデックスに反映するgit rmコマンドが用意されています。

git rm <path>

これはrm <path>でワーキングツリーからファイルを削除してそれをgit add <path>でインデックスに反映した場合と同じ結果が得られます(git rmは対象のファイルが編集されていない場合にしか利用できないなど細かい点は少し異なる)。

ワーキングツリーからはファイルを削除せずに、インデックスからのみ削除したい場合には--cachedフラグを渡します。

git rm --cached <path>

git mv: ファイルを移動する

Git にはファイルを移動し、その移動をインデックスに反映するgit mvコマンドが用意されています。

git mv <src> <dst>

他のバージョン管理システムのユーザーには信じられないと思いますが、Git はファイルの移動履歴をトラッキングしません(If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file.)。そのため、mv <src> <dst>でワーキングツリー上のファイルを移動してから、git add <src> <dst>で移動元、移動先のファイルの状態をインデックスに反映してもgit mvしたのと場合と全く同じ結果が得られます。

ちなみにファイルのコピーを行うgit cpというコマンドは存在しません。なんででしょうね。

git clean: トラックされていないファイルの削除

手元でいろいろな作業を繰り返してできてしまったワーキングツリー上の一時的なファイルはgit cleanで一括削除できます。もちろん.gitignoreで指定されているファイルは削除されません。

git clean -f

git cleanで削除したファイルは復元できないからなのか、git clean-fで削除を矯正するか-iでインタラクティブモードで動かさないと機能しません。でもgit checkout .などの他の不可逆的なコマンドは-fなしで動くのですが。

git commit: 変更をコミットとして記録する

上記のコマンドでインデックスが、コミットとして記録したい状態になったらgit commitで変更をコミットとして記録します。

git commit

エディターが起動しするのでコミットメッセージを書いてエディタを閉じるとコミットが作成されます。-m <message>を渡すとコミットメッセージをコマンドラインから指定することも可能です。

git commit --amend: 直前のコミットを修正する

git commitした直後に、間違いがあることに気がついてgit commitをやり直したいことがよくあります。そんなときにはgit commit --amendを使います。

git commit --amend

間違えのあったファイルを修正し、git addで修正をステージングし、git commit --amendを実行することで直前のコミットが破棄され、新しい修正済みのコミットが作成されます。

レポジトリ全体を元の状態に戻す

レポジトリ全体を編集前の元の状態(HEAD)に戻すにはレポジトリのルートディレクトリで以下のコマンドを実行します:

git checkout HEAD .
git clean -f

前述したようにまずgit checkout HEAD .でワーキングツリーとインデックスをHEADの状態に戻します。.を指定することでディレクトリ内のすべてのファイルがもとに戻されます。 git checkoutはトラックされていないファイルに関しては何もしないので、必要であればgit cleanで不要なファイルも削除します。

ちなみに最初のgit checkoutgit reset --hard HEADでも代用できます。

git log: 履歴の表示

Git でコミットの履歴を表示するにはgit logを使用します。

git diff: 差分の表示

git で差分を表示するにはgit diffを使います。ワーキングツリー(作業ツリー), インデックス, コミットなど差分を表示したい対象によってオプションを使い分けます。

ワーキングツリーの diff

git diff [<commit>]

ワーキングツリーをインデックスや他のコミットと比較するときには上記のフォーマットを使います。<commit>が省略されるとワーキングツリーとインデックスの比較になり、<commit>が指定されているとワーキングツリーと指定したコミットとの差分が表示されます。

ワーキングツリーをインデックスと比較する

現在のディレクトリの状態をインデックスと比較するには単にgit diffを実行します。

git diff

ワーキングツリーを HEAD(先頭のコミット)と比較する

現在のディレクトリの状態を先頭のコミットと比較するにはgit diff HEADを実行します。

git diff HEAD

インデックスの diff

git diff --cached [<commit>]

インデックス(ステージされた変更)を他のコミットと比較するときには上記のフォーマットを使います。<commit>が省略されるとインデックスとHEADの比較となります。--cached--stagedでも代用できます。

2つのコミットを比較する

git diff <commit> <commit>

gitで2つのコミットの差分を表示するにはgit diff <commit> <commit>のフォーマットを使います。1つ目のコミットが差分のベースとなります。また<commit> <commit>の部分は<commit>..<commit>とも書けます。この形式の場合は片側の<commit>を省略可能です。省略された<commit>HEADとして扱われます。

HEAD を一つ前のコミットと比較

git diff HEAD^ HEAD
git diff HEAD^..

ブランチとリモートトラッキングブランチの比較

リモートレポジトリ上のブランチをgit pullする前に差分を確認するには以下のようにします。

git remote origin # originの最新版を取得
git diff master origin/master # origin上のmasterとローカルのmasterの比較

git merge: コミットのマージ

Git を代表とする DVCS ではコミットは簡単に分岐していくので、それをマージする処理が非常に頻繁に行われます。Git で2つ以上のコミットをマージするにはgit mergeを使います。

git merge <commit>

git merge <commit>を実行すると現在のブランチに<commit>が指すコミットがマージされます。例えば下のようなコミット履歴があり、現在のブランチがmasterだとしましょう。

	  A---B---C topic
	 /
D---E---F---G master

ここでgit merge topicを実行すると、マージコミットHが作成されて最終的に以下のような履歴グラフが作成されます。

	  A---B---C topic
	 /         \
D---E---F---G---H master

git merge topicはブランチtopicが指しているコミットCを現在のブランチmasterにマージするコマンドなので、実行後もtopic変わらずCを指し続けます。

ちなみにgit merge<commit>を複数与え、3つ以上のコミットを1つのコミットにマージすることも可能です。3つ以上のコミットのマージはあまり使わない気がしますが。

	  A---B---C topic
	 /
D---E---F---G master
	 \
	  I---J---K dev

この状態で master で git merge topic devするとC, G, KがマージされたHができます。3つ以上のコミットのマージはoctopus(タコ)と呼ばれデフォルトでは衝突が起こらない場合のみ実行することができます。

	  A---B---C topic
	 /         \
D---E---F---G---H master
	 \         /
	  I---J---K topic

git merge: 衝突の解消

git mergeでマージしようとしている2つのコミットが共通するファイルの同じ部分を編集していると、衝突(conflict)が発生します。

$ git merge topic
Auto-merging members.txt
CONFLICT (content): Merge conflict in members.txtAutomatic merge failed; fix conflicts and then commit the result.

マージの状態を確認する

どのファイルで衝突が発生したのかはgit statusで確認します。Unmerged paths:の部分にマージに失敗しているファイルが列挙されます。

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   hello.txt

no changes added to commit (use "git add" and/or "git commit -a")

衝突を解決する

git mergeに表示された変更が衝突しているファイルを開くと、

<<<<<<< HEAD
現在のブランチでの変更
=======
マージする対象のブランチでの変更
>>>>>>>

のように衝突が表示されるので好きなエディタを使って、衝突部分を修正します。修正が終わったらファイルをgit addしてステージングします。

git add hello.txt

片側のコミットでファイルが削除されている場合には git merge, git status で以下のようなメッセージが表示されます

$ git merge bob
CONFLICT (modify/delete): members.txt deleted…
$ git status
Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)

        deleted by them: hello.txt

そして片側で編集されたファイルがローカルに存在する状態になるので、ファイルを残すのであればgit add, ファイルを削除するのであればgit rm (--cached)を実行してインデックスに対して明示的にファイルを追加するか削除するかします。

すべてのファイルの衝突が解決できたらgit commitを実行してマージコミットをコミットします。コミットメッセージは自動生成されるので-mなどは渡す必要はありません。

git commit

ちなみにUnmerged pathsがある状態でgit commitを実行しても Committing is not possible because you have unmerged files.という警告が表示され何も行われません。また最後のgit commitgit merge --continueでも代用できます。

マージを中止する

衝突の解消が難しく、一旦git merge処理を中止したい場合にはgit merge --abortを実行します。--abortするとgit merge実行前の状態に戻ります。

git merge --abort

マージ中なのかを確認する・どのコミットとマージ中なのかを再確認する

マージの解消は時間が手間のかかる処理なので後回しにしてしまって、後になって現在のレポジトリがマージ作業中だったのか分からなくなることがたまにあります。あるいはどのコミットとマージしている最中だったのかが分からなくなることもあります。

このような場合には、.git/MERGE_HEADファイルをチェックします。マージ中の場合にはファイルが存在し、ファイルの中にマージしようとしているコミットの hex が書かれています。

cat .git/MERGE_HEAD

ブランチの操作

Git ではブランチの操作は表示に関わるコマンドはgit branchに集約されています。

ブランチ一覧表示

git branch -vv

レポジトリ内に存在するブランチを一覧表示します。現在のブランチの先頭には*が表示されます。

-vvをつけることで、各ブランチがどのコミットを指しているかと、どのリモート上のブランチと紐づけられているか(トラッキングブランチ)も合わせて表示されています。-vvを取り除くとブランチ名のみが表示されます。単に今いるブランチの名前を確認したいだけなら、これで十分です。

新しいブランチを作る

現在のHEADを起点として新しいブランチを作成します。

git branch <branch>
最終更新: 6/7/2019