はじめまして、今回のエンジニアブログを担当する原です。
当エントリでは「gitコマンドを活用していきたい」という初心者の方のために、
私が実際に使っているコマンド群を、ユースケースとともにご紹介します。
私もまだまだGit初心者のうちに入るのですが、
これから紹介するユースケースを意識しコマンド郡が手に馴じんでくるにつれ、
Gitを使うのが楽しくなってきました。参考にしてみてください。
なぜ、gitコマンドを使う必要があるのか
ご紹介する前に、なぜgitコマンドを使う必要があるのか、考えてみましょう。
Gitを使うには、コマンドによって作業ツリーを操作するCUIツールと、
コミットログやDiffなどをビジュアルに表現可能なGUIツールの大きく2つの手段がありますが、
どちらも一長一短です。
Github for MacやSourceTreeといったGUIベースのツールは非常に使いやすいのですが、
Gitへの操作をメニューやコマンドなどで抽象化しているため、
Git自体への理解が進みにくいのではないでしょうか。
Subversionなどの集中型VCSの延長線上で、ただ何となく使っている人も少なくはないでしょう。
(私がそうでした)
一方、CUIツールのgitコマンドは、コミットログやDiffの表示は苦手としますが、
使いこなすことでGit自体への理解が進みます。
GUI環境の有無を問わずGitが利用できる他、
ターミナル上に表示されるメッセージやコマンドの「ググラビリティ」が高いのもメリットの一つです。
どちらが優れているというわけではなく、開発プロセス中の自分の作業状態や知りたい情報などによって、
適材適所で使うのが良いでしょう。
私は主に、作業ツリーやブランチ・リポジトリへの更新操作や、狭い範囲でのコミットログやDiffはCUIで、
複数ブランチの状態や大量のファイルのDiffの参照はGUIツールで行っています。
それでは、実際にどのようなユースケースでgitコマンドを使用しているかを、3点ご紹介します。
1. コードに触る、その前に
コマンド
$ git clone {remote_repository_url} $ git checkout -b {topic_branch_name}
結果
- {remote_repository_url}から作業ツリーをローカルにcloneする
- 新しいブランチを{topic_branch_name}でローカルに作成し、そのブランチに切り替える
解説
まず、コードに触れる前に、自分がどのようなタスクでコードを触るか考えます。
そして、その意図をトピックブランチの名前で表現します。
複数タスクを抱えている場合は、それぞれのタスクにどのような依存関係があるか分析して、
必要であればタスクを統合します。
チケット管理している場合は、チケット名でも良いでしょう。
git cloneした直後のmasterブランチに対してコードを修正すると
複数のタスクのコミットが混ざってしまい、
あとで特定タスクのみの修正を要求された場合に非常に面倒くさいことになります。
トピックブランチを作成している場合は、
そのトピックブランチ単位でのマージが容易であるため、
そのタスクのみの修正の反映にも複数のタスクでの修正の同時反映にも、柔軟に対応することができます。
2. リモートのmasterの修正をブランチにも反映したい
コマンド
$ git checkout master $ git fetch -v $ git merge FETCH_HEAD $ git checkout {topic_branch} $ git rebase master
結果
- masterブランチに切り替える
- masterブランチの最新の修正を取得(作業ツリーにはまだ反映されない)
- masterブランチの最新の修正をローカルのmasterブランチにマージ
- {topic_branch}に切り替える
- {topic_branch}に対する修正のコミットを、masterブランチの最新コミットに対するコミットに置換
解説
トピック・ブランチで作業している途中にリモートブランチに修正が入り、
その修正を取り込むときのコマンド郡です。
リモートの最新の修正をmasterにmergeしただけではトピックブランチにその修正は反映されません。
このような場合、rebaseするかmergeするかなのですが、
ここでは「トピックブランチを公開していない」という前提に立ち、rebaseを選びました。
もしトピックブランチを公開している場合は、rebaseではなくmergeを推奨します。
rebaseはブランチの修正分のコミットを全て作り直します。
gitのコミットは、そのコミットの一つ前のコミットを親コミットとして参照しており、
その親コミットが変更されると、別コミットとして扱われます。
よって、過去にそのブランチのコミットをリモートのブランチにpushしていた場合に、
rebase後のローカルのブランチをpushすることができなくなります。
リモートに存在しているコミットがpushされたコミットと全く関連がないためです。
強制的にpushすることも可能ですが、そのリモートブランチをcloneした人全員がその影響を受けるため、
可能な限り避けた方が良いでしょう。
ちなみにgit fetch+git mergeは、git pullでも良いのですが、
初心者のうちは原理を理解するというメリットを得るため、git fetch+git mergeに分けて使うことをオススメします。
3. push、mergeのその前に
コマンド
$ git commit -m "{commit_message}" : : $ git rebase -i master $ git push origin {topic_branch}
結果
- 普段の作業中に定期的にコミットしておく
- pushする前にmasterの最新ブランチに対話的rebaseして、不要なコミットをSquash
- コミットログを整えてリモートブランチにpush
解説
Gitにおけるコミットは、Subversionなどのコミットと異なり、非常にカジュアルです。
普段の開発では、一区切りしたらコミットしておきます。
あとでpushやmergeをする前に
rebase -iで複数のコミットを一つにまとめる&コミットログを整形することで、
コミットログ内のノイズを取り除きます。
開発者の精神安定とコミットログの可読性を両立するためにも、ぜひとも実践したいですね。
いかがだったでしょうか。まだまだ色んなユースケースが考えられると思いますが、
gitコマンド覚えたてでもこれぐらいのユースケースを理解していれば、
Gitを使った開発に一歩踏み出せると思います。
日常的にgitコマンドを使ってみて、新しいユースケースやgitコマンドのパターンを自ら作り上げていくと、
Gitが更に楽しくなりますよ。
是非、参考にしてみてください。
おまけ
日常的にgitコマンドを使っているとコマンドを打つのが面倒くさくなってくるので、
.gitconfigにコマンドのエイリアスを定義して楽をしましょう。
初心者の方でもすぐに使えそうなエイリアスをご提案します。
[alias] a = add cm = commmit cmm = commit -m co = checkout st = status ft = fetch br = branch mg = merge df = diff -C rb = rebase lg = log --graph --all --decorate --oneline
ここまでお読みいただき、誠にありがとうございました。