Git

Gitの概観とコマンド(初級レベル)

Gitについて人に説明する機会があったので、概観をまとめました。

既にGitの文献やサイトでたくさん解説されていますが、詳細(正確さ)追求しすぎると、かえってわかりにくい説明になりがちなので、大きくはずさない程度にざっくりかいてみます。

■■■全体■■■

Gitは自分のPCの中にリポジトリを作って変更管理ができるところが嬉しいところ。

ある程度、自分のPCの中でソースコードを育てたらリモート(クラウドなどにある)リポジトリにアップロードするというのがGit流のやりかた。

git_repo_arch00.png

ざっくりとした作業のながれ

↓こんな感じ

全体図
repo_arch_anim.gif

■■リモートリポジトリとローカルリポジトリ間のやりとり■■

全体図の右側から2つに注目したのが下の図。リモートリポジトリとローカルリポジトリの間のやりとりはこんな感じです。
青字はGitコマンド。

git_local_remote_repo_01.png

まず良く出てくるキーワードの整理から。

originとは

originとはリモートリポジトリの名前、デフォルトでこの名前がつく。それだけ知っていれば何も難しいことはない。

masterとは

これも最初にリポジトリを作るとできるデフォルトのブランチ名。これも何も難しいことはない。

masterには常に安定版に入れようとか、「ふだんの開発はトピックブランチなる別ブランチを作って品質確認した後でmasterブランチにマージしよう」のような運用のルールや慣例はある。
運用の考え方的にはSVNでいうところのtrunkに近いイメージ。

fetchとは

リモートリポジトリにあるブランチをリモート追跡ブランチまでダウンロードしてくる。
(ダウンロード=最新の履歴を取得する)

git fetch
  • 上コマンドでは、リモートリポジトリにあるすべてのブランチをダウンロードしてくる。
  • 勘違いしやすいのは、git fetch --allで、こちらはすべてのリモートリポジトリをダウンロードしてくる。

特定のブランチだけあえてfetchしたければブランチ名を指定する

git fetch origin master
  • 上のコマンドでは、originというリモートリポジトリにあるmasterブランチをローカルのリモート追跡ブランチにダウンロードしてくる。

mergeとは

リモート追跡ブランチからローカルブランチに差分を取り込む。

git merge origin/master
  • 上のコマンドでは、origin/masterをmasterに取り込む。

origin/masterとは

originという名前のリモートリポジトリのmasterブランチをローカル(つまり自分のPC)にコピーしたものを指す呼び名。このブランチは、リモート側にある最新を追いかけているから、リモート追跡ブランチ

このブランチの指定の方法はいくつかある。
origin/masterのかわりにremotes/origin/masterとしてもOK。
フルネームだとrefs/remotes/origin/masterとなる、これを指定してもOK。

pullとは

git fetchとgit mergeを同時に行うコマンド。
(git fetchとgit mergeを別々にやりたがる人が多い。私はpull使い派。)

git pull

git fetchとgit mergeを別にやったときと同様、内部的にfetchしているときはリモートのすべてのブランチをダウンロードした後に、現在のブランチとのマージとなる。

下図は再掲

git_local_remote_repo_01.png

pushとは

ローカルブランチの変更をリモートブランチに反映(アップロードする)する。

git push

diffとは

図の各所に示したが、2つの対象間の差分をみる。

■■ローカルリポジトリと作業ディレクトリの間のやりとり■■

git_local_remote_repo_02.png

作業用のディレクトリで編集したファイルをコミット(ローカルリポジトリに反映)するには、まず git addでコミット候補のファイルを指定する。その後にgit commitでコミットする。

addとcommitを同時にやりたいときはgit commit -amというコマンドを使う。

以上、概観はこんな感じです。

■■■シーン別Gitコマンド■■■

■■あるフォルダをgit管理下にする■■

あるフォルダをgit管理下にする

そのフォルダに移動して以下を実行

git init

ファイルをgitでトラックする

そのフォルダにあるすべてのファイルをgit管理下におく

git add -A

改行コードを自動変換しない(autoCRLF)

Windows版gitをデフォルトインストールしている場合は autoCRLFなので注意

.gitフォルダを開いて、configというファイルに以下を追記する
bash
autoCRLF = false

■■GITの状態・設定■■

現在のステータス表示

  • 前回のcommitからの差分表示
git status
  • config情報の表示
git config --list

GITエディタ設定

  • エディタをterapadにする(vi系苦手なwinユーザー向け)
git config --global core.editor "'C:\Program Files (x86)\TeraPad\TeraPad.exe' //cu8" 

■■ブランチ■■

ブランチの表示

  • 現在のブランチ(=自分が今編集しているブランチ)を表示する。*印が現在のブランチ
git branch

* master
  • リモートも含めた現在のブランチを表示
git branch -a

* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

ブランチ作成、ブランチ選択(チェックアウト)

  • リモートリポジトリのorigin/topic2ブランチをtopic2という名前のローカルブランチとして作成する。
git branch topic2 origin/topic2

Branch topic2 set up to track remote branch topic2 from origin.
  • topic2というローカルブランチを選択する(作業するブランチを切り替える)。topic2をチェックアウトする、という。
git checkout topic2
  • 上の2つを一度にやるのが↓のコマンド。つまり、リモートリポジトリのorigin/topic2をローカル側にダウンロードしてきて、かつ、そのブランチの選択する、ところまでを以下のコマンドで一発でできる。
git checkout -b topic2 origin/topic2

ブランチの新規作成/削除

  • topic1というローカルブランチを作成して、そのブランチを選択
git checkout -b topic1
Switched to a new branch 'topic1'
  • topic1というブランチを作成
git branch topic1
  • topic1というブランチを削除
git branch -d topic1

Deleted branch topic1 (was a4e4a05).
  • topic1というブランチを強制削除
git branch -D topic1
  • topic1というブランチを選択
git checkout topic1

Switched to branch 'topic1'

ブランチをマージ

  • まずmasterブランチにもどる
git checkout master
  • topic1をmasterにマージする –no-ff オプションを つけてマージコミットをのこす。fast-forwardできる場合はコミット履歴が残らないが、このオプションをつけるとfast-forwardできる場合でもあえてコミット履歴を残す動作となる。
git merge --no-ff topic1

ブランチをPUSH

  • 編集したブランチをリモートリポジトリに新たにPUSHする。 リモートリポジトリにも同名のブランチtopic1でpushする(名前を変えてももちろんOK)
git push –u origin topic1

■■コミット■■

コミット

  • コミットをする前に、どのファイルをコミットするか指定するためにgit addする。addされたファイルはステージ領域(インデックス)というコミット待ちの領域に追加される
git add -u

-uオプションで、変更があったファイルやフォルダと、削除されたファイルやフォルダをすべてステージ領域に追加する。詳しくは後述。

  • (ステージしたファイルを) topic1ブランチにコミットする
git commit -m “change something”
  • git addとgit commitを1コマンドでやる。 commit対象ファイルはgit管理されているファイル
git commit -am “change something”

addのコマンドバリエーション

git add -A

git add -Aは以下をステージ領域に追加
- 新規追加されたファイルやフォルダ
- 変更があったファイルやフォルダ
- 削除されたファイルやフォルダ


git add -u

git add -uは以下をステージ領域に追加
- 変更があったファイルやフォルダ
- 削除されたファイルやフォルダ

■■reset ~コミットを無かったことに~■■

ある時点のcommitに戻る

  • commitログを表示する
git log --graph

| |
| * commit 2c4d8f2dc95b4fa50dac35d03f9facfb77d336b8
|/  Author: John Doe<jj@example.com>>
|   Date:   Fri Oct 27 22:48:29 2017 +0900
|
|       Add osaka
|
* commit a4e4a054dfe9322a84b8d075db4b751038b9ba1a
| Author: John Doe<jj@example.com>>
| Date:   Fri Oct 27 22:08:22 2017 +0900
|
  • commitログをonelineで表示する
git log --oneline --graph
  • あるcommitまで戻る
git reset --hard a4e4a054dfe9322a84b8d075db4b751038b9ba1a

HEAD is now at a4e4a05 Add tokyo
  • 今編集している内容を無かったことにする (前回コミット以降に変更した分を、前回コミット相当の状態に戻す)
git reset --hard
  • 直前のcommitを取り消す(HEADを1つ前に移動し、そのほかの(addとワークツリー)変更をすべて戻す)
git reset --hard HEAD^
  • 直前のcommitを取り消す(HEADだけを1つ前に移動し、ステージとワークツリーはそんまま)
git reset --soft HEAD^

これまでHEADが辿った位置の変遷

  • HEAD位置の変遷をみる
git reflog

9e84eb9 HEAD@{0}: commit (amend): Fix conflict and merge
adb8e69 HEAD@{1}: commit (merge): Fix conflict
1aed162 HEAD@{2}: reset: moving to HEAD@{5}
a4e4a05 HEAD@{3}: checkout: moving from topic2 to master

  • あるcommitまで戻る
git reset --hard HEAD@{3}

リセットを間違えた

  • 直前のreset操作を取り消す
git reset --hard ORIG_HEAD

Gitでトラックしていないファイルも消す

git clean -f -d

■■revert ~コミットを打ち消す■■

直前のcommitを打ち消す

  • 直前のcommit打消しするcommitを実行する
git revert HEAD
  • 複数のcommitを打ち消すcommitをつくる。 -n オプションをつけるとcommitを実行しないでstageまでの巻き戻しになる。 つまり、以下のように複数の-nつきrevertをしたあとに、commitすれば複数巻き戻しが1回のcommitで済む
git revert –n <commitId>
git revert –n <commitId>
git revert –n <commitId>
git commit

■■コンフリクト解消■■

PUSH時のエラー

  • ローカルブランチをPUSHしようとしたら既にリモートブランチ側が更新されていた場合 以下のようになったら

image.png
⇒git fetch をして、まずリモートの最新をfetchする

  • ローカルブランチをPUSHしようとしたら、non-fast-forward だった場合、

image.png
⇒git mergeをする

マージ時のエラー

  • リモートブランチとローカルブランチをmergeしようとしたら CONFLICTを起こしていた場合
git merge

Auto-merging src/main/java/com/example/quick/App.java
CONFLICT (content): Merge conflict in src/main/java/com/example/quick/App.java
Automatic merge failed; fix conflicts and then commit the result.

選択肢その1

コンフリクトしている部分を適宜修正した後、commit

image.png

選択肢その2

(とりあえず)mergeコマンド実行前の状態にもどす

git reset --hard HEAD

■■PUSH■■

ローカルブランチをPUSH

  • 現在の編集中のブランチをリモートリポジトリにPUSHする (現在設定されているこのローカルブランチの upstreamブランチにpushされる)
git push
  • pushするまえにまず、今自分がどのブランチで作業しているか確認する
git status

On branch topic3
Your branch is ahead of 'origin/topic3' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean
  • 現在のブランチがどのupstreamブランチに設定されているか
git branch -vv

Upstreamブランチが設定されていないときのPUSH

  • まだローカルブランチしかなくて、Upstreamブランチが設定されていない場合はUpstreamブランチを設定
git push --set-upstream origin topic2

Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (9/9), 581 bytes | 0 bytes/s, done.
Total 9 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/xxxxxx/mytest.git
 * [new branch]      topic2 -> topic2
Branch topic2 set up to track remote branch topic2 from origin.

(類似コマンド再掲)ブランチをPUSH

  • 編集したブランチを新たなリモートリポジトリにPUSHする リモートリポジトリにも同名のブランチtopic1でpushする (名前を変えてももちろんOK)
git push –u origin topic1

Upstreamブランチを確認する

  • ローカルブランチがトラッキングしているorigin側のブランチ(=upstream) を確認する
git branch –vv

 master 9aecd10 [origin/master] Add third
  topic1 d0a5383 Add 1-chome
* topic2 0b04311 Add test3.txt
  topic3 310ee29 [origin/topic3: behind 1] Fix conflict

■■topicブランチで開発したコードをmasterにpushする手順■■

トピックブランチで作業した後、masterにマージする

1.(リモートリポジトリ側にもtopicブランチがあるような場合)
リモートリポジトリのブランチを取得し、ローカルリポジトリにブランチを作る

git fetch
git checkout -b topic3 origin/topic3

2.topic3ブランチにmasterをマージする

git merge master

3.各種変更を加えコミットする

git commit –am “something”

4.(念のため)変更しているあいだにmasterが変わったかもしれないので、もういちどmergeしてもいい。

git fetch
git merge master

5.ローカルリポジトリの変更をリモートリポジトリのtopic3ブランチに反映してもいい。
(PUSHの後、何も指定していないが、その場合は設定されているupstreamブランチにpushされる)

git push

6.ブランチをmasterに切り替える(ねんのためpullしてもいい)

git checkout master

7.masterにtopic3をマージする –no-ff オプションをつけてfast-forwardでもcommitのログをのこす
(これを省略すると、HEADが移動するだけとなり、どこでマージしたかわからない)

git merge topic3 --no-ff
  • ■■ローカルリポジトリと作業ディレクトリの間のやりとり■■
  • ■■■シーン別Gitコマンド■■■
  • ■■あるフォルダをgit管理下にする■■
  • ■■GITの状態・設定■■
  • ■■ブランチ■■
  • ■■コミット■■
  • ■■reset ~コミットを無かったことに~■■
  • ■■revert ~コミットを打ち消す■■
  • ■■コンフリクト解消■■
  • ■■PUSH■■
  • ■■topicブランチで開発したコードをmasterにpushする手順■■