Gitの便利な使い方 13個+1
開発者にとってもっとも使われているツールはgitでしょう。Youtubeチャンネルのfireshipチャンネルに「13 Advanced (but useful) Git Techniques and Shortcuts」という動画でgitの便利なテクニックが紹介されています。知っておくと役立つことも多かったので、ここで紹介します。
- add と commit を同時に
- エイリアス
- コミットの修正
- 強制push
- コミットの取り消し(revert)
- リモートワーク(Codespaces)
- 作業中に一時退避(stash)
- ブランチ名の変更(branch)
- ログを見やすく(log)
- 問題箇所の特定(bisect)
- 自動squash
- フック
- 破壊
- (おまけ)一つ前のブランチに戻る
add と commit を同時に
addコマンドで変更内容をインデックスに追加してから、commitコマンドでコミットします。
$ git add . $ git commit -m "hi mom" [main d6b7949] hi mom 1 file changed, 1 insertion(+)
commitコマンドに-am
オプションをつければ、git add .
を自動的にやってくれます。
git commimt -am "that was easy!" [main 4bc37a8] that was easy! 1 file changed, 1 insertion(+)
エイリアス
毎回同じようなコマンドやオプションをうつことが多いですが、エイリアスをつけて短くタイプすることができるようになります。
例えば、上記のcommit -am
をac
というエイリアスにしてみます。
$ git config --global alias.ac "commit -am" $ $ git ac "noice!" [main 296cfb6] noice! 1 file changed, 1 insertion(+)
コミットの修正
コミットを間違ったので修正したい場合は、amend
オプションを使います。
コミットコメントだけを修正したい場合は、-m
オプションが使えます。
$ git commit --amend -m "nice!" [main f57c3ed] nice! 1 file changed, 1 insertion(+)
ファイルを追加・変更したけど、コミットコメントを変えない場合は、--no-edit
オプションをつけます。
$ git add . $ git commit --amend --no-edit [main 26783b2] nice! Date: Sun Sep 5 19:37:55 2021 -0700 2 file changed, 1 insertion(+) create mode 100644 foo.md
強制push
amend
オプション修正したコミットをリモートレポジトリにプッシュしようとすると失敗することがあります。
$ git push origin main To https://github.com/mizumotok/test-repo ! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/mizumotok/test-repo'
こんなときは--force
オプションをつけることでリモートの履歴を上書きできます。
$ git push origin main --force Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 12 threads Compressiong objects: 100% (2/2), done. Writing objects: 100% (4/4), 307 bytes | 307.00 KiB/s, done. Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/mizumotok/test-repo + d78d86a...6299342 main -> main (forced update)
ただし共同作業者がいる場合は、リモートと彼らのローカルで不整合になるので注意しましょう。
コミットの取り消し(revert)
前のコミットが不要な場合があります。その時はrevert
コマンドで新しいコミットを作って、1つ前のコミットに戻ることができます。
$ git log --oneline b4f4098 (HEAD -> main) update 6299342 (origin/main) initial commit
上記のケースでb4f4098
のコミットを取り消したいときは、コミットIDを指定します。
$ git revert b4f4098 $ git log --oneline 2218b92 (HEAD -> main) Revert "update" b4f4098 update 6299342 (origin/main) initial commit
コミット履歴を壊さないので、共同作業で混乱することがなくなります。
リモートワーク(Codespaces)
ローカルPCに触れない状況で、レポジトリで作業をしたいという場合があるでしょう。GitHubではレポジトリのページで「.(ドット)」をうつか、github.com
の.com
を.dev
と変えるだけで、ブラウザ上でVS Codeが使えるようになります。プルリクの対応もここでできるようになります。
https://github.com/mizumotok/zipcode
↓
https://github.dev/mizumotok/zipcode
このままではソースコードの編集だけで、開発サーバを動かしての確認はできません。GitHubではCodespacesというクラウド上の開発環境が用意されていて、VS Code(github.dev)のdevcontainerとして接続できるようになっています。 github.co.jp
現在はベータ版で無料ですが、GAになると以下の料金体系が予定されています。
Product | SKU | 単位 | 料金 |
---|---|---|---|
Codespaces Compute | 2 core | 1時間 | $0.18 |
4 core | 1時間 | $0.36 | |
8 core | 1時間 | $0.72 | |
16 core | 1時間 | $1.44 | |
32 core | 1時間 | $2.88 | |
Codespaces Storage | Storage | 1GB-month | $0.07 |
最低スペックで月160時間動かして、3,000円程度です。
About billing for Codespaces - GitHub Docs
作業中に一時退避(stash)
コミットをしていない作業中の状態を一時的に保存しておきたい場合があるでしょう。そのときにはstash
コマンドを使います。
$ git stash
Saved working directory and index state WIP on main: 6d010fd 1
stash
コマンドにpop
オプションをつけると保存したものを取り出すことができます。
$ git stash pop On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (f4a3b907badab9a516405a3b052cbbbceee42cd1)
名前をつけてstash
をすることもできます。
$ git stash save coolstuff Saved working directory and index state On main: coolstuff
stashされた一覧を見るにはlist
オプションをつけます。
$ git stash list stash@{0}: On main: coolstuff
インデックス番号を指定して取り出すことができます。
palau:test kiyoshi% git stash apply 0 On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a")
Codespacesを使ってリモートで作業している場合は、stashはクラウド上に保存されます。
ブランチ名の変更(branch)
gitのデフォルトブランチはmaster
が長年使われていましたが、その名前が一部の人にとって不快だといういう理由で、変更する方向になっています。
https://sfconservancy.org/news/2020/jun/23/gitbranchname/
ブランチ名を変えるにはbranch
コマンドに-M
オプションをつけます。
$ git branch -M mucho $ git status On branch mucho nothing to commit, working tree clean
ログを見やすく(log)
log
コマンドはコミット履歴を見るのに便利ですが、長いコミットIDやAuthorやDate等のいろいろな情報が一つのコミットに凝縮されて、履歴を眺めるのには見づらいです。
--graph
--oneline
--decorate
オプションをつけることで見やすくなります。
$ git log --graph --oneline --decorate * fa1a4b657c (HEAD -> main, origin/main, origin/HEAD) Let jsbundling-rails expand without requiring a change in Rails * 83808166e6 Add --css app generator option (#43177) * 061bf3156f Merge pull request #43148 from jbourassa/polymorphic-custom-name-fixes |\ | * 2ea5ff9e13 Use `polymorphic_class_for` over `constantize` |/ * e1f90a30a2 Merge pull request #43171 from yykamei/replace-location-with-request-in-process_action.action_controller |\ | * 92ac51bf66 Replace :location with :request in process_action.action_controller * | 7595c922a6 Use the combined jsbundling-rails gem instead of individual js bundler gems (#43172) * | 532ef0d13c Add back Lint/UselessAssignment |/ * 78e402077d Merge pull request #43170 from byroot/rubocop-explicit-block-argument |\ | * c91c266872 Enable `Style/ExplicitBlockArgument` cop |/ * 5fbc750840 Get rid of `mattr_accessor` in `ActiveSupport::Dependencies`
問題箇所の特定(bisect)
アプリケーションに不具合が入って、どのコミットで不具合が起き始めたのか見つけたいことがあります。そんなときはbisect
コマンドを使って二分探索法でコミットを探していくことができます。
$ git bisect start $ git bisect bad $ git bisec good 6d010fd Bisecting: 0 revisions left to test after this (roughly 1 step) [18e0abe6f25bcc99f53cad5e426cecc5f5ef18fd] 2
まずbisect start
でbisectを開始します。bisect bad
で現在のコッミットをbad
とマークします。bisect good <commit id>
で問題がなかったときのコミットをgood
とマークします。bisect
はbad
とgood
の中間のコミットを見つけてチェックアウトしてくれます。
このコミットを確認してやはり不具合が残っていた場合は、もう一度bisect bad
とすることで、また別のコミットを提案してチェックアウトしてくれます。
$ git bisect bad Bisecting: 0 revisions left to test after this (roughly 1 step) [cd9f0e0038c166467425ea55cff6063c8152a3f7] 1
これを繰り返すことで、問題が発生したコミットを効率よく探すことができます。
自動squash
mainブランチから派生したfeatureブランチで作業していて、コミットが多くなりすぎてコミットを一つにまとめたいときにrebase
を--interactive
オプションをつけることで対応できます。
(featureブランチで) $ git rebase main --interactive hint: Waiting for your editor to close the file...
rebase
コマンドを--interactive
オプションをつけて実行するとエディタが立ち上がります。
pick 62079a8 feature complete pick b95ba00 1 pick e9d38a4 2 pick 63bc7fd 3 # Rebase 9a8d40c..63bc7fd onto 63bc7fd (4 commits)
ここで最後の3つのコミットをpick
からsquash
に変えます。
pick 62079a8 feature complete squash b95ba00 1 squash e9d38a4 2 squash 63bc7fd 3 # Rebase 9a8d40c..63bc7fd onto 63bc7fd (4 commits)
こうして保存すると、featureブランチのコミットが一つになってmasterブランチのHEADにつきます。
(rebase / squash前) A - B - C - D <- master \ X - Y <- feature (rebase / squash後) A - B - C - D <- master \ Z <- feature
ブランチは同じで、現在の変更を過去のコミットに統合したいというケースがあります。commit
コマンドに--fixup
や--squash
オプションをつけて過去のコミットの修正であることを指定します。
$ git commit --fixup fb2f677 # 修正したいコミットIDを指定する
ここでrebase
コマンドに--autosquash
オプションをつけるとfixup
で作成されたコミットが自動的に元のコミットと統合されてrebaseされます。
git rebase -i --autosquash 62079a8 # 修正したいコミットIDの一つ前のコミット(このコミットから後ろがrebaseされる)
(最初) [A] - [B] - [C] - [D] (commit --fixup C) [A] - [B] - [C] - [D] - [fixup! C] (rebase -i --autosquash B) [A] - [B] - [C'] - [D'] ※ [C']は[C]と[fixup! C]が統合されている
フック
コミットの前後で何か処理(例えばシンタックスチェック)を入れたい場合があります。その時はフックが使えます。
.git/hooks
フォルダに特定のファイル名をつけたスクリプトを置くだけです。コミット前の処理はpre-commit
というファイル名にします。
$ ls .git/hooks
applypatch-msg.sample pre-push.sample
commit-msg.sample pre-rebase.sample
fsmonitor-watchman.sample pre-receive.sample
post-update.sample prepare-commit-msg.sample
pre-applypatch.sample push-to-checkout.sample
pre-commit.sample update.sample
pre-merge-commit.sample
huskyというツールを使うとフックが簡単に作れます。 github.com
例えばコミット前にテストを実行したい場合は、以下のようになります。
$ npm install husky -D $ npm set-script prepare "husky install" $ npm run prepare $ npx husky add .husky/pre-commit "npm test" $ git add .husky/pre-commit
これでコミットコマンド実行前にnpm test
が実行されます。
破壊
ローカル環境で作業をしていたけど、リモートレポジトリと同じ状態に戻したい場合(ローカルで作業中の変更は失われるので注意)
$ git fetch origin
$ git reset --hard origin/main
git管理されていないファイル(ビルド生成物やログ等)を消したい場合
$ git clean -df
gitをやめたい場合
$ rm -rf .git
(おまけ)一つ前のブランチに戻る
checkout
コマンドでブランチ名でなく-
を指定するだけです。
$ git checkout -