- 心掛け
- git の基礎知識
- コミット関連
- ブランチ関連
- .gitignore 関連
- 参考
- 自分が書いた git に関する記事
git を使う際に勉強したことを雑に更新していく.大雑把な理解なので間違っている情報が記載されていたらご指摘お願いします.更新は不定期です.
心掛け
git add *
は使わない.- 出来る限りターミナル,コマンドラインで
git add
,git commit
は行わない(やむを得ない場合は仕方ない).SourceTree などの GUI 環境で編集内容を確認しながらコミットを行う.(そうは言ってもコマンドは勉強しておく必要は当然ある) - 空白行などに注意して綺麗な diff を心掛ける.diff は必ず GUI 等で確認すること.
- フォーマッタによるフォーマットと機能追加を一つのコミットで行わない.diff が汚くなる.
- commit の粒度に気を配る(今の所「一つの機能ごと,かつ正常に動く」を目標にしている.一つの機能の粒度はチームによりけり...).
git の基礎知識
master と origin
- origin: リポジトリの場所(URL)の別名(default).origin 以外の名前も付けれるが慣例として origin が用いられる.
- master: ブランチの名前
git pull origin master
は,origin という名前のリポジトリの master ブランチから,git pull
しろと命令している.
コミット関連
コミット:git commit
「コミット」=「その時点におけるソースコードの編集履歴をメッセージ付きで残す」イメージ.
$ git commit -m 'commit message'
コミットの取り消し:git reset
- 直前のコミットを取消
- オプション
- (注意)
--hard
:コミットを取り消した上で,コミット時のソースコードの変更内容は消えてしまう(つまり一つ前のコミットまで全てのファイルの変更内容が戻る). --soft
:コミットを取り消すが,コミット時の変更内容はそのまま残る.コミットメッセージやコミットの内容を修正したい時はこちらを実行すると良い.
- (注意)
- オプション
# 変更内容が全て元に戻ってしまう注意が必要 $ git reset --hard HEAD^ # 変更内容は保存されたまま,'soft' にコミットを取り消す $ git reset --soft HEAD^
コミットの取消:
HEAD^
,HEAD~{n}
,@^
,commit hash- (git > v1.8.5,「
HEAD
」の alias として「@
」が実装された) - 1 つ前(直前)のコミット
HEAD^
=HEAD~{1}
=HEAD~
(これだけ特殊) =@^
- 2 つ前のコミット
HEAD^^
=HEAD~{2}
=@^^
- 3 つ前のコミット
HEAD^^^
=HEAD~{3}
=@^^^
- ...
- (git > v1.8.5,「
HEAD^
,HEAD~{n}
,@^
の代わりにコミットのハッシュ値を指定しても良い.
$ git reset --hard HEAD^^ $ git reset --soft HEAD~{2} $ git reset --soft @^^ $ git reset --soft [commit-hash]
コミットを打ち消し(コミットを取り消した履歴を残す):git revert
作業ブランチを,指定したコミット時点の状態まで戻し,コミットを行う.現時点までのコミットを消去するのではなく,逆向きのコミットを行うことで「コミットを打ち消した」という履歴を残す.
git revert [commit-hash]
直前のコミットの上書き
直前のコミットを上書きするには以下を実行.
$ git commit --amend
git commit --amend
の使いどころ- コミットメッセージを変更したいとき
git rebase
に失敗した時,コンフリクトを避けるためにコミットを上書きするとき
git cherry-pick:他ブランチの特定のコミットをカレントブランチに反映する
git cherry-pick
により,他ブランチの特定のコミットを指定し,そのコミットをカレントブランチに反映することができる.コミットはコミットハッシュ等で指定する(後述).
使い所
- リリース用のブランチにパッチ的な用途で使える
- 「あのブランチの内容,こっちに持ってきたくね?」
cherry-pick の挙動
git cherry-pick
を実行した時の挙動には注意が必要.
- コンフリクトがない場合
- 自動でコミットが実行される
- 指定したコミットのコミットメッセージのまま,カレントブランチにコミットが反映される
- コミットメッセージを直したかったら
git --amend
- 自動でコミットが実行される
- コンフリクトがある場合
- コミットは実行されない
- コンフリクトがあるファイルには,お馴染みの「>>>> HEAD」で編集内容が追加される.つまり,コンフリクトを修正しないとコミットできない(大体これ?).
他ブランチの特定の 1 つのコミットを反映する
- template
$ git cherry-pick [commit hash]
他ブランチの特定のコミットを範囲指定して反映する
- template
指定したブランチ branch-name
の最新のコミットからさかのぼり,number
番目までのコミットをカレントブランチに反映する.
$ git cherry-pick [branch-name]~[number]..[branch-name]
- ex)
develop
ブランチの最新のコミットからさかのぼり,5 番目までのコミットをカレントブランチに反映する.
# git cherry-pick [branch-name]~[number]..[branch-name] $ git cherry-pick develop~5..develop
ブランチ関連
既存のブランチの確認:git branch
- ローカルリポジトリのブランチの確認
$ git branch
- リモートリポジトリのブランチの確認
-r
オプションを付けるだけ.
$ git branch -r
リモートリポジトリのブランチの情報を取得する:git fetch
リモートリポジトリから,ブランチ(とタグ)の情報をローカルリポジトリに取得するためのコマンドである.git fetch
は,チーム開発などで他のメンバーがリモートリポジトリを更新した際に,その更新をローカルリポジトリに反映させる場合などに用いる.
git fetch
を実行した際,リモートリポジトリでの変更内容がローカルリポジトリのソースコードに勝手にマージされたり,作業中の内容を書き換えたりすることはない.従って,必要に応じて自分でマージをする必要がある.
つまり,もしリモートリポジトリの変更をローカルリポジトリに反映させたい場合,「fetch
-> merge
」という手順を必ず踏まなければならない(pull
はこれらを合わせたようなものだが,ここではややこしくなるため触れない).
例えば,下記はリモートリポジトリ origin
から,ブランチ master
の全てのコミット履歴と参照(=ブランチ・タグ)を取得するコマンドである.取得した履歴に関連するタグがあれば,同時に取得する.
全てのリモートリポジトリの情報を取得する
1 つのローカルリポジトリにつき,複数のリモートリポジトリを登録することができるが,この複数のリモートリポジトリの情報を一挙に取得することができる.
- template
$ git fetch --all
特定のリモートリポジトリの情報を取得する
- template
$ git fetch [remote-repository]
- ex) リモートリポジトリ
origin
の情報を取得する
単一のリモートリポジトリのみを扱う場合,origin
という名前が用いられることが多い(リモートリポジトリを clone
したときには,リモートリポジトリ名に origin
という名前が自動的に付けられる).
$ git fetch origin
特定のリモートリポジトリの特定のブランチの情報を取得する
- template
$ git fetch [remote-repository] [branch-name]
- ex) リモートリポジトリ
origin
のmaster
ブランチの情報を取得する
$ git fetch origin master
(最近 master
というブランチ名 main
になるというのが話題になってますね(2020/06/18))
ブランチの切り替え
基本
$ git checkout [branch-name]
ブランチの作成 & 切り替え
以下のコマンドで,一気にブランチの作成 -> 切り替えが行える.
$ git checkout -b [new-branch]
1-liner:リモートのブランチを pull & ブランチの作成 & 切り替え
下記のコマンドにより,新規ブランチの作成,リモートのブランチの pull,ブランチの切り替えを同時に行える.
$ git checkout -b [new-branch-name] origin/[remote-branch-name]
ブランチ名の変更
ローカルリポジトリのブランチ名の変更
ローカルリポジトリのブランチ名を変更する.ブランチ名のミス,例えば PR の issue 番号が間違っていたときなどに使える.
- template
$ git branch -m [古いブランチ名] [新しいブランチ名] $ git branch -m [新しいブランチ名] # 現在のブランチの名前を変更
現在の作業中のローカルのブランチ名を変更する場合は [古いブランチ名]
を省略できる.
- ex1) ローカルリポジトリの
issues/9
というブランチ名をissues/11
というブランチ名に変更する
# 例えば,develop ブランチで作業中 $ git branch -m issues/9 issues/11
issues/9
上で作業している場合,issues/9
を省略できる.
# issues/9 ブランチで作業中 $ git branch -m issues/11
- ex2
$ git branch # 現在のブランチの確認 develop * feature/add-filters $ git branch -m feature/add-filter # 単数形に変更 $ git branch develop * feature/add-filter # 変更されたことを確認
リモートのブランチ名の変更
ローカルでブランチ名を変更し、新しいブランチ名のブランチを新規ブランチとして push する。このタイミングでは、古いブランチ名と新しいブランチ名の 2 つのブランチがリモートリポジトリに存在することになる。
最後にリモートの古いブランチ名のブランチを削除する。リモートのブランチを削除する作業なので、変更を消してしまわないように慎重に。
# ローカルのブランチ名を変更 git branch -m issues/9-fix-error-handling issues/9-hotfix-error-handling-on-receiving-signal # 新しいブランチ名でリモートに新規ブランチとして push git push origin issues/9-hotfix-error-handling-on-receiving-signal # リモートの古いブランチ名のブランチを削除 git push origin :issues/9-fix-error-handling
ブランチの消去
ローカルブランチの消去
- template
git branch -D
を行う際は十分注意すること(自己責任で実行してください).
# soft(変更内容が merge されていない場合エラーが出る) $ git branch -d [branch-name] # hard(強制的に消去) $ git branch -D [branch-name]
- ex
$ git checkout master $ git branch -d [branch-name] # もしそのブランチがマージされていないとエラーが出る error: The branch '[branch-name]' is not fully merged. If you are sure you want to delete it, run 'git branch -D my-branch'. # -D でオプションで強制的に消去できる $ git branch -D [branch-name]
リモートリポジトリのブランチの消去
- template
# 短くて良さげ $ git push origin :[branch-name] # 明示的に的に delete $ git push --delete origin [branch-name]
- ex)
issues/9
というブランチを消去する
$ git push origin :issues/9 $ git push --delete origin issues/9
既存のブランチをコピーする
ローカルのブランチ -> ローカルのブランチへコピー
- template
$ git branch $ git checkout -b [コピー先の新しいブランチ] [コピー元のブランチ]
リモートのブランチ -> ローカルのブランチへコピーする
ローカルで開発するとき,リモートリポジトリの既存のブランチ上で作業したい場合がある.それを行う方法は以下 4 つ.一番楽なのは 3 つ目だが,仕組みを理解するためにも順を追って説明する(新規ブランチを作成する場合はここでは紹介しないが,これよりも簡単).
branch
+checkout
checkout -b
- (推奨)
checkout -t
branch + checkout
- template
git branch [branch-name] origin/[branch-name]
で,リモートリポジトリ origin/[branch-name]
(origin
はリモートリポジトリの名前)というブランチをローカルリポジトリの [branch-name]
というブランチにコピーする(ブランチの新規作成 & 内容のコピー),という処理を行っている.
$ git branch [branch-name] origin/[branch-name] $ git checkout [branch-name]
- ex) ローカル環境でリモートリポジトリの
issues/9
というブランチ上で作業をしたい
$ git branch issues/9 origin/issues/9 $ git checkout issues/9
checkout -b
- template
$ git checkout -b [branch-name] origin/[branch-name]
- ex) ローカル環境でリモートリポジトリの
issues/9
というブランチ上で作業をしたい
$ git checkout -b issues/9 origin/issues/9
(推奨)checkout -t
これが一番楽.
- template
ほとんどの場合,リモートリポジトリのブランチ名をそのままローカルリポジトリのブランチ名に使うため,このコマンドならそれが少ないタイプ量で実現できる.
git checkout -t origin/[branch-name]
fetch + checkout
# リモートブランチ一覧から指定の探す git branch -r # fetch git fetch origin [branch-name] # checkout git checkout [branch-name]
作業中 / 新規ブランチの push
既に作業中のブランチに対する push も,ローカルで新しく作成したブランチの push も同じコマンドで行える
$ git push origin [branch-name] $ git push origin [new-branch-name]
git stash:作業の一時保存
一時退避
git stash
は,現在のブランチでの作業を(コミットせずに)一時保存して他のブランチで作業できるようにするためのコマンド.git stash
を実行すると変更内容がスタックに保存される.
実際にやってみると分かるが,git commit
しないまま git checkout
でブランチを切り替えようとするとエラーが出てブランチを切り替えることができない.
git stash
(後で単語調べる用)現在進行中の作業(WIP)をスタッシュ(安全な隠し場所)に入れて、git checkout を実行できるようにする.
スタックのリスト
まず,積まれているスタックを git stash list
で確認する.
$ git stash list stash@{0}: WIP on branch1: ... stash@{1}: WIP on branch2: ... ... stash@{3}: WIP on master: ...
スタックから特定の退避内容を復元
特定のブランチをスタックに積まれているものから復元する.
git stash pop stash@{[num]}
スタックから特定の退避内容を消去
git stash drop stash@{[num]}
スタックを全消去
git stash clear
main ブランチの変更を作業ブランチに反映させる
- よくある状況
- 複数のブランチで作業してて、とある作業ブランチを main にマージしたときに、その変更を別の作業ブランチに反映させたいとき
merge
不必要なマージコミットが発生するのでできれば merge はしたくない。状況によるのでなんとも言えないが、個人で作業する場合は rebase の方が良い(基本的に作業ブランチは個人で作業することの方が多いはず。ただし、複数人で作業しているときに rebase をすると、作業ブランチのこれまでのコミット ID が全て更新されるので場合によっては force push が必要になる可能性がある)。
rebase
まず、main ブランチを最新の状態にする。
git switch main git pull
rebase
コマンドを使用して、作業ブランチで main ブランチの作業を適用する。
git rebase main
コンフリクトが発生した場合
Git が指示する通りにそれらを解決し、rebase を続ける。コンフリクトを解決した後、以下のコマンドで rebase を続けることができる。
git add .
git rebase --continue
コンフリクトが解決できなそうなとき、以下のコマンドで中止して、元の状態に戻すことができる。
git rebase --abort
.gitignore 関連
一度追跡したファイル,ディレクトリを追跡対象から外す
一度追跡してしまったファイル,ディレクトリは,.gitignore
に追加しても追跡対象から外すことはできない.もしこれらを追跡対象から外したければ,git rm --cached
コマンドで一度 git の管理下から外し,.gitignore
に追加すれば良い.(git rm
に --cached
オプションを付けないとファイル,ディレクトリごと消えてしまうため注意)
- ファイルを追跡対象から外す
teminal
git rm --cached [filename]
.gitignore
filename
- ディレクトリを追跡対象から外す
ディレクトリごと外したい場合は,ディレクトリ下全てのファイルを外す必要があるため,再帰オプション(recursive option)-r
を付ける必要がある.
terminal
git rm --chached -r [dirname]
.gitignore
dirname/
注意点は 2 点
git rm
に必ず--cached
オプションを付けて実行すること.付けないとファイル,ディレクトリごと消える.git rm
で管理下から外した直後には,外したファイル群は再度git add
で追跡対象に加えることができてしまう.そのため必ず,git rm
->.gitignore
を編集 ->git add
という順序を辿り,外したファイル群を再度追跡対象に加えてしまうことがないように気をつける.
参考
- Pro git
辞書的に使っている資料.まぐ(@maguroguma0712)さんに教えていただいた.
実はほぼ1年前にGit研修で先輩に教えていただいたものなんですが、そのできる先輩も「まずは通読は3章まででいい」とのことだったので、全部は読まなくていいと思います!実際、普段使わないものは忘れるし、「こんなことしたいな」が出てきたら調べる、なスタイルでもいいんじゃないかと思います(^o^)
— まぐ (@maguroguma0712) March 28, 2019