Instantly share code, notes, and snippets.

@troter /gtuggirls.rst Secret
Last active Dec 27, 2015

Embed
What would you like to do?
GTUG Girls原稿

GTUG Girls Meetup #14 Gitを使ってみよう

イベント概要

主催:GTUG Girls
日程:2013/11/05 19:00-21:45
参加人数:30名
講師:@troter
チューター:@kana1 @sinsoku_listy
イベントURL:https://groups.google.com/forum/#!topic/gtug-girls/KLNG3ECWfQA

Agenda

  • Gitの紹介
  • ハンズオンの狙い
  • 初期設定 (10分)
  • リポジトリを探索してみよう (20分)
  • 基本の使い方 (30分)
  • ブランチとマージ (30分)
  • リモートリポジトリ (20分)
  • より使いこなすために

Gitとその周辺の紹介

  • 2005年 Linuxのソースコード管理のために開発が開始される
  • 2005年末 1.0 リリース
  • 2008年 GitHubローンチ
  • 2010年 GitHubがPull-Requestをサポート
  • 2011年 Bitbucketがgitをサポート
  • 2012年 1.8.0リリース

開発コンセプト

Pro Gitの 1.2 使い始める - Git略史 より抜粋

  • スピード
  • シンプルな設計
  • ノンリニア開発(数千の並列ブランチ)への強力なサポート
  • 完全な分散
  • Linux カーネルのような大規模プロジェクトを(スピードとデータサイズで)効率的に取り扱い可能

特徴

  • 分散バージョン管理システム
  • ほとんどの操作がローカルで行える
  • 作業ディレクトリ、インデックス(ステージングエリアのようなもの)、リポジトリの3つの領域がある
  • 柔軟なブランチ
  • コマンドライン体系は過去のVCSと若干異なる

何が嬉しいか

  • ローカルで作業できる
  • 簡単にブランチがつくれる(自分用のサンドボックス環境が作れる)
  • マージ簡単
  • 過去のVCSと比べ高速に動作する
  • GitHubつかえる

独習おすすめサイト

GitのWebサイトPro Git の日本語訳 があります。Gitの使い方をわかりやすく説明しているのでとてもよいです。

その他 はてなブックマークのgitタグのついたエントリ や、Qiitaのgitタグのついた投稿 などを見ると、いっぱいtipsが見つかります。書籍と比べると玉石混交なのは注意。

GUIのGitクラアントはここでは扱いませんが、Windows/Macの両方で使える SourceTree がおすすめです。

ハンズオンの狙い

  • いろいろなgitのコマンドを実行してもらう
  • gitに慣れる。感覚をつかむ
  • gitのコマンドの出力内容を読み取れるようになってもらう
  • 時間も短いのでコピペ推奨

Gitの初期設定

さて、ここからハンズオン開始です。もちろんgitはインストールしていますよね?

$ git version
git version 1.8.4.msysgit.0

基本的なオプションの設定

git config でgitのオプションの確認と設定が行えます。

$ git config --global user.name                # 確認
$ git config --global user.name 'Takumi IINO'  # 設定

次のコマンドを実行して、基本的なオプションの設定をしましょう。

$ # (1) ユーザ情報
$ git config --global user.name 'ユーザー名'
$ git config --global user.email 'メールアドレス'

$ # (2) 便利なオプション
$ # 色を付けたり、改行コードの変換をやめたりします。便利なエイリアスも設定します。
$ git config --global color.ui auto
$ git config --global core.autocrlf false
$ git config --global core.quotepath false
$ git config --global alias.lg "log --graph --decorate --oneline"

$ # (3) エディタ
$ # viやemacsなど好きなエディタを指定しましょう。
$ git config --global core.editor vi

設定した内容は --list オプションで確認できます。

$ git config --list  # 明示的に設定した項目のみ表示

ヘルプ

git <subcommand> -h で簡易的なヘルプ、 git <subcommand> --help もしくは git help <subcommand> で詳細なヘルプが表示できます。

$ git help
$ git help -h        # (1) help コマンドの簡易的なヘルプを表示
$ git help --help    # (2) help コマンドの詳細なヘルプを表示
$ git help help      # (3) (2) と同じ

svn helphg help など他のVCSと同じです。何かわからないことがあったらヘルプを参照してみましょう。 Webから参照できるリファレンス(英語) もあります。

リポジトリを探索してみよう

gitを使って履歴を作っていく前に、いくつか用語の説明をしたいと思います。 履歴が無いと説明しにくい用語もあるので、既にあるリポジトリを探索しながら説明します。

注意:例で利用するリポジトリは git-flow を利用しているのでちょっと特殊なリポジトリです。

リポジトリのクローン

まずはリポジトリを用意します。調度良いリポジトリがあるので git clone を使って手元にクローンしましょう。

$ git clone https://github.com/ymotongpoo/goltsv
$ cd goltsv

履歴の閲覧

クローンしたリポジトリの中身を git log を使ってのぞいてみましょう。

$ git log --graph --decorate --oneline --all   # (1) 履歴をコミットグラフで見る
$ git lg --all                                 # (2) alias版
* 84f1da8 (HEAD, origin/develop, origin/HEAD, develop) added contributor
*   cd82559 Merge pull request #2 from koyachi/fix_flush
|\
| * ddf5c14 add Flush method.
|/
* 9f83d55 added drone.io status badge
*   c17009f Merge branch 'release/0.1.0' into develop
|\
| | *   3697917 (origin/master) Merge branch 'release/0.1.0'
| | |\
| | |/
| |/|
| * | 63d1306 modified document and added AUTHORS and LICENSE
|/ /
* | faf41b7 fixed format
* | 676ac1e added writer and writer_test
|/
* a92c9b4 adding writer.go
*   0ddb830 Merge pull request #1 from mattn/fix
|\
| * 76d2645 add test.
| * 1fabf8a move reader.go, so package name is better to be "github.comymotongpoo/goltsv":
| * cec6e3f use bufio instead of csv. csv can't treat rows that growing up.
| * ab77c40 remove debug message
| * f63772f remove debug message
| * 6cfa47c go fmt
|/
* ac06f8e first commit
* 5f01c95 Initial commit

--graph オプションをつけるとグラフで履歴が、 --all オプションで全ての履歴が表示できます。GUIのGitクライアントで表示できるグラフと同じものが表示できるので、とても便利です。

では、このリポジトリを例に用語の説明をしていきます。

HEAD

現在の作業ディレクトリ(ファイルの状態)のコミットを示す目印が HEAD です。 まずは、「今いる場所 = HEAD 」と覚えておきましょう。

$ git lg | head -4
* 84f1da8 (HEAD, origin/develop, origin/HEAD, develop) added contributor
*   cd82559 Merge pull request #2 from koyachi/fix_flush
|\
| * ddf5c14 add Flush method.

git log は通常は HEAD から辿れる履歴を表示します。

$ git log -p              # HEADから辿れるコミットログ + 変更内容が見れる

git show を利用すると特定のコミットの変更内容を表示できます。

$ git show HEAD           # (1) HEADの内容だけ見る
commit 84f1da8262529ea67ea94f7f77b36caf7de767b9   # (2) コミットID。番号は無いよ!
Author: ymotongpoo <ymotongpoo@gmail.com>
Date:   Sat Feb 16 09:53:12 2013 +0900

    added contributor

diff --git a/AUTHORS b/AUTHORS                    # (3) 変更内容
index 3cf1698..5096924 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1,3 @@
 Yoshifumi Yamaguchi (ymotongpoo)
-Yasuhiro Matsumoto (mattn)
\ No newline at end of file
+Yasuhiro Matsumoto (mattn)
+@koyachi

HEAD~ のようにチルダをつけると、つけた分だけ過去のコミットを指します。

$ git show HEAD~          # (1) HEADの1個前の内容をみる
$ git show HEAD~~         # (2) HEADの2個前の内容をみる

HEAD を移動させたいときは(履歴を取り出したいときは) git checkout [<commit>|<branchname>] を利用します。 とりあえず無理やり移動してみましょう。

$ git checkout origin/master     # HEADを移動させる (gitに怒られるけどね、、)

git lg --all でグラフを確認すると HEAD が移動していることがわかります。

$ git lg --all             # HEADが移動してるのを確認(ファイルの内容も変わってる)

HEAD が移動していることが確認できたら、もとに戻します。

$ git checkout develop     # HEADの場所に元に戻す

ブランチ

git lg --all で表示された developorigin/master などがブランチです。 ブランチの操作(表示したり、作ったり、消したり)には git branch を使います。

$ git branch
* develop                  # *が付いているのは今選択されているブランチ

ブランチはコミットへのポインタです。コミットの別名、リンクみたいなものと認識してください。 ブランチは履歴とは別に管理されていて、簡単に作ったり削除したりすることが出来ます。

$ git branch my-branch     # (1) HEADのコミットを指す my-branch ブランチを作る
$ git checkout my-branch   # (2) ブランチをチェックアウトすると今のブランチが変わる
$ git branch               # (3) 今のブランチは my-branch
  develop
* my-branch
$ git branch -d my-branch  # (4) ブランチを消す。(でも現在選択されているので消せない!)

--all をつけるとリモートリポジトリのブランチも表示出来ます。

$ git branch --all
  develop
* my-branch
  remotes/origin/HEAD -> origin/develop # (1) クローン元のリポジトリのブランチたち
  remotes/origin/develop
  remotes/origin/master
$ git lg --all                          # (2) remotesは省略されてる

remotes/origin/* となっているのはクローン元のリポジトリ(ここではGitHubのリポジトリ)のブランチの情報です。クローン元のリポジトリ(のURL)は自動的に origin という名前になります。 ちなみに、 git lg --all の出力ではremotesは省略されます。

演習

develop ブランチに移動してから my-branch を削除してください。

ヒント: git checkoutgit branch -d を使います。

master ブランチ

gitのブランチといえば master です。 master ブランチはgitのリポジトリを作った時にデフォルトで作成されるブランチです。ただ、例で利用しているリポジトリには master ブランチが無いです。

$ git branch --all                         # (1) masterブランチは無い。
* develop
  remotes/origin/HEAD -> origin/develop
  remotes/origin/develop
  remotes/origin/master                    # (2) でも、originにはある。

origin (クローン元リポジトリ)には master ブランチがあるので( remotes/origin/master のことです)、このブランチを基点に master ブランチを作ります。

一般に origin のブランチ(リモートリポジトリのブランチ)をローカルのブランチとして取り出すときは git checkout -b <local-branchname> <remote-branchname> を使います。

$ git checkout -b master origin/master     # (1) masterを作る
Branch master set up to track remote branch master from origin.
Switched to a new branch 'master'
$ git branch                               # (2) masterに移動しているか確認
  develop
* master

masterを作ったらHEADの位置やブランチの状態を確認してみてください。

$ git lg --all                             # 全体を確認してみよう

git checkout -b <new-branch> <branch> の補足

git checkout -b <new-branch> <branch><branch> 基点に <new-branch> を作成し、作成した <new-branch> に移動するコマンドです。このコマンドは基点として指定したブランチの種類によって若干動作が異なります。

  • 基点のブランチにリモートのブランチを指定した場合

git checkout -b <new-local-branchname> <remote-branchname> は次のコマンドと大体等価です。

$ git branch --track <new-local-branchname> <remote-branchname>
$ git checkout <new-local-branchname>
  • 基点のブランチにローカルのブランチを指定した場合

git checkout -b <new-local-branchname> <local-branchname> は次のコマンドと等価です。

$ git branch <new-local-branchname> <local-branchname> # --trackは無いよ
$ git checkout <new-local-branchname>

詳しくは git help で調べてください。

演習

develop ブランチを基点に hogehoge ブランチを作り、 hogehoge ブランチに移動してください。

ヒント: git checkout -b <new-local-branchname> <local-branchname> を使うと一つのコマンドで出来ます。

基本の使い方

まずはGitで履歴をつくる基本的な使い方を学んで行こうと思います。ここでは次のことを行います。

  • リポジトリの作成
  • ファイルを作成してコミット
  • ファイルを変更してコミット
  • 変更のやり直し方

リポジトリの作成

まずは git init <directory> でリポジトリを作成します。

$ git init gtug-girls-14
$ cd gtug-girls-14

ファイルを作成してコミット

まずはファイルを作成します。

$ echo "# GTUG Girls # 14 Gitを使ってみよう" > README.md

ファイルを作成したら git status でリポジトリの状態を確認してみます。

$ git status             # リポジトリの状態を確認
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       README.md
nothing added to commit but untracked files present (use "git add" to track)

git status はリポジトリの状態を見る以外に、次にどのコマンドを実行すればよいかアドバイスを表示てくれます。 アドバイスにしたがって、 git add を使ってファイルを管理対象に追加しましょう。

$ git add README.md     # コミット対象(インデックス)に追加する
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   README.md
#

git add を実行すると、ファイル(変更内容)がインデックスという場所に追加されます。インデックスはステージングエリアのようなもので、次のコミット対象となる変更内容を保存しておく場所です。コミットする場合は、まず変更内容をインデックスに入れて、その後コミットします。 git status の出力にあるように、ファイルの追加をインデックスから取り除く場合は git rm --cached <file> を使います。

では git commit を使ってインデックスの内容をコミットしましょう。

$ git commit -m "add README.md"
[master (root-commit) 528a519] add README.md
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

コミットできました!

ファイルを変更してコミット

先ほどコミットしたファイルを変更してみましょう。

$ echo "gitの使い方を勉強します" >> README.md
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   README.md
#
no changes added to commit (use "git add" and/or "git commit -a")

git status の出力内容はファイルを作成した時と異なります。変更をコミットする場合は git add <file> を、変更した内容を破棄する場合は git checkout -- <file> を利用します。

変更した内容を確認する場合は git diff を利用します。 git add する前にちょっと確認してみます。

$ git diff
diff --git a/README.md b/README.md
index ece6ee1..389a8ec 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # GTUG Girls # 14 Gitを使ってみよう
+gitの使い方を勉強します

では git add します。

$ git add README.md
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   README.md
#

git status の内容のとおりインデックスから変更を取り消す場合は git reset HEAD <file> を利用します。 git rm --cached <file> を実行すると次のように意図しない状態になるので気をつけてください。

$ git rm --cached README.md     # (1) 誤って実行してしまった場合
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    README.md
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       README.md
$ git add README.md             # (2) git rm --cached する前に戻るよ

ではインデックスに追加してから再度diffを実行してみましょう。

$ git diff

何も出力されない、、実は git diff は「作業ディレクトリの変更内容」のうち「 git commit してもコミットされないもの」(作業ディレクトリとインデックスの差分)を表示するコマンドなのです。

インデックスの内容(インデックスとHEADの差分)を確認する場合は git diff --cached を使います。

$ git diff --cached
diff --git a/README.md b/README.md
index ece6ee1..389a8ec 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # GTUG Girls # 14 Gitを使ってみよう
+gitの使い方を勉強します

変更内容も確認できたので、コミットします。

$ git commit -m "study how to use git"
[master f2dae35] study how to use git
 1 file changed, 1 insertion(+)

作業ディレクトリ、インデックス、リポジトリの関係

  • ファイルを追加した場合
working dir(clean)       working dir               index              repository
   |                        |                        |                    |
   |  touch file            |                        |                    |
   |----------------------->|                        |                    |
   |                        |                        |                    |
   |                        |  git add file          |                    |
   |                        |----------------------->|                    |
   |                        |                        |                    |
   |                        |  git rm --cached file  |                    |
   |                        |<-----------------------|                    |
   |                        |                        |                    |
   |  rm file               |                        |  git commit        |
   |<-----------------------|                        |------------------->|
   |                        |                        |                    |
  • ファイルを変更した場合
working dir(clean)       working dir               index              repository
   |                        |                        |                    |
   |  edit file             |                        |                    |
   |----------------------->|                        |                    |
   |                        |                        |                    |
   |                        |  git add file          |                    |
   |                        |----------------------->|                    |
   |                        |                        |                    |
   |                        |  git reset HEAD file   |                    |
   |                        |<-----------------------|                    |
   |                        |                        |                    |
   |  git checkout -- file  |                        |  git commit        |
   |<-----------------------|                        |------------------->|
   |                        |                        |                    |
  • git diff の内容
working dir               index              repository
                            |                        |
   |                        |                        |
   |        git diff        |                        |
   |<---------------------->|                        |
   |                        |                        |
   |                        |   git diff --cahced    |
   |                        |<---------------------->|
   |                        |                        |
   |                                                 |
   |                git diff HEAD                    |
   |<----------------------------------------------->|
   |                                                 |

変更をやり直す

幾つか変更をやりなおす操作があります。簡単な方法から説明していきます。まずはコミットログを変更する方法から。

git commit --amend を利用するとコミットをやり直せます。

$ git commit --amend -m "change commit message"  # コミットログを変更する
[master aba6ceb] change commit message
 1 file changed, 1 insertion(+)

コミットした内容をなかったコトにしたい場合は git revert を利用します。コミットした内容と逆の変更のコミットを作ります。

$ git revert HEAD   # HEADの内容をなかったコトにする。エディタが立ち上がるよ
[master f1ed1fb] Revert "change commit message"
 1 file changed, 1 deletion(-)

履歴を消したい場合は git reset を使います。このコマンドはブランチの位置をずらすコマンドです。ブランチの位置をずらすことによって、見かけ上の履歴を消すことが出来ます。

$ git branch                # (1) 今のブランチはmaster
* master
$ git lg                    # (2) masterの指すコミットを確認
* f1ed1fb (HEAD, master) Revert "change commit message"
* aba6ceb change commit message
* 528a519 add README.md
$ git reset --soft HEAD~    # (3) masterの指すコミットをHEADの親にする
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   README.md
#
$ git lg                    # (4) masterの指すコミットがずれている。
* aba6ceb (HEAD, master) change commit message
* 528a519 add README.md

2回実行すると、一度ずれた master が更にずれます、気をつけましょう。

でもって、これらの全ての操作をやり直したい時は git reflog を利用します。

$ git reflog
aba6ceb HEAD@{0}: reset: moving to HEAD~
f1ed1fb HEAD@{1}: revert: Revert "change commit message"
aba6ceb HEAD@{2}: commit (amend): change commit message
f2dae35 HEAD@{3}: commit: study how to use git
528a519 HEAD@{4}: commit (initial): add README.md

git reflog を確認すると今までの操作の一覧が表示されます。やり直したい場所を見つけたら、その内容で git reset を実行します。

$ git reset --hard HEAD@{3}  # やり直す前の状態に戻す
HEAD is now at f2dae35 study how to use git

ちなみに、この git reset の操作も git reflog で参照できます。

$ git reflog      # git resetの内容もreflogに記録される
f2dae35 HEAD@{0}: reset: moving to HEAD@{3}
aba6ceb HEAD@{1}: reset: moving to HEAD~
f1ed1fb HEAD@{2}: revert: Revert "change commit message"
aba6ceb HEAD@{3}: commit (amend): change commit message
f2dae35 HEAD@{4}: commit: study how to use git
528a519 HEAD@{5}: commit (initial): add README.md

reflogはとても便利なのですが永続的な情報ではありません。gitのコマンド実行時に時折実行される git gc で消えることがあります。基本的にはgcが実行されると30日より古いreflogの内容は消え去ると考えてください。

reflogを削除する条件や、条件のカスタマイズなど詳しい動作については git help gc を参照してください。

演習

git addgit commitgit rmgit checkout などいままで登場したコマンドの一行解説を README.md に追記してチートシートを作成してください。

## git add

変更内容をインデックスに追加する

{{{
git add <file>     # <file> をインデックスに追加する
}}}

わからなかったら git help なども参考にしてください。演習なので、今まで登場したコマンドを試してみましょう。

ブランチとマージ

基本の使い方を学んだので、ブランチやらマージやらのgitの醍醐味を味わってみようと思います。ここでは次のことを行います。

  • ブランチの作成
  • マージ
  • マージのコンフリクトとその解決

新規リポジトリを作成

履歴があるといろいろ説明が大変なので、とりあえずリポジトリをつくり直しましょう。

$ git init gtug-girls-14-branch-test
$ cd gtug-girls-14-branch-test
$ echo "# GTUG Girls # 14 Gitを使ってみよう" > README.md
$ git add README.md
$ git commit -m "add README.md"
[master (root-commit) 9039f70] add README.md
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

グラフはこんな形になってるはず。

$ git lg
* 9039f70 (HEAD, master) add README.md

ブランチの作成

ブランチを作ってみます。今回はREADME.mdにグラフに関する説明を追加するということで feature-log というブランチを作成します。

# 方法1
$ git branch feature-log master
$ git checkout feature-log

# 方法2
$ git checkout -b feature-log master

成功したらこんな状態になっていると思います。

$ git branch
* feature-log
  master
$ git lg
* 9039f70 (HEAD, master, feature-log) add README.md

ブランチを作れたので、ブランチに対してコミットします。README.mdに何か追加してみます。

$ vi README.md
$ git diff
diff --git a/README.md b/README.md
index ece6ee1..bee0247 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,9 @@
 # GTUG Girls # 14 Gitを使ってみよう
+
+## git log
+
+ログを見るコマンド
+
+{{{
+git log -p   # 変更内容も表示する
+}}}
$ git add README.md
$ git commit -m "short description of git log"
[feature-log 654b1c6] short description of git log
 1 file changed, 8 insertions(+)

もう一回変更してコミットします。

$ vi README.md
$ git diff
diff --git a/README.md b/README.md
index bee0247..1a5b330 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,5 @@

 {{{
 git log -p   # 変更内容も表示する
+git log --graph --decorate --oneline  # グラフでいい感じに表示
 }}}
$ git add README.md
$ git commit -m "add example of git log --graph"
[feature-log 3066fac] add example of git log --graph
 1 file changed, 1 insertion(+)

2回コミットしました。グラフはこんな形になっていると思います。

$ git lg
* 3066fac (HEAD, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 (master) add README.md

ブランチのマージ

では feature-log の変更を master にマージしてみましょう。 master にマージするので、 master に移動してから git merge を実行します。

$ git checkout master              # masterに移動
Switched to branch 'master'
$ git merge feature-log            # feature-logをマージ
Updating 9039f70..3066fac
Fast-forward
 README.md | 9 +++++++++
 1 file changed, 9 insertions(+)
$ git lg
* 3066fac (HEAD, master, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 add README.md

Fast-forwardというメッセージが表示され、masterブランチのいちが移動しました。マージコミット(あとで登場します)はできませんでした。 今回の様に履歴が一直線で、単にブランチを移動させるだけで、マージコミットを作らないマージのことをファストフォワードマージと呼びます。

2つのブランチで分岐を作ってマージ

先ほどのマージの例では一つの修正をマージしました。今度は同時に2つの修正を行って、マージしていきましょう。

master を基点に新しいブランチ feature-branch を作って git branch の説明文を末尾に追加します。

$ git checkout -b feature-branch master
Switched to a new branch 'feature-branch'
$ vi README.md
$ git diff
diff --git a/README.md b/README.md
index 1a5b330..58d521d 100644
--- a/README.md
+++ b/README.md
@@ -8,3 +8,12 @@
 git log -p   # 変更内容も表示する
 git log --graph --decorate --oneline  # グラフでいい感じに表示
 }}}
+
+## git branch
+
+ブランチの操作を行う
+{{{
+git branch # ブランチを表示
+git branch <branch-name> # ブランチを作成
+git branch <branch-name> <start-point> # start-pointにブランチを作成
+}}}
$ git add README.md
$ git commit -m "short description of git branch"
[feature-branch ee51e7e] short description of git branch
 1 file changed, 9 insertions(+)

もう一つブランチを作ります。 master を基点にブランチ feature-merge を作り、 git merge の説明を末尾に追加します。

$ git checkout -b feature-merge master
Switched to a new branch 'feature-merge'
$ vi README.md
$ git diff
diff --git a/README.md b/README.md
index 1a5b330..cd57616 100644
--- a/README.md
+++ b/README.md
@@ -8,3 +8,12 @@
 git log -p   # 変更内容も表示する
 git log --graph --decorate --oneline  # グラフでいい感じに表示
 }}}
+
+## git merge
+
+2つの変更を取り込むコマンド
+
+{{{
+git merge <branch>  # 現在のブランチに<branch>をマージする
+git merge --no-ff <branch>  # ファストフォワードしないマージをする
+}}}
$ git add README.md
$ git commit -m "short description of git merge"
[feature-merge 1bbbf94] short description of git merge
 1 file changed, 9 insertions(+)

うまくいくとこんなグラフになっていると思います。

$ git lg --all
* 1bbbf94 (HEAD, feature-merge) short description of git merge
| * ee51e7e (feature-branch) short description of git branch
|/
* 3066fac (HEAD, master, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 add README.md

分岐してますね。

では、 feature-branchfeature-merge のそれぞれのブランチを master にマージしてみます。

$ git checkout master
Switched to branch 'master'

今回は --no-ff オプションを指定してみましょう。まずは feature-branch のほうから

$ git merge --no-ff feature-branch  # エディタが立ち上がるよ
Merge made by the 'recursive' strategy.
 README.md | 9 +++++++++
 1 file changed, 9 insertions(+)

マージできました。今度はファストフォワードしたよ、というメッセージは表示されません。グラフはこんなかんじです。不思議なコミットができてますね。

$ git lg --all
*   7899e10 (HEAD, master) Merge branch 'feature-branch'
|\
| * ee51e7e (feature-branch) short description of git branch
|/
| * 1bbbf94 (HEAD, feature-merge) short description of git merge
|/
* 3066fac (HEAD, master, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 add README.md

つぎは feature-merge をマージします。

$ git merge feature-merge
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトしました!

コンフリクトと解決

今まで、事あることに git status を実行してきました。実はコンフリクトの状態も git status で確認できます。

$ git status
# On branch master
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#       both modified:      README.md
#
no changes added to commit (use "git add" and/or "git commit -a")

README.md が両方で修正されているため、コンフリクトしてるというメッセージが表示されています。どのようにコンフリクトしているかについては git diff で調べることが出来ます。

$ git diff
diff --cc README.md
index 58d521d,cd57616..0000000
--- a/README.md
+++ b/README.md
@@@ -9,11 -9,11 +9,21 @@@ git log -p   # 変更内容も表示す
  git log --graph --decorate --oneline  # グラフでいい感じに表示
  }}}

++<<<<<<< HEAD
 +## git branch
 +
 +ブランチの操作を行う
 +{{{
 +git branch # ブランチを表示
 +git branch <branch-name> # ブランチを作成
 +git branch <branch-name> <start-point> # start-pointにブランチを作成
++=======
+ ## git merge
+
+ 2つの変更を取り込むコマンド
+
+ {{{
+ git merge <branch>  # 現在のブランチに<branch>をマージする
+ git merge --no-ff <branch>  # ファストフォワードしないマージをする
++>>>>>>> feature-merge
  }}}

今までとは違う出力です。

<<<<<<<=======>>>>>>> などの記号はコンフリクトマーカーと呼びます。コンフリクトしている場所を示すもので、実際にファイルに書きだされます。2つ表示された + ( - ) もマーカーで、由来するブランチを示します。こちらは git diff にのみ登場します。

コンフリクトの内容がわかりました。今回は両方の変更を残します。ファイルを編集して

$ vi README.md
$ git diff
diff --cc README.md
index 58d521d,cd57616..0000000
--- a/README.md
+++ b/README.md
@@@ -9,11 -9,11 +9,20 @@@ git log -p   # 変更内容も表示す
  git log --graph --decorate --oneline  # グラフでいい感じに表示
  }}}

 +## git branch
 +
 +ブランチの操作を行う
 +{{{
 +git branch # ブランチを表示
 +git branch <branch-name> # ブランチを作成
 +git branch <branch-name> <start-point> # start-pointにブランチを作成
 +}}}
++
+ ## git merge
+
+ 2つの変更を取り込むコマンド
+
+ {{{
+ git merge <branch>  # 現在のブランチに<branch>をマージする
+ git merge --no-ff <branch>  # ファストフォワードしないマージをする
+ }}}

git add を実行してコンフリクトが解決されたことをgitに教えます。

$ git add README.md

ではコミットしましょう。

$ git commit  # エディタが立ち上がるよ
[master 88b2d84] Merge branch 'feature-merge'

うまくいくと次のようなグラフになります。

$ git lg
*   88b2d84 (HEAD, master) Merge branch 'feature-merge'
|\
| * 1bbbf94 (feature-merge) short description of git merge
* |   7899e10 Merge branch 'feature-branch'
|\ \
| |/
|/|
| * ee51e7e (feature-branch) short description of git branch
|/
* 3066fac (HEAD, master, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 add README.md

マージする前に戻したい場合

コンフリクト解決時に失敗した、間違ってマージしてしまった場合は、次のコマンドを実行します。

$ git merge --abort   # マージをやめる

これでマージ前の状態に戻ります。

演習

master から feature-resetfeature-reflog というブランチを作り、それぞれのブランチで変更を加えた後、 master にマージしてください。

リモートリポジトリ

実際に Git を使っていく上では、リモートリポジトリ(クローン元だったりフォーク元だったり)とのやりとりが必須です。ここでは次のことを行います。

  • 共有用のリポジトリの作成
  • リモートリポジトリを登録
  • 変更の反映と取得

リポジトリの関係

/
|-- gtug-girls-14-branch-test  # 今作業していたリポジトリ
|-- gtug-girls-14.git          # リモートリポジトリ

共有用リポジトリの作成

git では作業用リポジトリと共有用リポジトリの作成方法が異なります。 --bare オプションをつけて共有用リポジトリ(ベアリポジトリ)を作成しましょう。

$ git init --bare gtug-girls-14.git
Initialized empty Git repository in /Users/takumi/tmp/gtug-girls-14.git/

補足: sshでリポジトリを公開する場合は --shared オプションが必要になる場合があります。詳しくは git help init を参照してください。

ベアリポジトリは作業ディレクトリを持たないリポジトリのことです。サフィックスに .git をつけるのが慣習です。

  • 普通のリポジトリ 作業ディレクトリを持つ
goltsv
├── .git
│   ├── HEAD
│   ├── branches
│   ├── config
│   ├── description
│   ├── hooks
│   ├── index
│   ├── info
│   ├── logs
│   ├── objects
│   ├── packed-refs
│   └── refs
├── .gitignore
├── AUTHORS
├── LICENSE
├── README.rst
├── reader.go
├── reader_test.go
├── writer.go
└── writer_test.go
  • ベアリポジトリ .gitの中身だけの存在
hogehoge.git
├── HEAD
├── branches
├── config
├── description
├── hooks
├── index
├── info
├── logs
├── objects
├── packed-refs
└── refs

リモートリポジトリを登録

共有用リポジトリが出来たので、今まで作業していたリポジトリに共有用リポジトリを追加してみましょう。 共有用リポジトリには git remote add <name> <url> を使います。 今回は共有用リポジトリを origin として追加します。

$ cd gtug-girls-14-branch-test
$ git remote add origin ../gtug-girls-14.git
$ git remote -v
origin  ../gtug-girls-14.git (fetch)
origin  ../gtug-girls-14.git (push)

リモートリポジトリに変更を反映させる

アップロードには git push <repo> <branchname> を使います。 <repo> には git remote で使った名前が使えます。

$ git push origin master   # masterの内容をoriginに反映させる
Counting objects: 19, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (19/19), 2.05 KiB | 0 bytes/s, done.
Total 19 (delta 5), reused 0 (delta 0)
To ../gtug-girls-14.git
 * [new branch]      master -> master

master の部分を変更すれば、そのブランチをpush出来ます。

また、pushするとpushしたリポジトリのブランチの情報が記録されます。

$ git lg
*   88b2d84 (HEAD, origin/master, master) Merge branch 'feature-merge'
|\
| * 1bbbf94 (feature-merge) short description of git merge
* |   7899e10 Merge branch 'feature-branch'
|\ \
| |/
|/|
| * ee51e7e (feature-branch) short description of git branch
|/
* 3066fac (HEAD, master, feature-log) add example of git log --graph
* 654b1c6 short description of git log
* 9039f70 add README.md

リモートリポジトリの変更を取得する

よく、pushとpullが対比として紹介されますが、これはgitの場合は嘘です。pushの反対はfetchです。 git fetch <repo> を使いましょう。

$ git fetch origin          # originの全てのブランチを取得
$ git fetch origin master  # originのmasterのみ取得

変更が取り込まれると、 origin/master などリモートリポジトリのブランチの情報が更新されます。 ローカルのブランチと同期したい場合は手動でマージしましょう。

$ git checkout master
$ git merge origin/master

このマージの場合はファストフォワードになってほしいので、基本的に --no-ff オプションはつけません。

git pull について

git pull は内部で git fetchgit merge を実行します。このため動作を把握できていない場合、意図しないマージが発生する可能性があります。 git help pull の内容をしっかり理解するまでは git fetchgit merge を個別に実行したほうが混乱が少ないです。

演習

GitHubにアカウントを作成してください。

GitHubのリポジトリはHTTPSとSSHの両方でアクセス可能です。SSHを利用する場合は次のドキュメントを参考にSSHの鍵を登録してください

演習

次のGitHubのリポジトリをフォーク(右上のボタンをクリック)して、プルリクエストを送ってください。

https://github.com/sugamasao/kanojo_bot

プルリクエストを送るときに次の手順をとってください。

  1. リポジトリをフォーク
  2. フォークしたリポジトリをhttpsでクローン
  3. masterからブランチを作成 例: git checkout -b feature-awesome-message master
  4. 変更をコミット
  5. 変更を自分のリポジトリのpush 例; git push origin feature-awesome-message
  6. ぷるりを送る

変更内容については 調度良い課題があるので、そちらも参考にしてください。

より使いこなすために

基本的な使い方、プルリクエストを送るために最低限必要なコマンド群を紹介しました。 まずは、紹介したコマンドの使い方をしっかり覚えましょう。

履歴改変などを行いたい場合は次のコマンドを重点的に調べてください。

  • git add -p インデックスに入れる変更を対話的に選択する
  • git rebase 履歴を別のブランチに移動させる
  • git rebase -i 履歴を書き換える
  • git cherry-pick 指定したコミットを今のブランチに適用させる
  • git reflog 困ったときはこれ。「git アレ」で検索すると良い感じの情報が出てきます

ドキュメント

  • Pro Git (日本語訳)
    • これを見ながらこの資料を作りました。
  • Git - Reference
    • 代表的なコマンドのリファレンスです。左半分のコマンドを使いこなせるようになれば一人前です。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment