今年の4月インターンから晴れて株式会社ユニキャストに入社して、Gitを研修でやったので、勉強がてらまとめてみました。
以前こんな記事を書きましたがもうちょっと詳しく書いてます。
1. Gitの基本
Gitとは分散型のバージョン管理システムです。Gitを使うことで、ファイルの状態を好きな時に更新履歴として保存しておくことができます。そのため、一度編集したファイルを過去の状態に戻したり、編集箇所の差分を表示することができます。
1-1. バージョン管理システム
バージョン管理システムとは、ファイルに対して「いつ」「誰が」「何を変更したか」といった情報を記録することで、過去のある時点の状態を復元したり変更内容の差分を表示できるようにするシステムのことです。バージョン管理システムは大きく「集中型バージョン管理システム」と「分散型バージョン管理システム」に分けることが出来ます。
1-2. 集中型バージョン管理システムと分散型バージョン管理システム
集中型バージョン管理システム
集中型(クライアント・サーバ型)のバージョン管理システムでは1つのリポジトリを使用します。リポジトリとはファイルそのものや変更履歴などを保存しておく場所です。そのため、複数メンバで開発する場合には、1つのリポジトリを複数人で共有して使用します。ソフトウェア開発に参加するメンバーは、中央リポジトリ(プロジェクトメンバー間で共有するリポジトリ)からソースコードを持ってきて編集し、編集が終わったら中央リポジトリに直接反映します。
分散型バージョン管理システム(Git)
分散型バージョン管理システムではリポジトリを複数持つことが出来、開発の形態や規模に合わせてバージョン管理ができます。リポジトリを複数用意できるので「分散型」と呼ばれています。Gitで管理する場合、リモートリポジトリをサーバ上に置き、開発者それぞれがローカル環境にローカルリポジトリを持つという構成で使われています。この場合、普段はローカルリポジトリで作業を進めていき、ある程度作業をした時点でリモートリポジトリに反映するという流れとなります。そのためチームで開発をする場合、1つのリポジトリを使いまわす集中型よりも分散型バージョン管理システムは非常に効果的なツールとなります。
1-3. リポジトリ
上で取り上げたようにGitではローカルリポジトリとリモートリポジトリを使用します。
リポジトリ種類 | 概要 |
---|---|
ローカルリポジトリ | ローカル環境(自分のマシン)に配置し、自分の作業履歴をバージョン管理するリポジトリです。 |
リモートリポジトリ | 専用のサーバに配置し、複数人で共有するリポジトリです。 |
各々は、普段ローカルリポジトリでバージョン管理を行い、自分のローカルリポジトリで作業した内容を公開したい時は、リモートリポジトリにアップロードして公開します。また、リモートリポジトリを通してほかの人の作業内容を取得することもできます。
1-4. コミット
ファイルの追加や変更をリポジトリに追加するにはコミットと呼ばれる操作をする必要があります。この操作を行うと、前回のコミットから現在の状態の差分を記録したコミットと呼ばれるものが作成されます。
このコミットは、時系列順につながった状態でリポジトリに格納されています。
コミットをする際に必ずコミットメッセージが求められます。これは、変更内容の要約等を記入するものです。Gitでは標準的に以下のような形式でメッセージを書きます。
1行目 : コミットでの変更内容の要約
2行目 : 空行
3行目以降 : 変更した理由
各コミットにはユーザ名や日時、一意のIDが付与されます。
1-5. ワークツリーとインデックス
ワークツリーとは実際に自分のマシンで作業しているディレクトリのことを指し、インデックスとは、リポジトリとワークツリーの間に存在するものです。
Gitでは、コミットを実行した時にワークツリーから直接リポジトリ内に状態を記録するのでなく、その間に設けられているインデックスの設定された状態を記録するようになっています。
そのため、一度インデックス(ステージングエリア)にファイルを登録してからリポジトリに登録します。逆にリポジトリに上げたくないファイルはインデックスに登録しなければリポジトリにはアップロードされません。なので、必要なものだけを選んでバージョン管理を行うことができます。
※ Git初心者の人がよく分からなくなる1つがワークツリーやインデックス、ローカルリポジトリやリモートリポジトリの違いだと思いますので、しっかり理解してから進むことをおすすめします。
2. バージョン管理の流れ(基本)
2-1. リポジトリの作成
バージョン管理を行うには、まずリポジトリを作成する必要があります。git_trainingフォルダをGitの管理下にするには、そのディレクトリに移動してinit
コマンドを使用します。
cd git_training
git init
2-2. ローカルリポジトリにコミット
ファイルの追加や変更を行ったらadd
コマンドを使用してバージョン管理を行う、ファイル群をステージングエリア(インデックス)に登録します。
ワークツリー => ステージング
追加方法
git add <filename>
git add . #サブディレクトリを含めた全てのファイルを登録
git add -f . #.gitignoreに登録されているファイルを含めて登録
git add -u #リポジトリに登録されていて変更されたファイルのみ登録
git add -A #ワークツリーの変更と新しく作成されたファイルをリポジトリに登録
追跡を解除
git reset HEAD -- <file> # addしたファイルを解除する
git rm --cached <filename> # addしたファイルを解除する
確認方法
git add -n . # 実際には追加せずに追加されるファイルを調べる
git status # 変更されたファイルの一覧を調べる
git diff HEAD # 現在のワークツリーが最後のコミットからどのように編集されたかを調べる
2-3. リモートリポジトリにプッシュ
ローカルリポジトリにcommitをしたら次に、これまでの変更履歴をローカルリポジトリからリモートリポジトリにpushします。pushするとローカルリポジトリの内容がアップロードされリモートリポジトリがローカルリポジトリと同じ状態になります。
pushに入る前にリモートリポジトリに関する操作を少し解説します。
リモートリポジトリの操作
リモートリポジトリをクローンする
既に稼働しているプロジェクトに途中参戦するときは通常git clone
することからはじまります。urlにはとってきたいgithubやgitlabのプロジェクトのURLが入ります。プロジェクトをとってきたい場所に移動して以下のコマンドを使用してください。
git clone <url>
リモートリポジトリを追加する
ローカルリポジトリに対してリモートリポジトリを追加します。にはorigin
を入れてください。
git remote add <name> <url>
リモートリポジトリの内容を変更する
git remote set-url <name> <newurl> #<name>で登録済みのリモートリポジトリのURLを変更する
git remote rename <old> <new> #<olt>で登録済みのリモートリポジトリのURLを変更する
リモートリポジトリにpushする
git push <repository> <refspec>
=> 例:git push origin master
repositoryにはリモートリポジトリのURLや名前が入ります。refspecにはブランチ名等が指定できます。
git push --delete <repository> <branchname> #リモートリポジトリのブランチを削除する
2-4. リモートリポジトリからpullする
複数人で開発している時、他の人がpushしたリモートリポジトリの内容を自分のローカルリポジトリに取り込む場合にはpull
コマンドを使用します。pullを実行すると、リモートリポジトリから最新の変更履歴をダウンロードしてきて、自分のローカルリポジトリにその内容を取り込みます。
リモートリポジトリの変更内容を確認する
git fetch <repository> <refspec>
リモートリポジトリの変更内容を取り込む
git pull <repository> <refspec>
2-5. ブランチを切り替える
ブランチとは
ブランチは並行して行われる複数の機能追加やバージョン管理を支援するためのものであり、履歴の流れを分岐して記録していくものです。分岐したブランチは他のブランチの影響を受けないため、同リポジトリ内で複数の変更を同時に進めていくことができます。
プロジェクトから枝分かれさせることをよく「ブランチを切る」といいます。
また分岐したブランチは他のブランチを統合することができ、複数人でブランチを切って開発した内容を1つにまとめることが出来ます。
ブランチの切り替え
ブランチの操作
git branch <branchname> #ブランチを作成する
git branch -m <oldbranch> <newbranch> #ブランチ名を変更する
git branch -d <branchname> #ブランチを削除する
ブランチ一覧と自分の今いるブランチを確認する
git branch
ブランチを切り替える
git checkout <branchname>
通常の流れは以下の通りです。
git branch # 今いるブランチを確認
git branch <branchname> # ブランチを作成
git checkout <branchname> # ブランチを切る
ブランチの運用
ブランチは自由に作成出来ますが、複数人で開発する場合、Gitを効果的に運用するためにあらかじめ運用のルールを定めておく必要があります。ここでは統合ブランチとトピックブランチという二種類のブランチを使った運用方法について紹介します。
ブランチ | 概要 |
---|---|
統合ブランチ | リリース版が何時でも作成可能なようしておくためのブランチ、安定版を統合するブランチです。 |
トピックブランチ | 機能追加やバグ修正といったある課題に関する作業を行うために作成するブランチです。 |
そして詳しい運用方法はこちらを読みましょう!
2-6. ブランチをマージする
作業が終わったブランチは最終的には統合ブランチに統合する流れとなります。ブランチを統合するのはrebaseによる方法とmergeによる方法があります。
mergeによるマージ
今自分のいるブランチがbugfixブランチだったとし、bugfixブランチをmasterブランチにマージするとします。
masterブランチの履歴がbugfixブランチを分岐した時より進んでいた場合、両方の変更を取り込んだmergeコミットが作成されます。
masterブランチがC, bugfixブランチがYのときにmasterブランチからbugfixブランチマージしようと、両方の変更を取り込んだDコミットが作成されます。Dにはmasterとbugfix両方の変更が取り込まれています。
git checkout master
git merge bugfix
rebaseによるマージ
rebaseによってマージを行うとマージするブランチの後にマージされるブランチのコミット履歴が付け替えられブランチが一本化されます。
git rebase bugfix
2-7. 衝突を解決する
mergeした時やpullしたときに競合が発生する場合があります。その場合、競合のあった箇所には、Gitが差分を挿入しています。その場合、手動でワークツリー上でその部分を修正して改めてコミットします。
git add .
git commit
Gitを使いこなす
3-1. タグ
タグとは
Gitにおいてタグとはコミットを参照しやすくするために、わかりやすい名前を付けるものです。タグには軽量タグと注釈タグの2種類が存在します。一度付けたタグは移動ができないため、タグの移動が必要な場合は、そのタグを削除してから改めて作り直します。
タグ | 概要 |
---|---|
軽量タグ | 名前のみを付けられる。 |
注釈タグ | 名前、コメント、署名を付けられる。 |
タグの一般的な使い方は、リリースタグには注釈付きタグを使ってコメントや署名を追加します。 軽量タグはローカルで一時的に使用する使い捨てなどに使用します。
コマンド
軽量タグ
現在のHEADが指しているコミットに軽量タグをつける
git tag <tabname> #HEADに軽量タグをつける
注釈タグ
現在のHEADが指しているコミットに注釈タグをつける
git tag -a <tagname> #HEADに注釈タグをつける
上のコマンドを実行するとエディタが起動するのでそこにコメントを記述します。
エディタを起動せずにコメントを書くには以下のようにします。
git tag -am "コメントです" <tagname> #HEADに注釈タグをつける
タグを削除
git tag -d <tagname> #タグを削除する。
タグを調べる
git tag #タグ一覧を調べる
git log --decorate #タグ情報を含めて履歴を調べる
git show <tagname> #タグのついた情報を調べる
3-2. 過去のバージョンの戻る
Gitの大きなメリットの1つが過去のバージョンに戻って作業することができることです。この機能のお陰で私達開発者は何も恐れることなくリファクタリングできたり、機能の書き換えをすることができます。
過去のバージョンを戻るには reset
コマンドを使用します。
git reset --hard <コミットID>
git reset --hard HEAD #1つ前のコミットをかき消す
git reset --hard HEAD^ #2つ前のコミットをかき消す
このようにすることで以前のコミットに戻ることができます。
またGitでは前回取り消された内容がORIG_HEADというものに1つだけ格納されています。間違えてresetしたなどの場合は、ORIG_HEADにresetするとreset前の状態に戻すことができます。
git reset --hard ORIG_HEAD #前の状態に戻す
resetコマンド
resetコマンドは便利ですがしっかりと使い方を覚えて使わないといけなそうなので、ここで一度resetコマンドについて詳しく見ていきます。
まずresetコマンドは結局何をしているのかですが、reset
はHEADの位置を変更するコマンドであり、オプションによってはステージングやワークツリーも変更することができます。HEADの位置を変更できるということはreset
を使うとコミットを取り消すことができるということです。
reset
にはいくつかオプションがあり、それによって影響範囲を指定することができます。
オプション | 概要 |
---|---|
--hard | コミットを取り消した上でステージング、ワークツリーの内容も書き換える。 |
--mixed | コミットを取り消した上でステージングの内容も書き換える。 |
--soft | ワークディレクトリの内容はそのままでコミットだけを取り消す。 |
※HEAD: 今いるブランチの最新のコミット
3-3. 作業の一時退避
作業途中で別の修正や機能追加をする必要がでてきて、別のブランチに切り替えて作業をする必要があるとき、現在の変更を一時的に退避しておくことのできる機能がGitには備わっています。それを実現するのが stash
コマンドです。
早速使い方です。
まずは、まだcommitしていない状態の変更ファイル(addしてる or add していない)が存在する状況で、次のコマンドを実行すると変更ファイルを退避することができます。
git stash save #変更を退避する
変更ファイルが退避できたかどうかは git status
などで確認できます。
stashで退避できるのは1つとは限らず、複数退避できます。
退避した作業の一覧を確認
git stash list #退避作業一覧を調べる
git stash list -p #変更内容も含めて調べる
退避した履歴を取り出す
git stash apply stash@{0} #退避履歴を取り出す
stash apply
で変更を復活した場合は、stashリストのなかに復活済みの変更が残されているこれを削除する
git stash drop stash@{0} #退避作業を削除する
上記の取り出しと削除を一気に行う
git stash pop stash@{0} #退避作業を取り出し、削除する
退避した作業をすべて削除する
git stash clear #退避作業をすべて削除する
使用する流れとしては、今いるブランチで作業を一時退避(stash save)してbranchを切り替えます(checkout)。そこで作業をして作業が終わったらコミットして(commit)、また最初のブランチに戻ってきて(checkout)退避していた作業を戻します。(stash pop)
3-4. コミットを書き換える
直前のコミットを修正する
1つ前のコミットを修正するには、commitに--amend
オプションを追加します。
git commit --amend #1つ前のコミットを修正する
そうすると、直前のコミットのコミットメッセージがエディタで表示されます。「addとcommitの説明を追加」に変更して保存・終了してください。
過去のコミットを打ち消す
revert
コマンドを使うと過去のコミットを打ち消すことができます。revertは正確には、commit を無かったことにするのではなく、対象の commit の変更を相殺するような差分commitを自動で生成するというものです。resetはコミット自体なかったことにするのに対してrevertはなかったことにはならずに相殺するコミットを作成します。
git revert HEAD #1つ前のコミットを打ち消す
過去のコミットをなかったことにする
これは先ほど書いたresetを使用しておこないます。
コミットを抜き取る
cherry-pick
コマンドを使うと他のブランチのある特定のコミットのみを抜き取って、取り込むことができます。
git cherry-pick <commit ID> #コミットを取り込む
コミットをまとめる
複数のコミットを1つにまとめるには rebase -i
を使用します。
git rebase -i HEAD^ #HEADからHEAD^までのコミットをまとめる
ブランチ上のコミットを一つにまとめてマージする
git checkout develop
git merge --squash issue1 #ブランチのコミットを1つにまとめてマージする
4. git-flow
git-flowはGitの運用ガイドラインの1つです。
A successful Git branching modelといったモデルを採用することにより、Gitによるバージョン管理の見通しがよくなります。
弊社では、これをベースとして、git運用方針が定められています。http://www.slideshare.net/UnicastInc/git-v09
4-1. 基本ブランチ
masterブランチ
masterブランチは常に安定稼働するリリース可能なソフトウェアある必要があります。一定の機能がdevelopブランチにマージされたときに、developブランチの内容をmasterブランチにマージします。masterブランチのコミットにはタグ付けをしてバージョンを表します。
developブランチ
開発中主にメインとなるのがdevelopブランチです。各トピックブランチの起点となり、マージ先になります。開発者はdevelopブランチを起点にしてトピックブランチを作成し、開発が完了したらdevelopブランチにマージします。
4-2. サポートブランチ
featureブランチ
実際に機能を開発するブランチで、developブランチより先に作成されます。機能の開発が完了したらdevelopブランチにマージし、featureブランチは削除します。
マージのときfast-forwardマージを行わないことが必要です。これにより、developブランチには実装が完了したトピックブランチのコミットのみが作成されることになり見通しがよくなります。
git merge --no-ff function1
releaseブランチ
releaseブランチは、新しくリリースするための準備をするブランチです。developブランチより作成し、releaseブランチで作成した内容はdevelop, masterブランチにマージします。
hotfixブランチ
hotfixブランチは、リリース後の不足の事態や、重度のバグ対策に用いられるブランチです。masterブランチより作成し、hotfixブランチで対応した内容はdevelp, masterブランチにマージします。
.gitignore
.gitignore とは名前からも分かるように git で無視するファイルを指定するファイルです。
.gitignoreで設定できるパターン
パターン | 概要 |
---|---|
*~ | ファイル名の最後に ~ がある全てのファイル 例) index.html~ 等 |
*.[ao] | 拡張子が a 又は o のファイル 例) hello.a foo.o |
t/ | t ディレクトリは全て無視されます |
v | ファイル名が v の場合無視されるが v がディレクトリ名の場合は無視されません |
!*.t | 拡張子 t を持つファイルは無視されません |
5-1. WordPress
*.log
.htaccess
sitemap.xml
sitemap.xml.gz
wp-config.php
wp-content/advanced-cache.php
wp-content/backup-db/
wp-content/backups/
wp-content/blogs.dir/
wp-content/cache/
wp-content/upgrade/
wp-content/uploads/
wp-content/wp-cache-config.php
5-2. Ruby on Rails
*.rbc
capybara-*.html
.rspec
/log
/tmp
/db/*.sqlite3
/db/*.sqlite3-journal
/public/system
/coverage/
/spec/tmp
**.orig
rerun.txt
pickle-email-*.html
# TODO Comment out these rules if you are OK with secrets being uploaded to the repo
config/initializers/secret_token.rb
config/secrets.yml
## Environment normalisation:
/.bundle
/vendor/bundle
# these should all be checked in to normalise the environment:
# Gemfile.lock, .ruby-version, .ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
# if using bower-rails ignore default bower_components path bower.json files
/vendor/assets/bower_components
*.bowerrc
bower.json
# Ignore pow environment settings
.powenv
Git用語集
名前 | 概要 |
---|---|
HEAD | 現在チェックアウトしているブランチの最新コミットを指定する代名詞 |
HEAD^ | 1つ前のコミット |
HEAD~{n} | n個前のコミット |
FETCH_HEAD | 最後に取得したリモートブランチの最新コミットを指定する代名詞 |
ORIG_HEAD | 前のHEADの値を指定する代名詞 |
MERGE_HEAD | マージ中に生成され,ブランチにマージするコミットが記録されている代名詞 |
Gitコマンド集
init
リポジトリを作成する
git init
git init --bare #共有リポジトリの作成
add
ワークツリーからインデックスに追加する
git add <filename>
git add . #サブディレクトリを含めた全てのファイルを登録
git add -f . #.gitignoreに登録されているファイルを含めて登録
git add -u #リポジトリに登録されていて変更されたファイルのみ登録
git add -A #ワークツリーの変更と新しく作成されたファイルをリポジトリに登録
commit
git commit #コミットする
git commit --amend #1つ前のコミットを修正する
reset
git reset HEAD -- <file> # addしたファイルを解除する
git reset --hard HEAD #1つ前のコミットをかき消す(ワークツリーとステージングも)
git reset --mixed HEAD #1つ前のコミットをかき消す(ステージングも)
git reset --soft HEAD #1つ前のコミットをかき消す
rm
git rm --cached <filename> # addしたファイルを解除する
status
git status # 変更されたファイルの一覧を確認する
diff
git diff #変更されたファイルの一覧を確認する
# オプションなしの場合ワークツリーとステージングのdiffをとる
# HEAD やコミットを指定すると、ワークツリーと指定した HEAD との差分を表示する
log
コミットログを確認する
git log #コミット履歴を確認する
git log --oneline #コンパクトに確認する
git log -p #diffも見る
git log --stat #どのファイルがどれくらい変わったかを確認する
git log --decorate #タグ情報を含めて履歴を調べる
clean
追跡対象でないファイルを削除する
git clean -n #リポジトリで管理されていないファイルを調べる
git clean -n *.txt #拡張子が.txtのものを追跡から外す
remote
git remote # リモートリポジトリの一覧を表示する
git remote add <name> <url> # リモートリポジトリを追加する
git remote set-url <name> <newurl> #<name>で登録済みのリモートリポジトリのURLを変更する
git remote rename <old> <new> #<olt>で登録済みのリモートリポジトリのURLを変更する
push
git push <repository> <refspec> #リモートリポジトリのブランチにpushする
git push --delete <repository> <refspec> #リモートリポジトリのブランチを削除する
fetch
git fetch <repository> <refspec> # リモートリポジトリに変更内容を確認する
pull
git pull <repository> <refspec> # リモートリポジトリの変更内容を取り込む
branch
git branch <branchname> #ブランチを作成する
git branch -m <oldbranch> <newbranch> #ブランチ名を変更する
git branch -d <branchname> #ブランチを削除する
git branch # ブランチ一覧を確認する
checkout
git checkout <branchname> #ブランチを切り替える
git checkout -b <branchname> #ブランチを作成して切り替える
git checkout <commit> <file> # <file> が、指定した <commit> に含まれそのファイルの完全なコピーとなり、さらにそれをステージングエリアに追加
git checkout <commit> #指定したコミットと同一の状態に更新する
tag
git tag <tabname> #HEADに軽量タグをつける
git tag -a <tagname> #HEADに注釈タグをつける
git tag -d <tagname> #タグを削除する。
git tag #タグ一覧を調べる
stash
git stash save #変更を退避する
git stash list #退避作業一覧を調べる
git stash list -p #変更内容も含めて調べる
git stash apply stash@{0} #退避履歴を取り出す
git stash drop stash@{0} #退避作業を削除する
git stash pop stash@{0} #退避作業を取り出し、削除する
git stash clear #退避作業をすべて削除する
revert
git revert HEAD #1つ前のコミットを打ち消すコミットを自動生成する
cherry-pick
git cherry-pick <commit ID> #コミットを取り込む
merge
git merge <brachname> #ブランチをマージする
git merge --squash issue1 #ブランチのコミットを1つにまとめてマージする
素敵なGit Lifeを!