1 Gitの操作環境

Git Bash

概要

  • Windowsユーザーは「Git Bash」を使用する
  • WindowsでもLinuxやMacのBashコマンドをそのまま使うことができる
  • GitはLinux環境を想定した操作が多いので、WindowsでもBashコマンドで操作する必要がある

コマンドライン

<メリット>

  • Gitが用意しているすべての操作(オプション操作)を行うことができる
  • コマンドの補完入力、オプションの使用で素早い操作が可能

<デメリット>

  • コマンドを覚えていないと操作ができない
  • Git Flowなど複雑なワークフローでは全体感が見えにくくなる

ショートカット

  • コピー :Ctrl + Insert
  • ペースト:Shift + Insert

学習資料

  • Git:もう怖くないGit!チーム開発で必要なGit完全マスター

Git Kraken

概要

  • GUIベースでのGitの操作が可能なアプリケーション
  • 全てのコマンド操作ができるわけではないが、開発実務で使用する操作は網羅されている
  • 「.git」のあるディレクトリでは、右クリックの「Open with Git Kraken」で開く

主な機能

  • Git操作のGUIでのサポート
  • 簡易的なエディタ機能
  • ディレクトリのエクスプローラー機能
  • ファイル比較機能

Git Flowのサポート

  • GitKrakenはGit Flowを実践するためのサポート機能が備わっている
  • 具体的にはGit Flowのフレームワークが準備されている
  • コマンドラインではフローの全体像を把握するのが難しいので、GUIの併用は必須といえる

学習資料

  • Git入門:ノンプログラマーのためのGit

基本設定

バージョン確認

In [ ]:
# バージョン表示
$ git --version

設定登録

  • はじめに登録すべき内容は以下の3つがある
  • エディタはatomやVScodeなどがよく用いられる
In [ ]:
# ユーザー名の登録
$ git config --global user.name "github user name"

# E-mailアドレスの登録
$ git config --global user.email "github@sample.ne.jp"

# エディタの登録
# --- コミットメッセージを書く際に使用
$ git config --global core.editor "atom --wait"
$ git config --global core.editor "code --wait"
  • コマンドにエイリアス(別名)をつけることができる
In [ ]:
# commit
$ git config --global alias.ci commit

# status
$ git config --global alias.st status

# branch
$ git config --global alias.br branch

# checkout
$ git config --global alias.co checkout
  • より使いやすい環境にするための諸設定
In [ ]:
# コンソール出力の色付け
$ git config --global color.ui true

# 変更をフローチャート表示
git config --global alias.graph 'log --graph --decorate --oneline'
  • 必要に応じて行う高度な設定
In [ ]:
# Fast-Fowardマージを禁止する
# --- ff:fast-foward
$ git config --global merge.ff false

個別設定の確認

In [ ]:
# ユーザー名の確認
$ git config user.name

# E-mailアドレスの確認
$ git config user.email

# エディタの確認
$ git config core.editor

全体設定の確認

  • 設定情報はホームディレクトリの「.gitconfig」ファイルに保存されている
  • catコマンドでファイルの中身を表示
  • 「~」でホームディレクトリに移動
In [ ]:
# 設定全体の確認
$ git config --list

# 設定の保存場所
$ cat ~/.gitconfig

2 Gitの基礎知識

Gitの構造

ローカルのフォルダ構造

  • gitの管理で使用するすべてのファイルが格納される(具体的には以下の通り)
  • config , description , HEAD , hooks/ , info/ , objects/ , refs/
  • 「objects」はリポジトリの本体
  • 「config」はgitの設定ファイル
In [ ]:
# **** フォルダ構造の確認 ****

# ローカルリポジトリの新規作成
# --- 適当なディレクトリで実行
$ git init


# 「.git」ディレクトリの確認
$ ls -a
./  ../  .git/


# 「.git」ディレクトリの中を確認
$ ls .git
COMMIT_EDITMSG  description  hooks/  info/  objects/
config          HEAD         index   logs/  refs/

ステージの役割

コミット粒度の調整

  • Gitにはgit addで変更状況をステージに追加して、その後コミットするという2段階の操作を行う
  • ステージが存在することで、コミットの粒度をコントロールすることができる
  • 開発中はファイル更新に集中して、ステージでコミットの粒度や順番を考えていく

変更が記録されるタイミング

  • git addでステージに追加する前は、Gitは1つの変更として扱う
  • git addでステージに追加した後は、Gitはファイルの変更を個別に扱う

コミットの単位

方針

  • コミットの単位(粒度)はなるべく細かいほうがよい

行単位のコミット

  • 同一ファイル内でコミット単位を分けたい場合がある
  • Gitでは行単位のコミットというのが可能

<ポイント>

  • コマンドラインでは柔軟に行いにくいレベルの操作になってくる
  • Git KrakenのようなGUIを使わないと分かりにくくなる操作なので注意
In [ ]:
# **** 構文 ****

# 行単位でコミット
$ git add -p <file>

コミットメッセージの書き方

ポイント

  • コミットメッセージは明確に記述する
  • コミットメッセージが一言で意図が伝えられる程度の粒度で開発を行う
  • 表現や文体は統一しておく(動詞+目的語)
  • バグがある状態ではコミットしない

簡便な書式

  • 1行目:変更内容の要点と理由を1行で簡潔に記述(72文字以内)

正式な書式

  • 1行目:変更内容の要点(72文字以内)
  • 2行目:空白行
  • 3行目:変更した理由

雛形

  • 「git commit」を実行すると、エディタに以下のようなメッセージが表示される
  • 「git commit -m "コミットメッセージ"」として入力すると、エディタを使わずに入力できる
In [ ]:
ここにコミットメッセージを記述
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
#	new file:   index.html
#

バージョン管理の対象外

「.gitignore」による指定

  • 「.gitignore」ファイルにファイル名を指定しておくとバージョン管理の対象外となる
  • バージョン管理の対象外のファイルは作業環境によってほぼ決まってくると考えてよい
  • 「.gitignore」ファイルの雛形は様々なところで配布されている

<ファイルの書き方>

  • #から始まる行はコメント
  • 直下のファイル名を指定(index.html)
  • ルートディレクトリのファイルを指定(/root.html)
  • ディレクトリを指定(dir/)
  • ワイルドカード指定(*.css)

空ディレクトリ

  • Gitでは、空ディレクトリは管理対象とならない(適当なファイルをディレクトリに置いておく必要がある)
  • 慣例的に「.gitkeep」というファイル名が用いられることが多い
In [ ]:
# 空のディレクトリ作成
$ mkdir <new_dir> 

# ディレクトリ移動
$ cd <new_dir>

# ファイル作成
$ touch .gitkeep

3 チーム開発のフロー

Git Flow

準備中

GitHub Flow

開発の流れ

<準備>

  • ステップ1: リモートリポジトリからプロジェクトをローカルにクローンする

<ローカルでの作業>

  • ステップ2: 「master」ブランチから、開発トピックのブランチ(topic_1)を作成
  • ステップ3: 開発
  • ステップ4: 開発したファイルをコミット
  • ステップ5: ローカルで作成したブランチと同名のブランチをGitHubにプッシュ

<リモートでの作業>

  • ステップ6: プルリクエストの送信
  • ステップ7: コードレビュー
  • ステップ8: レビュアーがリモートのマスターに開発を反映

ポイント

  • 「master」ブランチは常にデプロイできる状態を保つ(ローカルとリモートの両方)
  • 新開発は「master」ブランチから新しいブランチを作成してからスタート
  • トピックブランチでのコミットを細かい単位で行う
  • 定期的にリモートにPushしておく(開発状況の共有)
  • 開発が終了したらレビュアーにプルリクエストを送信(コードレビュー)
  • 「master」ブランチにマージしたら即時デプロイ(テストとデプロイの自動化)

ハンズオン

In [ ]:
# **** ハンズオン ****

# ファイル新規作成
$ touch test.txt     Git管理するファイル
$ touch secret.txt   Git管理しないファイル

# 除外ファイルの設定ファイル
$ cat .gitignore
secret.txt

# ファイル一覧
# --- 「.gitignore」ファイルは隠しファイルなので出力されない
$ ls
index.html  secret.txt

# ステータスの確認
# --- secret.txtが除外されている
# --- 「add」コマンドでも同様に除外される
$ git status -s
?? .gitignore
?? test.txt

4 基本操作

環境構築

はじめに

  • gitの環境構築は「git init」か「git clone」で行う
  • 新規プロジェクトへの立ち上げには「git init」を実行する
  • 既存プロジェクトへの参加には「git clone」を実行する

環境新規の作成:init

  • 「git init」を実行すると「.git」ディレクトリが隠しフォルダとして作成される
  • 「.git」ディレクトリに必要なすべての情報が格納される
  • 「.git」ディレクトリを削除するとGitの管理はなくなる
  • 「init」は「initialize」の略語
In [ ]:
# **** 構文 ****

# カレントディレクトリに「.git」を作成
$ git init


# 新規フォルダを作成して「.git」を作成
$ git init <フォルダ名>
In [ ]:
# **** ハンズオン1:カレントディレクトリに作成 ****

# カレントディレクトリに「.git」を作成
$ git init

# 「.git」ディレクトリの確認
$ ls -a
./  ../  .git/
In [ ]:
# **** ハンズオン2:新規フォルダに作成 ****

# 新規フォルダを作成して「.git」を作成
$ git init proj_x

# 「.git」ディレクトリの確認
$ ls -a
proj_x/

# ディレクトリの移動
$ cd proj_x

# 「.git」ディレクトリの確認
$ ls -a
./  ../  .git/

クローンの作成:clone

  • リモートリポジトリをローカルリポジトリに取り込んでクローンを作成する
  • 「URL」はGithubの対象リポジトリで「Clone or download」ボタンを押下してコピーする
  • ダウンロードするプロジェクト用にディレクトリを作成して、「Git Bash Here」で開いておく
In [ ]:
# **** 構文 ****

# リモートリポジトリのクローンを作成
$ git clone <url>
In [ ]:
# **** ハンズオン ****

# リモートリポジトリのクローンを作成
# --- テスト用:atomプロジェクト
$ git clone https://github.com/atom/atom.git
    
# ディレクトリ移動
$ cd atom

# ファイル一覧の確認
# --- 隠しファイルも併せて確認
$ ls -a
./                 benchmarks/         package-lock.json
../                CHANGELOG.md        packages/
.coffeelintignore  CODE_OF_CONDUCT.md  PULL_REQUEST_TEMPLATE.md
.eslintignore      coffeelint.json     README.md
.eslintrc.json     CONTRIBUTING.md     resources/
.git/              Dockerfile          script/
.gitattributes     docs/               spec/
.github/           dot-atom/           src/
.gitignore         exports/            static/
.prettierrc        keymaps/            stylelint.config.js
.python-version    LICENSE.md          SUPPORT.md
apm/               menus/              vendor/
atom.sh*           package.json

リモートの設定

はじめに

  • gitは「ローカルリポジトリ」と「リモートリポジトリ」の両方でプログラムを管理する
  • 「リモートリポジトリ」を使う準備として、以下の作業を行っておく必要がある

<準備>

  • リモートリポジトリの登録(GitHubやCodeCommitなど)
  • リポジトリの作成(任意の名前で作成)
  • リポジトリのURL取得(リポジトリで表示されている)
  • ローカルリポジトリにリモートリポジトリのURLとショートカット名を登録

リモートの登録:remote add

  • リモートリポジトリのURLをショートカットとして特定の名前で登録しておく
  • Githubなどのリモートリポジトリは別途作成しておく必要がある
  • Gitではリモートリポジトリのことを「origin」と呼ぶので、その名前を付けることが多い

<複数のリモートリポジトリ登録について>

  • リモートリポジトリはプロジェクト単位で複数登録することができる
  • 通常は1つのプロジェクトは1つのリポジトリで管理する(トラブル防止の観点)
  • ただし、1つのプロジェクトで複数の開発にかかわっていたりする場合に、複数のリモートリポジトリを持つこともある
In [ ]:
# **** 構文 ****

# リモートリポジトリを登録
# --- 以下の構文は、Githubでリポジトリを作成する際にページ上に表示される
$ git remote add <リモート名> <リモートURL>
In [ ]:
# **** ハンズオン ****

# 登録 --------------------------------

# リモートリポジトリの追加:1つめ
$ git remote add origin https://github.com/xxxxxx/git_tutorial.git

 # リモートリポジトリの追加:2つめ
$ git remote add bak https://github.com/user_name/git_tutorial_bak.git
    

# 確認 --------------------
    
# 登録したリポジトリ一覧を確認
$ git remote
bak
origin

# リポジトリの登録URLの確認
$ git remote -v
bak     https://github.com/user_name/git_tutorial_bak.git (fetch)
bak     https://github.com/user_name/git_tutorial_bak.git (push)
origin  https://github.com/user_name/git_tutorial.git (fetch)
origin  https://github.com/user_name/git_tutorial.git (push)
    

リモートの表示:remote

  • ローカルのGitに登録しているリモートリポジトリの情報を表示する
In [ ]:
# **** 構文 ****

# リモートリポジトリを表示
$ git remote

# 対応するURLも併せて表示
$ git remote -v
In [ ]:
# **** ハンズオン ****

# リモートリポジトリを表示
$ git remote
origin

# 対応するURLも併せて表示
# --- fetchとpushでURLを変更することができるので2つ表示される
$ git remote -v
origin  https://github.com/user_name/git_tutorial.git (fetch)
origin  https://github.com/user_name/git_tutorial.git (push)

リモートの表示:remote show

  • ローカルのGitに登録しているリモートリポジトリの詳細情報を表示する

<表示される内容>

  • FetchとPushのURL
  • リモートブランチ
  • 「git pull」の挙動
  • 「git push」の挙動
In [ ]:
# **** 構文 ****

# リモートから情報を取得してマージする
$ git remote show <リモート名>
In [ ]:
# **** ハンズオン ****

# 情報を確認
$ git remote show origin
* remote origin
  Fetch URL: https://github.com/user_name/git_tutorial.git
  Push  URL: https://github.com/user_name/git_tutorial.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local ref configured for 'git push':
    master pushes to master (up to date)

リモートの変更:remote rename

  • 登録したリモートリポジトリの名前を変更する
  • 使わなくなったリモートを名前変更して再利用するなどで使う
In [ ]:
# **** 構文 ****

# 名前を変更
$ git remote rename <旧リモート名> <新リモート名>
In [ ]:
# **** ハンズオン ****

# 準備:現在登録しているリモートの確認
$ git remote
bak
origin

# リモートリポジトリの名前変更
# --- コマンド出力なし
$ git remote rename bak bakup

# 変更を確認
$ git remote
bakup
origin

リモートの削除:remote rm

  • 登録したリモートリポジトリを削除する
In [ ]:
# **** 構文 ****

# リモートを削除
$ git remote rm <リモート名>
In [ ]:
# **** ハンズオン ****

# 準備:現在登録しているリモートの確認
$ git remote
bakup
origin

# リモートリポジトリを削除
# --- コマンド出力なし
$ git remote rm bakup

# 削除を確認
$ git remote
origin
  • 「git remote」コマンドよりも詳しい情報を表示することができる

基本フロー

はじめに

  • Gitの登録フローは「Add」「Commit」「Push」の3ステップで構成される
  • 変更の修正や削除はここでは言及しない

ステージ追加:add

  • 「ワークツリー」から「ステージ」に変更を追加する
  • 「ステージ」とは、「コミットする変更を準備」するためにある

<フロー>

  • ワークツリーに変更を記録したいファイルAを作成する(準備)
  • 「リポジトリ」に、ファイルAの内容を圧縮したファイル(圧縮ファイルA)を作成する
  • 「ステージ」に、圧縮ファイルの名前とファイル内容をマッピングした「インデックス」が作成される
In [ ]:
# **** 構文 ****

# 変更をステージに追加する
$ git add <ファイル名>
$ git add <ディレクトリ名>
$ git add .
In [ ]:
# **** ハンズオン ****

# 新規ファイルを作成
$ touch test.txt
    
# ファイルをステージに追加
$ git add .

変更を記録:commit

  • 準備:「git add」でステージエリアにインデックスを追加しておく
  • リポジトリに「ツリーファイル」と「コミットファイル」を作成する
  • 「ツリーファイル」とは、ステージのインデックスをもとに、
  • 「コミットファイル」には、「ツリー名」「作成者」などが記録されて、「ツリーファイル」と「ツリー名」でリンクする
In [ ]:
# **** 構文 ****

# ステージの変更をリポジトリに記録する
$ git commit

# オプション:-m
# --- Gitのエディタを立ち上げることなくメッセージを追加することができる
$ git commit -m "<メッセージ>"

# オプション:-v
# --- エディタ上に変更内容を表示する
$ git commit -v
In [ ]:
# **** ハンズオン ****

# エディタを開く
# --- 作業ディレクトリにファイルを作成&保存
$ atom
    
# 保存されたファイルを確認
$ ls

# ステージに追加
$ git add .

リモートに反映:push

  • ローカルの内容をリモートリポジトリに反映する
  • チームメンバーとコードを共有する場合に使用する
In [ ]:
# **** 構文 ****

# ファイルごとの移動
$ git push <リモート名> ><ブランチ名>
$ git push origin master

# オプション:-u
# --- origin masterを今後省略できるように設定
git push -u origin master
In [ ]:
# **** Gitにプッシュ ***

# プッシュするリポジトリに移動
# --- 右クリックの「Git Bush Here」でカレントディレクトリでGit Bashを開始してもよい
cd local_repos


# プッシュ
git push -u origin master

ステータスの確認

ベーシック表示:status

  • ローカルリポジトリの変更状態を確認
  • 「ワークツリー」と「ステージ」の間(add)、「ステージ」と「リポジトリ」の間(commit)での変更状況を確認する
  • 「-s」をつけたコンパクト表示のほうが見やすい
In [ ]:
# **** 構文 ****

# 現在の変更状況を確認する
$ git status
In [ ]:
# **** ハンズオン:準備 ****

# ステータス確認(準備前)
# --- コミットするファイルがないことを確認
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)


# 準備
# --- Git管理環境に新規ファイルを作成
$ touch test.txt
$ echo "test" > test.txt
In [ ]:
# **** ハンズオン:ステージに追加 ****

# ステージに追加
$ git add test.txt


# ステータス確認(add後)
# --- ステージに変更が反映されていないことを検知
$ git status
On branch master

No commits yet

Changes to be committed: 変更(ステージに追加)されたけどコミットされていないファイルがある
  (use "git rm --cached <file>..." to unstage)
        new file:   test.txt
In [ ]:
# **** ハンズオン:コミット ****

# コミット
$ git commit -m "initial commit"
[master (root-commit) 32d5efd] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt


# ステータス確認
# --- リポジトリに変更が反映されていないことを検知(コミットされていないファイルを教えてくれる)
$ git status
On branch master
nothing to commit, working tree clean コミットされていないファイルはない

コンパクト表示:status -s

  • 「git status」の要点をコンパクトに表示する

<ステータス表記>

  • M_ : 変更がgit addされている (staged)
  • _M : 変更がgit addされていない (modified)
  • A_ : 新しいファイルがgit addされている
  • _D : rmされているけどgit addやgit rmはされていない
  • ?? : gitに登録されていない(untracked)
  • UU : mergeするbranchも手元も変更がありconflictした (unmerged)
  • DU : mergeするbranchで変更されたが手元では削除されいるのでconflictした
In [ ]:
# **** 構文 ****

# 現在の変更状況をコンパクトに表示する
$ git status -s
In [ ]:
# **** ハンズオン ****

# Git管理前 --------------------------------

# 準備
# --- Git管理環境に新規ファイルを作成
$ touch test2.txt
$ echo "test" > test.txt

# ステータス確認
$ git status -s
?? test.txt  Git管理外のファイルに「??」がつく


# ステージ追加後 --------------------------------

# ステージに追加
$ git add test.txt

# ステータス確認
$ git status -s
A  test.txt  AddされたファイルにAAddがつく


# ステージ追加後に変更 --------------------------------

# ファイル内容を変更
$ echo Hello World! >> test.txt

# ステータス確認
$ git status -s
AM test.txt  変更されたファイルにMModifyがつく


# ステージに再度追加 --------------------------------

# ステージに追加
$ git add test.txt

# ステータス確認
$ git status -s
A  test.txt


# コミット後 --------------------------------

# コミット
$ git commit -m "initial commit"


# ステータス確認
# --- 何も表示されない
$ git status -s

変更差分の確認:diff

  • 何を変更したのかを確認する(前回との比較)
  • 「ワークツリー」と「ステージ」、「ステージ」と「リポジトリ」の2パターンがある
In [ ]:
# **** 構文 ****

# 変更差分の表示
# --- 「ワークツリー」と「ステージ」の差分(git addを行う前)
$ git diff
$ git diff <ファイル名>

# オプション:--staged
# --- 「リポジトリ」と「ステージ」の差分(git commmitを行う前)
$ git diff --staged
In [ ]:
# **** ファイルを変更して変更差分を表示 ****

# エディタを起動
# --- ファイルを変更
$ atom


# ステータス確認
# --- 「ワークツリー」と「ステージ」に変更差分がないことを確認
$ git diff

diff --git a/index.html b/index.html
index d31eea4..47028db 100644
--- a/index.html
+++ b/index.html
@@ -1,2 +1,3 @@
 <h1>Gitチュートリアル</h1>
 <p>git status</p>
+<p>git diff</p>
In [ ]:
# **** 変更ファイルをステージに追加 ****

# ステージに追加
# --- 「ワークツリー」と「ステージ」の変更差分が解消
$ git add index.html


# ステータス確認
# --- 「ワークツリー」と「ステージ」に変更差分がないことを確認
$ git diff


# ステータス確認
# --- 「ステージ」と「リポジトリ」に変更差分があることを確認
$ git diff --staged

diff --git a/index.html b/index.html
index d31eea4..47028db 100644
--- a/index.html
+++ b/index.html
@@ -1,2 +1,3 @@
 <h1>Gitチュートリアル</h1>
 <p>git status</p>
+<p>git diff</p>
In [ ]:
# **** 変更ファイルをリポジトリに反映 ****

# コミット
# --- エディタにコミットメッセージを作成
$ git commit

# ステータス確認
# --- 「ワークツリー」と「ステージ」に変更差分がないことを確認
$ git diff

# ステータス確認
# --- 「ステージ」と「リポジトリ」に変更差分がないことを確認
$ git diff --staged

変更履歴の確認:log

  • コミットの変更履歴を確認する
  • リポジトリのコミットを直近から順にたどって表示している
  • ログは別画面で表示されるので、以下のような専用操作コマンドがある

<別画面の操作>

  • [p] :画面を上にスクロール
  • [j] :画面を下にスクロール
  • [q] :ログ画面から抜ける
In [ ]:
# **** 構文 ****

# 変更履歴の表示
$ git log

# オプション:--oneline
# --- 1行で表示
$ git log --oneline

# オプション:-n
# --- 表示するコミット数を制限
$ git log -n

# オプション:-p
# --- 「git log」と「git diff」を同時に表示
$ git log -p index.html
In [ ]:
# **** ハンズオン ****

# 変更履歴の表示
$ git log

commit 4d91580973b8cfdd167930ee7b9d19e73bab9e78 (HEAD -> master)
Author: user_name <user_name@git.com>
Date:   Sat Jan 00 06:54:22 2000 +0000

    initial commit
    
    
# 1行表示 ※推奨
$ git log --oneline
4d91580 (HEAD -> master) initial commit


# 「git log」と「git diff」を同時に表示
$ git log -p
commit 4d91580973b8cfdd167930ee7b9d19e73bab9e78 (HEAD -> master)
Author: user_name <user_name@git.com>
Date:   Sat Jan 25 06:54:22 2020 +0900

    initial commit

diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..980a0d5
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+Hello World!

ファイル操作

はじめに

  • ファイル削除やファイル移動(名前変更)は「git add」ではなく専用コマンドで履歴が記録される
  • Git管理を行っている(「git add」をしている)ファイルが以降の操作の対象となる

ファイル削除:rm

  • 「ファイルの削除」と「リポジトリからの削除」を分けて考えるようにする
  • 「リポジトリの削除」はgit履歴を削除することをいう
In [ ]:
# **** 構文 ****

# ファイルごとの削除
# --- ファイルとgit履歴の両方を削除したい
$ git rm <ファイル名>
$ git rm -r <ディレクトリ名>

# オプション:--cached
# --- gitの記録は削除したいが、ファイルは残したい
$ git rm --cached <ファイル名>
In [ ]:
# **** ハンズオン:ファイルと履歴の削除 ****

# 準備:ステージに追加
$ git add test.txt


# 指定したファイルを削除
$ git rm test.txt
rm 'test.txt'


# ファイル一覧の確認
# --- ファイルが削除されている
$ ls


# ステータスの確認
# --- 削除した操作がステージに記録されている
$ git status -s
D  test.txt
In [ ]:
# **** ハンズオン:ファイルの履歴のみ削除 ****

# 指定したファイルを削除
# --- 「リポジトリからの削除」のみが行われる
$ git rm --cached test.txt
rm 'test.txt'


# ファイル一覧の確認
# --- ファイルは削除されていない
$ ls
test.txt


# ステータスの確認
# --- 削除した操作がステージに記録されている
$ git status -s
D  test.txt
?? test.txt

ファイル名の変更:mv

  • 本来はファイルの移動を行うコマンドだが、実質的にファイル名変更に使う
  • ファイル名を変更する場合は、「実体ファイル」と「git履歴」の両方を変更する必要がある
In [ ]:
# **** 構文 ****

# ファイルごとの移動
$ git mv <旧ファイル名> <新ファイル名>

# 以下の動作度同じ
$ git rm <旧ファイル名>
$ git add <新ファイル名>
In [ ]:
# **** ハンズオン ****

# 準備:ステージに追加
$ git add test.txt


# 準備:ステータスの確認
$ git status -s
A  test.txt


# ファイル名の変更
$ git mv test.txt test2.txt


# ファイル一覧の確認
# --- ファイル名が変更されている
$ ls
index2.html


# 変更状態を確認
$ git status -s
A  test2.txt

リモートからの取得

fetchとpullの違い

  • 「fetch」は、ローカルリポジトリにダウンロードするだけで、ワークツリーへの反映は行われない
  • 「fetch」は、「git merge」で別途ワークツリーに反映される必要がある
  • 「pull」は、ローカルリポジトリにダウンロードして、ワークツリーへの反映まで一気に行う

<pullの注意点>

  • 「pull」は、現在のマスターブランチにリモートリポジトリの内容を反映する(マージされてしまう)
  • 「pull」を行う前に、リモートリポジトリから統合するブランチをマスターブランチとして選択しておく必要がある
In [ ]:
# **** ハンズオン ****

# 現在のブランチの確認
$ git branch
* feature    現在のブランチ
  master     マージしたいブランチ

# (重要)ブランチの切り替え
# --- 現在のブランチをマージしたいブランチに切り替えておく
$ git checkout master

リモートから取得:fetch

  • リモートリポジトリの内容をローカルリポジトリにダウンロードする
  • ローカルリポジトリのリモート専用の場所に保存される(保存先:remote/リモート/ブランチ)
  • ワークツリーにはダウンロード内容は反映されない(「merge」コマンドで別途反映させる)
  • ※「fetch」は取ってくるという意味
In [ ]:
# **** 構文 ****

# リモートリポジトリを表示
$ git fetch <リモート名>
In [ ]:
# **** ハンズオン ****

# 準備 --------------------------------

# ワークツリーのファイル確認
$ ls
index.html


# リモートにファイル追加
# --- 通常は他のメンバーが更新したリモートリポジトリを取り込む
# --- Githubから直接作成(ファイル名:git_fetch.txt)


# リモートから取得 ---------------------

# リモートリポジトリの取得
# --- ローカルリポジトリにダウンロードされる
$ git fetch origin
remote: Enumerating objects: 4, done.


# 取得ファイルの確認 ---------------------

# 取得ファイルの保存場所の確認
# --- 「-a」はallの略
# --- 現在指定しているブランチには「※」が付いている
$ git branch -a
* master
  remotes/bak/master
  remotes/origin/master ここにリモートリポジトリから取得した情報が格納されている

# ブランチの切り替え
$ git checkout remotes/origin/master
Note: switching to 'remotes/origin/master'.


# ファイルの確認
# --- 「git_fetch.txt」が存在する
$ ls
git_fetch.txt


# ワークツリーに反映 ---------------------

# 反映先のブランチに切り替え
# --- 「merge」コマンドは現在選択しているブランチに統合されるため
$ git checkout origin/master

# 取得ファイルをワークツリーに反映
$ ls
index.html  git_fetch.txt

リモートから取得:pull

  • 「pull」は、リモートリポジトリから情報を取得して、マージまでを一度にすることができる
  • 「pull」は、現在自分がいるブランチに対してマージを行う(取得したリポジトリ名のブランチにマージするのではない)
  • 慣れるまでは、「fetch」+「merge」でやったほうが安全
In [ ]:
# **** 構文 ****

# リモートから情報を取得してマージする
$ git pull <リモート名> <ブランチ名>
$ git pull origin master

# 上記のコマンドは省略可能
$ git pull

# 上記のコマンドは以下のように書き換え可能
$ git fetch origin master
$ git merge origin/master
In [ ]:
# **** ハンズオン ****

# 準備 --------------------------------

# ワークツリーのファイル確認
$ ls
index.html

# リモートにファイル追加
# --- 通常は他のメンバーが更新したリモートリポジトリを取り込む
# --- Githubから直接作成(ファイル名:git_pull.txt)


# リモートから取得&ワークツリーに反映 ---------------------

# 現在のブランチの確認
# --- マージするブランチにいることを確認
$ git branch
  feature
* master

# 他のブランチにいたら「checkout」で移動
$ git checkout master

# リモートから取得&ワークツリーに反映
$ git pull origin master

# ワークツリーのファイル確認
# --- ファイルの追加が反映されている
$ ls
index.html  git_pull.txt

5 各種操作の取消し

はじめに

パターン

  • Gitでは取消しのコマンドとして、「reset」「checkout」「revert」の3種類がある
  • 「reset」「checkout」は混同しやすいが、「revert」は動作が明確に異なる

整理の仕方

  • 「コミットレベル」「ファイルレベル」の2つに分けて整理する
  • 「ワークツリー」「ステージ」「ローカルレポジトリ」の3つのセッションでも動作に違いが出る

参考資料

取消しのコマンド

reset

  • 指定したコミットIDまでHEADを移動して、それまでのコミットを削除する
  • リセットは3つのレベルで行われる
  • リセットを行うと必ずコミットの削除は発生し、HEADの移動が伴う

<リセットレベル>

  1. コミットの取消 (soft)
  2. ステージングの取消 (mixed)
  3. ファイル変更の取消 (hard)
In [ ]:
# **** 構文 ****

# コミットのみ取消
# --- ステージングとファイルの変更は維持
$ git reset --soft <コミットID>

# コミットとステージングを取消
# --- ファイルの変更は
$ git reset --mixed <コミットID>

# 全てを取消
# --- ファイルは削除される
$ git reset --hard <コミットID>

checkout

revert

  • 特定コミットの処理を打ち消すコミットを作成するためのコマンド
  • 「git log」などでコミットIDを調べておく必要がある

<処理の流れ>

  • 打ち消したいコミットの直前のコミットを指定
  • 直前のコミットを元に、打消対象の直後のコミットの内容でコミットする
In [ ]:
# **** 構文 ****

# 特定のコミットを打ち消すコミットを作成 
$ git revert <commit>

# 打ち消すだけでコミットは作成したくない場合
$ git revert -n <commit>

# マージコミットを打ち消す
$ git revert -m 1  <commit>

commit --amend

  • 直前のコミットはcommit --amendで追加&修正することができる

<Git Krakenの場合>

  • 修正したファイルをステージ追加する
  • コミットメッセージの横のチェックボックスををオンにする(直前のコミットメッセージがSummaryに入る)
  • コミットする
In [ ]:
# **** 構文 ****

# 直前のコミットを修正
$ git commit --amend

squash

  • 今回のコミットを直前のコミットにとまとめる場合にはsquashを用いる
  • 今回のコミットは削除される

<Git Krakenの場合>

  • 隣り合った2つのコミットをshiftキーを押しながら複数選択する
  • squash n commitを選択する
In [ ]:
# **** 構文 ****

# 直前のコミット
git merge --squash <branch or commit>


git rebase -i [commit]

「add」の取消し

一度もコミットしてない場合

  • リポジトリ自体がコミット経験がない場合(「add」の対象をコミットしたかではない)
  • コミットが一度も行われていない状態では「reset」が使えない
  • この場合は、「rm --cached」を使ってステージエリアの追加を削除することができる
In [ ]:
# **** 構文 ****

# ファイルの履歴のみを削除
$ git rm --cached <ファイル名>
In [ ]:
# **** ハンズオン ****

# --- 準備 ----------

# ステージに追加
$ git init

# 新規ファイル作成
$ touch test.txt

# ステータス確認
# --- ファイルがステージに追加されていない
$ git status -s
?? test.txt


# ステージに追加
$ git add test.txt

# ステータス確認
# --- ファイルがステージに追加されている
$ git status -s
A  test.txt


# --- ステージから取り消す ----------

# 履歴のみ削除
# --- ファイル自体は削除されない
$ git rm --cached test.txt
rm 'test.txt'

# ステータス確認
# --- ファイルがステージから削除されてGit管理から外れている
$ git status -s
?? test.txt

一度はコミットした場合

  • リポジトリ自体がコミット経験がある場合(「add」の対象をコミットしたかではない)
  • すでにコミットを行っている場合、HEADを戻すことでステージ追加(add)を取り消すことができる
  • 指定した変更をステージから取り消すだけでワークツリーには影響を与えない
  • 「HEAD」は今いるブランチの最新のコミットのことをいう

<Gitがやっていること>

  • 「ステージ」の状態を「直前のコミット」と同じ状態にする
  • これにより、ワークツリーの直前の変更を取り消すことができる
In [ ]:
# **** 構文 ****

# ファイルを元に戻す
# --- 最新のコミット(HEAD)の状態にリセットするという意味
$ git reset HEAD <ファイル名>

# ディレクトリを元に戻す
$ git reset HEAD <ディレクトリ名>

# 全変更を取り消す
$ git reset HEAD .
In [ ]:
# **** ハンズオン:環境準備 ****

# --- 準備1:最初のコミット ----------

# ステージに追加
$ git init

# 新規ファイル作成
$ touch test.txt

# ステージに追加
$ git add test.txt

# コミット
$ git commit -m "Initial Commit"
[master (root-commit) 03e45f0] Initial Commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt


# --- 準備2:別のファイルをステージに追加 ----------

# 新規ファイル作成
$ touch test2.txt

# ステージに追加
$ git add test2.txt

# ステータス確認
# --- ファイルが追加されている
$ git status -s
A  test2.txt
In [ ]:
# **** ハンズオン:ステージから取り消す ****

# HEADを一つ前に戻す
# --- ファイルを追加する前
$ git reset HEAD .

# ステータス確認
# --- ファイルがステージから削除されてGit管理から外れている
$ git status -s
?? test2.txt

「commit」の取消し

コミットを削除

In [ ]:
# **** 構文 ****

# 直前のコミットを取り消す
# --- ワーキングディレクトリの内容も書き換える
$ git reset --soft HEAD^

# 直前のコミットを取り消す
# --- ワーキングディレクトリの内容も書き換える
$ git reset --hard HEAD^
In [ ]:
# **** ハンズオン:準備 ****

# --- 準備1:最初のコミット ----------

# ステージに追加
$ git init

# 新規ファイル作成
$ touch test.txt

# ステージに追加
$ git add test.txt

# コミット
$ git commit -m "Initial Commit"
[master (root-commit) 03e45f0] Initial Commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt


# --- 準備2:2回目のコミット(取り消し対象) ----------

# 新規ファイル作成
$ touch test2.txt

# ステージに追加
$ git add test2.txt

# コミット
$ git commit -m "Second Commit"
[master (root-commit) 03e45f0] Initial Commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt


# --- 環境確認 ----------

# ログの確認
$ git log --oneline
78b3af3 (HEAD -> master) Second Commit
198f2bb Initial Commit
In [ ]:
# **** ハンズオン:--soft ****

# 直前のコミットの取り消し
$ git reset --hard HEAD^
HEAD is now at 198f2bb Initial Commit

# ログの確認
# --- コミット履歴が削除されている
$ git log --oneline
198f2bb (HEAD -> master) Initial Commit

# ファイル確認
# --- ファイルが存在する(直前の操作が保存されている)
$ ls
test.txt test2.txt
In [ ]:
# **** ハンズオン:--hard ****

# 直前のコミットの取り消し
$ git reset --hard HEAD^
HEAD is now at 198f2bb Initial Commit

# ログの確認
# --- コミット履歴が削除されている
$ git log --oneline
198f2bb (HEAD -> master) Initial Commit

# ファイル確認
# --- ファイルが削除されている(直前の操作も併せて取り消している)
$ ls
test.txt

コミットファイルを修正

  • 直前のコミットメッセージの修正はcommit --amendで行うことができる

<注意>

  • リモートリポジトリに「Push」した内容は修正することができない(コンフリクトが発生)
  • この場合は、新しいコミットを作成して再度リモートリポジトリに「Push」する(コミットを追加することで対応)

<Gitがやっていること>

  • 現在の「ステージ」の状態を元に「直前のコミット」を上書きしている
  • 直感どおりの操作となっている
In [ ]:
# **** 構文 ****

# 直前のコミットを修正
$ git commit --amend
In [ ]:
# **** ハンズオン ****

# --- 準備 ---

# ファイル内容の確認
$ cat test.txt
git commit

# ステージに追加
$ git add test.txt

# コミット
$ git commit -m "git commit --amend"
[master 5782cc7] git commit --amend
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt


# --- 準備 ---

# ファイル内容の修正
$ cat test.txt
git commit --amend

# ステージに追加
$ git add test.txt

# コミットの修正
$ git commit --amend -m "git commit --amend"
[master 3d96e07] git commit --amend
 Date: Sun Jan 26 07:44:18 2020 +0900
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt

コミットメッセージの修正

  • 直前のコミットメッセージの修正は「commit --amend」で行うことができる
  • コミットをやり直すだけなので、「add」は行う必要はない

<注意>

  • リモートリポジトリに「Push」した内容は修正することができない(コンフリクトが発生)
  • この場合は、新しいコミットを作成して再度リモートリポジトリに「Push」する(コミットを追加することで対応)

<Gitがやっていること>

  • 現在の「ステージ」の状態を元に「直前のコミット」を上書きしている
  • 直感どおりの操作となっている
In [ ]:
# **** 構文 ****

# 直前のコミットメッセージを修正
# --- エディタを使用
$ git commit --amend

# 直前のコミットメッセージを修正
# --- メッセージを直接入力
$ git commit --amend -m "メッセージ"
In [ ]:
# **** ハンズオン ****

# --- 準備:コミット ----------

# 新規ファイル作成
$ touch test.txt

# ステージに追加
$ git add test.txt

# コミット
$ git commit -m "Initial Commit"
[master (root-commit) 03e45f0] Initial Commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt


# --- 準備:コミットメッセージを修正 ----------

# コミットメッセージを修正
$ git commit --amend -m "Initial Commit Modify"
[master 728db75] Initial Commit Modify
 Date: Sat Jan 25 10:16:52 2020 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt

# ステータスの確認
$ git log --oneline
728db75 (HEAD -> master) Initial Commit Modify 修正されている

「push」の取消し

原則

  • リモートリポジトリにプッシュしたものは原則取り消せない(コンフリクトを誘発)
  • 新しく正しいものをコミットすることで対応

6 ブランチの操作

ブランチとは

概要

  • 並行して複数機能を開発するための仕組み
  • Gitで履歴管理を行う上で、ブランチは最低1つは必要となる
  • 最初のブランチはmasterという名前になっている(マスターブランチは削除しない)
  • ブランチごとに個別の機能(プロジェクト)を開発して、開発後にマスターブランチに統合(マージ)する

メリット

  • 「ブランチ」を作成することで複数開発と分離することができ、開発同ごとの影響を排除することができる
  • 開発が独立するような「プログラムの書き方」や「ブランチの区切り方」が必要となる

フォルダとブランチ

  • ブランチもフォルダと同様の概念なので、フォルダを作ることができる
  • test/test01というブランチを作成することができる
  • testはブランチではないので、あくまでtest/test01を操作する

コミットとの関係

  • 「コミット」は、ファイル更新のスナップショットを保存するとともに、親コミットとリンクされている
  • 「ブランチ」とは、コミットIDを記録したポインタことをいう(ブランチごとに作成される)
  • ブランチを作成した後は、ブランチごとにコミットが行われるようになる
  • 「HEAD」は、現在作業中のブランチを示すポインタ

基本操作

ブランチの作成:branch

  • 新しいブランチを作成する
  • 新しいブランチへの切り替えは行われない
  • 「git checkout -b」で新規のブランチを作成して、新規ブランチを選択した状態にすることもできる

<Gitがやってること>

  • 最終コミットを指したブランチ(ポインタ)を新規作成している
  • 現在いるブランチを示す「HEAD」には変化はない(新しいブランチへの切り替えは行っていない)

<GitKrakenの場合>

  • ブランチを作成したいコミットを選択して右クリックのcreate branch hereを選択する
  • 作成したブランチを選択checkoutする
  • 新しいブランチに変更を加えるとブランチが明確になる
In [ ]:
# **** 構文 ****

# ブランチの作成
# --- 直前コミットに対して行われる
$ git branch <ブランチ名>
$ git branch feature

# ブランチの作成
# --- コミットを指定して行う
$ git checkout -b <new_branch> <commit_hash>
In [ ]:
# **** ハンズオン ****

# 新しいブランチの作成
$ git branch new_branch

# ブランチの確認
$ git branch
  feature
* master
  new_branch   新規作成されている

ブランチの一覧:branch

  • ローカルに存在するブランチを表示する
  • ブランチには「ローカルで使用しているブランチ」と「リモートから取り込んだブランチ」の2種類がある
In [ ]:
# **** 構文 ****

# ローカルのブランチの確認
$ git branch

# オプション:-a
# --- リモートリポジトリから取得したブランチを含めて表示する
$ git branch -a
In [ ]:
# **** ハンズオン ****

# ローカルのブランチの確認
$ git branch
  feature
* master

# リモートのブランチを含めて表示する
# --- 「※」がついているのが現在いるブランチ
$ git branch -a
  feature
* master
  remotes/origin/feature
  remotes/origin/master

# 現在のブランチの確認(別の方法)
$ git log --oneline --decorate
6258bda (HEAD -> master) Merge branch 'master' of https://github.com/user_name/git_tutorial

ブランチの詳細:branch -v

  • ブランチがどのコミットと紐づいているかなどを確認する
  • リモートリポジトリとの紐づきも併せて確認できる
In [ ]:
# **** 構文 ****

# 現在のブランチの詳細情報
$ git branch -v

# 全ブランチの詳細情報
$ git branch -vva
In [ ]:
# **** ハンズオン ****

# 現在のブランチの詳細情報
$ git branch -v
  feature 8ae96dc featureを追記
* master  6258bda Merge branch 'master' of https://github.com/user_name/git_tutorial


# 全ブランチの詳細情報
$ git branch -vva
  feature                8ae96dc Commit Message
* master                 6258bda Merge branch 'master' of https://github.com/user_name/git_tutorial
  remotes/origin/feature 5bc791b Commit Message
  remotes/origin/master  f347e5b Commit Message

ブランチの削除:branch -d

  • ローカルブランチを削除する
  • まだマージされていないブランチを削除しようとするとエラーが出る
  • 「-D」オプションをつけると、まだマージされていないブランチも強制削除することができる
In [ ]:
# **** 構文 ****

# ブランチの削除(どちらでも可)
$ git branch --delete <ブランチ名>
$ git branch -d <ブランチ名>

# マージされていないブランチの強制削除
$ git branch -D <ブランチ名>
In [ ]:
# **** ハンズオン ****

# ブランチの削除
$ git branch -d new_branch
Deleted branch new_branch (was 6258bda).

# ブランチの確認
$ git branch
  feature
* master

ブランチ名の修正:branch -m

  • ローカルブランチのブランチ名を変更する
  • Pull Requestのissues番号を間違っていたときなどに活躍する
  • 「-m」はmoveの略語
In [ ]:
# **** 構文 ****

# ブランチ名の変更
$ git branch -m <古いブランチ名> <新しいブランチ名>

# 現在のブランチの名前変更
$ git branch -m <新しいブランチ名>
In [ ]:
# **** ハンズオン ****

# 準備:現在のブランチ確認
$ git branch
  feature
* master
  new_branch

# ブランチ名の変更
$ git branch -m new_branch new2_branch

# ブランチの確認
$ git branch
  feature
* master
  new2_branch

切り替え

ブランチの切替:checkout

  • 既存のブランチ間での切り替えを行う(HEADを切り替える)
  • 「-b」オプションで新規のブランチを作成して、新規ブランチを選択した状態にすることもできる
  • ブランチを切り替えることで、複数ブランチを使って複数プロジェクトで開発することができるようになる

<GitKrakenの場合>

  • 右サイドバーのLOCALに表示されているブランチの中で、切り替えたいブランチをダブルクリックする
  • アクティブなブランチには、ブランチ名の左側のチェックボックスにチェックが入る
  • ブランチを切り替えると、フォルダに表示されるファイルも切り替わる
In [ ]:
# **** 構文 ****

# ブランチの作成
$ git checkout <既存ブランチ名>
$ git checkout feature

# オプション:-b
# --- ブランチを新規作成して切り替える
# --- 「b」はbranchのことを意味する
$ git checkout -b <新ブランチ名>
In [ ]:
# **** ハンズオン ****

# 準備:ブランチの状況確認
$ git branch
* feature
  master

# ブランチの切り替え
$ git checkout master

# ブランチの状況確認
$ git branch
  feature
* master

ブランチ切替で行われてること

  • ブランチを切り替えると、同じディレクトリでも表示されるファイルが異なる
  • 実際にGUIで見ると、ブランチの切替でファイルが表示/非表示となって切り替わっている
  • ディレクトリ内のファイルは固定というイメージが強い人が多いので、少し奇妙に思えるかもしれない
  • これが、「ブランチをごとに開発を分岐する」ということである
In [ ]:
# **** ハンズオン ****

# featureブランチ ------------------

# ブランチの状況確認
$ git branch
* feature
  master
    
# 存在するファイル
$ ls
feature.html

# 参考:現在のブランチID
$ git log --oneline -n 1
8ae96dc (HEAD -> feature) featureを追記


# masterブランチ ------------------

# ブランチの切り替え
$ git checkout master

# ブランチの状況確認
$ git branch
  feature
* master
    
# 存在するファイル
# --- コマンド結果が変わるだけでなく、GUIで見えるファイルも変わっている
$ ls
master.html

# 参考:現在のブランチID
# --- ブランチIDが異なる点に注意
$ git log --oneline -n 1
6258bda (HEAD -> master) 

その他

ブランチのサブディレクトリ

  • ブランチにはサブディレクトリを作ることができる

7 ブランチの統合

マージとは

概要

  • マージは「合流」というイメージ
  • 「統合する側のブランチ(develop)」を「統合される側のブランチ(master)」に最新コミットを作って合流させる

リモートリポジトリとの関係

  • マージは「ローカル」と「リモート」のそれぞれのブランチに対して行うことができる
  • 以降では、「ローカル」「リモート」の区別にはフォーカスを当てずに進める
  • ただし、ここでは明示的に「merge」を行うことを想定しているので、「fetch」によるリモートの取込みとの相性が良い

3パターンのマージ

  • Fast Foward:早送りになるマージ
  • Auto Merge:基本的なマージ
  • Conflict

ブランチのマージ:merge

  • 作業ブランチを元のブランチに統合する

<GitKrakenの場合>

  • 統合される側のブランチ(master)を選択する
  • 統合する側のブランチ(develop)で右クリックメニューのを「Merge develop into master」を選択する
  • 統合する操作がマスターブランチの最新コミットとして記録される
In [ ]:
# **** 構文 ****

# ブランチの作成
$ git merge <統合する側のブランチ>

リベースとは

概要

  • リベースは「一本化」というイメージ
  • コミットを時系列順に、「統合する側のブランチ(develop)」を「統合される側のブランチ(master)」に一本化する
  • developブランチは統合されてしまい、もともと存在しなかったような仕上がりになる
  • masterブランチに統合のための最新ブランチが作成されることはない

リベースの注意点

  • リモートにプッシュしたコミットに対してリベースしてはいけない(コンフリクト発生)
  • リベースをするとその順番を事後的に変更していることになる
  • 結果として、リモートにプッシュしようとするとエラーとなる
In [ ]:
# **** 参考 ****

# リモートでコンフリクトが発生しても強制的にプッシュ
# --- 完全に履歴が壊れるので絶対NG
$ git push -f

ブランチのリベース:rebase

<GitKrakenの場合>

  • 統合される側のブランチ(master)を選択する
  • 統合する側のブランチ(develop)で右クリックメニューのを「Rebase develop into master」を選択する
  • 統合する側のブランチ(develop)が、統合される側のブランチ(master)の途中で統合される
In [ ]:
# **** 構文 ****

# ブランチの作成
$ git rebase <統合する側のブランチ>

チェリーピック

はじめに

  • 特定ブランチのコミットのみを別のブランチに反映させる操作
  • mergerebaseと異なり、ブランチを統合することはない

コンフリクト

ポイント

  • 「リベース」は「マージ」と比較するとコンフリクトが発生しやすい

リモートブランチ

リモートリポジトリ

  • Gitでは、開発メンバーとのプロジェクト共有をリモートリポジトリで行う
  • リモートリポジトリは、「GitHub」「GitLab」「Code Commit」などがあげられる
  • 開発メンバーの成果は「リモートリポジトリ」で管理され、メンバーは開発進捗を適宜ローカルに取り込む

ローカルでの管理

  • 「fetch」をするとリモートリポジトリの情報がローカルの「リモート/ブランチ」に保存される
In [ ]:
# **** ハンズオン ****

# リモートの取り込み
$ git fetch

# ブランチの確認
# --- リモートから取得したものも表示
$ git branch -a
* master
  remotes/origin/feature
  remotes/origin/master

リモートのマージ

  • 「merge」する際には、リモートリポジトリを参照先とすることができる
  • リモートリポジトリを統合する際は、基本的に「Auto Merge」となる
In [ ]:
# **** ハンズオン ****

# ブランチの確認
# --- リモートから取得したものも表示
$ git branch -a
* master
  remotes/origin/feature
  remotes/origin/master

# リモートのマージ
# --- 「remote/」はつけない
$ git merge origin/master

マージによる統合

変更内容を取り込む:merge

  • 作業中のブランチに他のブランチのマージが行われた上で、新しくコミットが行われる
  • ここでのマージの方法は「Fast Foward」と「Auto」の2種類がある(結合時のマスターブランチのコミットIDがポイント)
  • マージの種類にかかわらずコマンドは同じものとなる
In [ ]:
# **** 構文 ****

# ブランチの結合
# --- ローカルのブランチ
$ git merge <ブランチ名>

# ブランチの結合
# --- リモートから取得したブランチ
$ git merge <リモート名/ブランチ名>

マージ1:Fast Foward

  • 「master」から分岐したブランチを統合する際に、「master」のコミットIDが分岐時と同じだったら「Fast Foward」となる
  • 統合後のコミットIDは、開発ブランチのコミットIDを引き継ぐ
  • 出力コマンドに「Fast-forward」であることが明記される
In [ ]:
# **** ハンズオン ****

# ※以下のコマンドまでの流れは「ブランチを用いた開発」の「ローカルで完結した開発」を参照

# ブランチの統合
# --- 統合先の「master」のコミットが分岐時から更新されていない
$ git merge topic_1
Updating f6a6d41..1593ac4
Fast-forward   ※「Fast Fowardマージになっている

マージ2:Auto Merge

  • 「機能A」と「機能B」を開発するため「func_A」「func_B」というブランチを作成(分岐)する
  • 「機能A」と「機能B」の開発の進捗に応じて「master」ブランチが統合される
  • ポイントは、分岐時点から「master」がコミットをして状態が変化している点である
  • こちらのオートマージが 通常よく行われている
In [ ]:
# **** ハンズオン ****

# ※以下のコマンドまでの流れは「ブランチを用いた開発」の「ローカルで完結した開発」を参照

# ブランチの統合
# --- 統合先の「master」のコミットが分岐時から更新されている
$ git merge topic_2
Merge made by the 'recursive' strategy.   ※「Autoマージになっている

リベースによる統合

履歴を整えて統合:rebase

8 その他の管理

タグ付け

使いどころ

  • コミットを参照しやすくするために分かりやすい名前をタグとしてつけておく
  • リリースポイントを明示するのに使用されることが多い

タグの作成:tag -a

  • タグには「注釈付き(annotated)」と「軽量版(lightweight)」の2種類がある
  • 「注釈付き(annotated)」は、「タグ名」に加えて「署名」「メッセージ」を記述することができる(おすすめ)
  • 「軽量版(lightweight)」は、「タグ名」のみ記述することができる

<GitKrakenの場合>

  • タグをつけるコミットを選択して右クリック(Create tag here)を選択
  • 出現したボックスにタグ名を英数字で入力
  • 右クリックには「Create annotate tag here」もあり「脚注付きタグ」を作成することもできる
In [ ]:
# **** 構文 ****

# 現在コミットにタグ付け ------------------------

# 注釈付きタグの作成
# オプション:-a (annotateの略)
# オプション:-m (messageの略)
# --- 「-m」をつけない場合はエディタで入力することになる
$ git tag -a <タグ名> -m <メッセージ>

# 軽量版タグの作成
# オプション:なし
$ git tag <タグ名>


# 過去コミットにタグ付け ------------------------

# 注釈付きタグの作成
$ git tag -a <タグ名> -m <メッセージ>  <コミット名>

# 軽量版タグの作成
$ git tag <タグ名> <コミット名>
In [ ]:
# **** ハンズオン ****

# 現在のブランチの確認
$ git branch
  feature
* master

# 現在のコミットにタグをつける
$ git tag -a "20170528" -m "version 20170528"

タグ一覧の表示:tag

  • コミットはタグをつけることができる(リリースポイントの明示などに使用)
  • プロジェクトでつけたタグの一覧を確認することができる

<GitKrakenの場合>

  • タグにカーソールを当てて右クリック(Show/Hide all tags)で操作可能
  • 左サイドバーにも「TAGS」があるので、そちらでも同様に操作可能
In [ ]:
# **** 構文 ****

# ブランチの作成
$ git tag

# オプション:-l
# --- 文字列でパターンを指定してタグを表示
$ git tag -l "201705"
In [ ]:
# **** ハンズオン ****

# タグ一覧の表示
$ git tag
20170528

タグの詳細表示:show

  • コミットに付けたタグ一覧を表示する

<GitKrakenの場合>

  • 右クリックのメニューなどで操作可能
In [ ]:
# **** 構文 ****

# タグの詳細を表示
$ git show <タグ名>
In [ ]:
# **** ハンズオン ****

# タグの詳細表示
$ git show 20170528
tag 20170528
Tagger: user_name <user_name@git.com>
Date:   Sun Jan 19 18:17:30 2020 +0900

version 20170528+

commit 72da0c63c2b348a1b597dd80c1c2b838dcfde8b1 (HEAD -> master, tag: 20170528, origin/master)
Author: user_name <user_name@git.com>
Date:   Sun Jan 19 08:20:02 2020 +0900

タグの削除:tag -d

  • 作成したタグは自由に削除することができる

<GitKrakenの場合>

  • タグをつけるコミットを選択して右クリック(Delete tag Locally)を選択
  • 画面上部に確認メッセージが表示される(取消できないと警告あり)
In [ ]:
# **** 構文 ****

# 注釈付きタグの作成
$ git tag -d <タグ名>
In [ ]:
# **** ハンズオン ****

# 準備:ブランチの確認
# --- 削除するタグを持つブランチに移動しておく
$ git branch
  feature
* master

# タグの削除
$ git tag -d show
Deleted tag '20170528' (was 06216cc)

タグの変更

  • タグを直接的に修正するコマンドは存在しない
  • 「旧タグ」にから「新タグ」を作成してから、「旧タグ」を削除することで対応する
In [ ]:
# **** ハンズオン ****

# タグ一覧の確認
$ git tag
v2.0.0

# 新しいタグの追加
$ git tag v2.0.1 v2.0.0

# タグ一覧の確認
# --- 追加が反映されている
$ git tag
v2.0.0
v2.0.1    追加された

# 古いタグの削除
$ git tag -d v2.0.0
Deleted tag 'v2.0.0' (was 4d59bb8)

タグのリモート送信:push

  • タグをリモートに送信するには「git push」コマンドで別途指定する必要がある
  • Githubのプッシュ先のリポジトリの「release」にタグが反映される
In [ ]:
# **** 構文 ****

# タグ一覧の表示
$ git push <リモート名> <タグ名>

# オプション:--tags
# --- タグを一斉に送信する
$ git push origin --tags
In [ ]:
# **** ハンズオン ****

# 準備:現在のタグ一覧を確認
$ git tag
20170528

# タグをリモートリポジトリにプッシュ
$ git push origin 20170528

作業の一時避難

使いどころ

  • 作業途中でコミットしたくけど、別のブランチで作業しなければならない時に使用する
  • ワークツリーとブランチの作業ファイルを「stash」に一時避難する
  • ワークツリーとブランチの変更をなかったことにすることで、別のブランチへの切り替えが可能となる

<エラー事例>

  • ブランチAが作業途中でコミットできないときに、ブランチBを新たに作って切り替えようとする
  • しかし、コンフリクトが発生して切り替えができない

一時避難:stash

  • 作業の途中でコミットはしたくないが、別のブランチで作業をしなければならない時に使用する
  • 基本的にGit管理下にあるファイルのみを対象とする(管理外のファイルも含めることは可能)
  • 「stash」とは「隠す」という意味
In [ ]:
# **** 構文 ****

# 作業の一時避難(Git管理下にあるファイルのみ)
# --- saveは省略可能
$ git stash
$ git stash save

# 作業の一時避難(Git管理下にないファイルも含める)
$ git stash -u
In [ ]:
# **** ハンズオン:Git管理下のファイル ****

# ワークツリーの変更
# --- ファイル追加
$ touch git_stash.txt

# ステージ追加
$ git add git_stash.txt

# ステータス確認
# --- ステージに追加されている(Git管理下に置かれた)
$ git status -s
A  git_stash.txt

# 作業の一時避難
$ git stash
Saved working directory and index state WIP on master: 06216cc Merge branch 'master' of 
https://github.com/user_name/git_tutorial

# ステータス確認
# --- 表示なし(stashされた)
$ git status -s
In [ ]:
# **** ハンズオン:Git管理外のファイル ****

# ワークツリーの変更
# --- ファイル追加
$ touch git_stash_2.txt

# ステータス確認
# --- Git管理下に置かれていない
$ git status -s
?? git_stash_2.txt

# 作業の一時避難
$ git stash -u
Saved working directory and index state WIP on master: 06216cc Merge branch 'master' of 
https://github.com/user_name/git_tutorial

# ステータス確認
# --- 表示なし(stashされた)
$ git status -s

避難リストの表示:stash list

  • 過去の非難した作業の一覧を表示する
  • 避難作業は番号で管理されている(0から附番されて、直近の一時避難が0となる)
In [ ]:
# **** 構文 ****

# 一時避難の一覧表示
$ git stash list
In [ ]:
# **** ハンズオン ****

# 一時避難の一覧表示
$ git stash list
stash@{0}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
stash@{1}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
stash@{2}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial

非難した作業の復元:stash apply

  • 非難した作業は自由に復元することができる
In [ ]:
# **** 構文 ****

# 最新の作業を復元する
# --- ステージの状況は復元されない
$ git stash apply

# オプション:--index
# ステージの状況も併せて復元する
$ git stash apply --index

# 最新の作業を復元する
$ git stash apply <スタッシュ名>
In [ ]:
# **** ハンズオン ****

# ステータスの確認
# --- スタッシュ後で何もない状態
$ git status
On branch master
nothing to commit, working tree clean

# 避難した作業の復元
$ git stash apply
Already up to date!
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        git_stash_2.txt

# ステータスの確認
# --- スタッシュした状態が復元している
$ git status -s
?? git_stash_2.txt

非難した作業の削除:stash drop

In [ ]:
# **** 構文 ****

# 最新の作業を削除する
$ git stash drop

# 特定の作業を削除する
$ git stash drop <スタッシュ名>
$ git stash drop stash@{1}

# 全作業を削除する
$ git stash clear
In [ ]:
# **** ハンズオン ****

# 一時避難の一覧表示
$ git stash list
stash@{0}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
stash@{1}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
stash@{2}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
        
# 最新のスタッシュを削除する
$ git stash drop
Dropped refs/stash@{0} (469b9368e9f364a83ac574567339f94545b9bdf6)

# 一時避難の一覧表示
# --- 削除されたことを確認
$ git stash list
stash@{0}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial
stash@{1}: WIP on master: 06216cc Merge branch 'master' of https://github.com/user_name/git_tutorial

# 全てのスタッシュを削除する
$ git stash clear

# 一時避難の一覧表示
# --- 全て削除されたことを確認
$ git stash list

9 開発事例

ブランチを用いた開発

ポイント

  • 「master」ブランチをリリース用ブランチにして、開発はトピックごとにブランチを作成して進める
  • トピックブランチは「master」ブランチから派生して作られる
  • 「master」ブランチに初回コミットがあることが前提

ハンズオン:Git環境の構築

  • 開発環境をはじめから構築していく
  • ブランチの動きにフォーカスしてハンズオンを進める
In [ ]:
# **** ハンズオン ****

# Git管理の開始
$ git init

# リモートリポジトリの登録
$ git remote add origin https://github.com/user_name/git_tutorial.git

# ブランチの確認
# --- 何も表示されない
# --- 「master」ブランチで作業しているが、初回コミット前は明示的な表示はない
$ git branch

ハンズオン:初回コミット

  • トピックブランチはマスターブランチから派生して作成するので、「master」ブランチでの初回コミットが必須となる
  • マスターブランチのコミットIDと独立に開発が進められることに注目
In [ ]:
# **** ハンズオン ****

# Git環境に変化を与える
# --- ファイル作成
$ touch master.txt

# ステージに追加
$ git add master.txt

# 初回コミット
# --- 「master」ブランチにコミットしている
# --- トピックブランチはマスターブランチから派生するので、「master」ブランチでの初回コミットが必須
$ git commit -m "Initial commit"
[master (root-commit) f6a6d41] 

# ブランチの確認
$ git branch
* master

# ログの確認
$ git log --oneline -n 1
f6a6d41 (HEAD -> master, topic_2) Initial commit

ハンズオン:ブランチごとの開発

  • 「master」ブランチから派生したトピックブランチは、それぞれ別のコミットを作成して開発が行われる
  • ブランチの切り替えごとに、ディレクトリに表示されるファイルは異なる
In [ ]:
# **** ハンズオン:開発 ****

# ブランチを追加 ---------------------------------------

# ブランチの追加
$ git branch topic_1
$ git branch topic_2

# ブランチの確認
$ git branch
* master     マスターブランチ
  topic_1    開発ブランチ1
  topic_2    開発ブランチ2


# 「topic_1」ブランチで開発 -------------------------------------------

# ブランチの切替
$ git checkout topic_1
Switched to branch 'topic_1'

# ファイル作成
# --- 開発
$ touch topic_1.txt

# ステージに追加
$ git add topic_1.txt

# コミット
$ git commit -m "Add topic_1.txt"

# ログ確認
$ git log --oneline -n 1
1593ac4 (HEAD -> topic_1) Add topic_1.txt

# ファイル確認
$ ls
master.txt  topic_1.txt


# 「topic_2」ブランチで開発 -------------------------------------------

# ブランチの切替
$ git checkout topic_2
Switched to branch 'topic_2'

# ファイル作成
# --- 開発
$ touch topic_2.txt

# ステージに追加
$ git add topic_2.txt

# コミット
$ git commit -m "Add topic_2.txt"

# ログ確認
$ git log --oneline -n 1
37641b1 (HEAD -> topic_2) Add topic_2.txt

# ファイル確認
$ ls
master.txt  topic_2.txt

整理:ブランチごとのコミットID

  • 「master」ブランチから分岐した「topic_1」「topic_2」の各ブランチは独立したコミットIDが割り当てられている
  • これは、ブランチが独立して開発を進めていることを意味する
In [ ]:
# **** ハンズオン ****

# ログの確認
# --- コミットIDは動いていない(トピックごとに分岐して開発している)
$ git log --oneline -n 1

f6a6d41 (HEAD -> master) Initial commit
1593ac4 (HEAD -> topic_1) Add topic_1.txt
37641b1 (HEAD -> topic_2) Add topic_2.txt

ハンズオン:開発のマージ:topic_1

  • 「master」ブランチは、「topic_1」を分岐してから一度もコミットをしていない
  • 「topic_1」を「master」に統合する際は、「Fast Foward」マージとして扱われる
In [ ]:
# **** ハンズオン ****

# ブランチの確認
# --- 統合先となる「master」ブランチにいる
$ git branch
* master
  topic_1
  topic_2

# ファイル確認
# --- 他の開発のファイルは紛れ込んでいない
$ ls
master.txt

# ブランチの統合
$ git merge topic_1
Updating f6a6d41..1593ac4
Fast-forward   ※「Fast Fowardマージになっている

# ログの確認
# --- コミットIDがtopic_1のコミットIDと等しい(Fast-Fowardマージ)
$ git log --oneline -n 2
1593ac4 (HEAD -> master, topic_1) Add topic_1.txt
f6a6d41 Initial commit

# ファイル確認
# --- topic_1で作成したファイルが追加されている
$ ls
master.txt  topic_1.txt

ハンズオン:開発のマージ:topic_2

  • 「master」ブランチは、「topic_1」を統合する際にコミットを行っている
  • 「topic_2」を「master」に統合する際は、「Auto」マージとして扱われる
In [ ]:
# **** ハンズオン ****

# ブランチの確認
# --- 統合先となる「master」ブランチにいる
$ git branch
* master
  topic_1
  topic_2

# ファイル確認
# --- 他の開発のファイルは紛れ込んでいない
$ ls
master.txt  topic_1.txt

# ブランチの統合
$ git merge topic_2
Merge made by the 'recursive' strategy.   ※「Autoマージになっている

# ログの確認
# --- コミットIDがtopic_1のコミットIDと等しい(Fast-Fowardマージ)
$ git log --oneline
d23d0d1 (HEAD -> master) Merge branch 'topic_2'
37641b1 (topic_2) Add topic_2.txt
1593ac4 (topic_1) Add topic_1.txt
f6a6d41 Initial commit

# ファイル確認
# --- topic_2で作成したファイルが追加されている
$ ls
master.txt  topic_1.txt  topic_2.txt

整理:マスターブランチの状態

  • 「master」ブランチに「HEAD」が当たった状態になっている
In [ ]:
# **** ハンズオン ****

# ブランチの確認
# --- 統合先となる「master」ブランチにいる
$ git branch
* master
  topic_1
  topic_2

# ファイル確認
$ ls
master.txt  topic_1.txt  topic_2.txt

# ログの確認
$ git log --oneline
d23d0d1 (HEAD -> master) Merge branch 'topic_2'
37641b1 (topic_2) Add topic_2.txt
1593ac4 (topic_1) Add topic_1.txt
f6a6d41 Initial commit

ハンズオン:新たなブランチの追加

  • 新しいブランチの作成は「master」ブランチから行う
  • そのため、「master」ブランチにいることを確認してからブランチを作成する
In [ ]:
# **** ハンズオン ****

# ブランチの確認
# --- マスターブランチにいることを確認
$ git branch
* master
  topic_1
  topic_2

# 最新のマスターから新たなブランチを作成
$ git branch topic_3

# ブランチの切り替え
$ git checkout topic_3
  master
  topic_1
  topic_2
* topic_3

# コミットID
# --- topic_3でまだコミットしていないので、masterブランチのコミットIDを指している
$ git log --oneline
d23d0d1 (HEAD -> topic_3, master) Merge branch 'topic_2'
37641b1 (topic_2) Add topic_2.txt
1593ac4 (topic_1) Add topic_1.txt
f6a6d41 Initial commit

ハンズオン:新たなブランチで開発

  • 新たなブランチでコミットすると、マスターブランチと独立したコミットIDが割り当てられる
  • マスターへの統合の際は、masterのコミットIDが分岐時から更新されているかどうかで「Fast Foward」「Auto」が決まる
In [ ]:
# **** ハンズオン ****

# ブランチの確認
$ git branch
  master
  topic_1
  topic_2
* topic_3

# ファイル作成
# --- 開発
$ touch topic_3.txt

# ステージに追加
$ git add topic_3.txt

# コミット
# --- 新しいコミットIDが割当て
$ git commit -m "Add topic_3.txt"
[topic_3 e3384e7] Add topic_3.txt

# ログ確認
$ git log --oneline
e3384e7 (HEAD -> topic_3) Add topic_3.txt
d23d0d1 (master) Merge branch 'topic_2'
37641b1 (topic_2) Add topic_2.txt
1593ac4 (topic_1) Add topic_1.txt
f6a6d41 Initial commit


# ファイル確認
$ ls
master.txt  topic_1.txt  topic_2.txt  topic_3.txt

リモートを用いた開発

準備中

リベースを用いた開発

準備中

参考サイト

全体像

inserted by FC2 system