Skip to content

Instantly share code, notes, and snippets.

@yatemmma
Last active February 15, 2022 03:36
Show Gist options
  • Save yatemmma/6486028 to your computer and use it in GitHub Desktop.
Save yatemmma/6486028 to your computer and use it in GitHub Desktop.
git初心者への道 - お仕事で困らないレベルまでググっとします。

git初心者への道

まずやってみよう - コミットする、ログを見る、差分を見る

初登場するコマンド: init, add, commit, log, config, status, diff

もうちょっとやってみよう - helpを見る、履歴をたどる、.gitignore

初登場するコマンド: help, clean

やりなおしたり戻したりしてみよう - 修正を戻す、コミットを戻す、打ち消す

初登場するコマンド: reset, show, revert

ブランチをつくってみよう - ブランチを作る、マージする

初登場するコマンド: branch, tag, merge, cherry-pick, rebase

みんなでやろう - リモートリポジトリと同期する

初登場するコマンド: clone, push, pull, fetch

中級者への道

初登場するコマンド: stash, reflog, blame

LICENSE

git初心者への道 by yatemmma is licensed under a Creative Commons Attribution 3.0 Unported License. クリエイティブ・コモンズ・ライセンス

git初心者への道 Level 1

初登場するコマンド: init, add, commit, log, config, status, diff

0. インストールしよう

Mac

$ brew install git

Windows

1. やってみよう

$ mkdir git-lesson
$ cd git-lesson

ディレクトリを作成します。

$ git init

gitを使う準備はこれだけ。

$ echo "hello git" > hello.txt
$ git add hello.txt
$ git commit -m "やってみた"
$ git log

ファイルの追加を記録できました。簡単ですね。

git init で、ファイルの変更や履歴の情報をつかさどる「リポジトリ」が作成されます。 リポジトリは、.gitというディレクトリで管理されます。つまり.gitを削除するとリポジトリの情報は消えるということ。

2. ファイルを修正する

hello.txtを開いて修正してみましょう。 修正を記録するには下記のコマンドを実行します。

$ git add hello.txt
$ git commit -m "修正してみた"

ファイルの修正を記録できました。簡単ですね。

修正を記録し、履歴として参照できる状態にすることを、コミットすると言います。 commitの直前に行っているaddは、修正をコミットの対象に追加する、というニュアンスです。 addしていない修正は、commitを実行してもコミットされません。

3. ファイルを追加する

新しいファイルを作成しましょう。

$ echo "I am curry." > curry.txt

curry.txtをコミットします。

$ git add curry.txt
$ git commit -m "追加してみた"

新しいファイルをコミットできました。簡単ですね。

4. ファイルを削除をする

ファイルの削除をしましょう。

$ rm -i curry.txt

ファイルの削除をコミットします。

$ git rm curry.txt
$ git commit -m "削除してみた"

ファイルの削除がコミットできました。簡単ですね。

5. 修正履歴を確認する

$ git log

修正の履歴を確認する事ができます。

履歴が1ページにおさまらないときは、スペースで改ページ、qで終了します。 (git logやgit diffのpagerにはデフォルトでlessが設定されています。)

ログの見方

commit 29ef86453d24354e67b5f913999ad86adce9f092 ・・・①
Author: yatemmma <[email protected]> ・・・②
Date:   Mon Sep 9 00:10:19 2013 +0900 ・・・③

    やってみた ・・・④
  • ① Revision: いわゆるコミット番号です。修正の履歴を一意に特定するハッシュ値が割り振られます。
  • ② Author: 修正者の情報です。後述のconfigで設定できます。
  • ③ Date: コミットした時刻です。
  • ④ Message: コミットメッセージです。修正内容の概要を入力します。

6. 設定を変更する

コミット時のAuthorを変更してみましょう。

$ git config --global user.name yatemmma
$ git config --global user.email [email protected]

出力を色付けしてくれる設定もしておきましょう。

$ git config --global ui.color auto

あとは安全対策

$ git config --global push.default current

Windowsクライアントで改行のワーニングが出る場合は、

git config --global core.autocrlf false

設定を確認するには、-lオプションを使います。

$ git config -l --global

7. ステータスを確認する

$ git status

git statusで、現在の作業状況が確認できます。 ファイルの追加や削除、修正、addなどを行って、statusの出力がどう変わるかを確認しましょう。

statusの見方

# On branch master         ・・・①
# Changes to be committed: ・・・②
#   (use "git reset HEAD <file>..." to unstage)
#
#    modified:   hello.txt
#
# Changes not staged for commit: ・・・③
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	deleted:    c.txt
#	modified:   hello.txt
#
# Untracked files: ・・・④
#   (use "git add <file>..." to include in what will be committed)
#
#	a.txt
  • ① 作業ブランチです。ブランチについては後述します。
  • ② Changes to be committed: コミットする準備ができた修正です。addしたものですね。ステージングされてインデックス(後述)に登録された修正がリストアップされます(緑)。
  • ③ Changes not staged for commit: ステージングされていない、インデックス未登録のワーキングツリー(後述)の修正がリストアップされます(赤)。addする前の修正です。
  • ④ Untracked files: まだgitで管理する対象になっていない、新しいファイルがリストアップされます(赤)。

状態の遷移

git statusでは修正がどのように扱われている状態なのかを確認する事ができます。

ファイルに修正が行われコミットされるまでの間に、gitでは3つの状態をいったりきたりします。 commitの前にaddが必要なのはこのためです。イメージできるようにしましょう。

  • ワーキングツリー
    • 現在作業している実ファイルです。
  • インデックス
    • コミットするための情報を登録する場所を指します。インデックスに登録されたものだけがコミットされます。
  • ローカルリポジトリ
    • コミットの情報が記録される場所です。

7. 差分を確認する

ファイルを修正した状態で、コミットする前に差分を確認しましょう。

$ git diff

git diffで、ワーキングツリーとリポジトリとのファイルの差分、つまり修正の内容を確認する事ができます。 コミット前に、修正内容が間違っていないかどうか、差分をチェックする癖を付けましょう。

参考サイト

Git初心者に捧ぐ!Gitの「これなんで?」を解説します。 | KRAY Inc
http://kray.jp/blog/git-why-explanation/

[Mac] Mountain Lionへパッケージ管理「Homebrew」をインストールする手順のメモ | Tools 4 Hack
http://tools4hack.santalab.me/howto-mountainlion-install-homebrew.html


[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson1-md)

git初心者への道 Level 2

初登場するコマンド: help, clean

1. コマンドを調べる

$ git help
$ git help -a
$ git help <command>

何だっけ?と思ったら調べましょう。

$ git help help

2. configの種類

git configには下記の3種類の設定があります。

範囲 オプション ファイル
システム共通 --system /usr/local/etc/gitconfig
ユーザー毎 --global ~/.gitconfig
リポジトリ固有 --local (デフォルト) .git/config

設定はシステム->ユーザー->リポジトリの順で読み込まれ、同じ項目は後で読み込まれた設定が優先されます。

共通で使いたい設定は、git config --global user.name watashiとし、 リポジトリ個別で設定したいものはgit config user.name curryとオプション無しで指定すると良いでしょう。

ファイルを直接編集することでも設定を変更できます。

3. gitで管理しないファイルを指定する

gitで管理しない(コミット対象にしない)ファイルを指定するには、.gitignoreというファイルを作成します。 たとえば、Macが作成する.DS_Storeなどを除外するには、.gitconfigファイルを作成して、.DS_Storeと記述します。

代表的な言語、開発環境向けの.gitignoreのサンプルテンプレートがgithubから公開されています。MITライセンスです。

github/gitignore https://github.com/github/gitignore

また、gitは空のディレクトリを管理対象にしません。 空のディレクトリをコミットしておきたい場合は、.gitkeepという名前の空ファイルを作成しておく事が一般的です。

4. git管理外のファイルをクリアする

ビルドによる生成ファイルや、IDEの設定ファイルなどのゴミをクリアする場合は、git cleanを使用します。

$ git clean -fdx

5. addを省略してコミット

$ git commit -a

ワーキングツリーの修正をaddしてコミットしてくれます。 ただし、新規追加ファイルは個別にaddしてやる必要があります。

6. いろいろな差分の見方

$ git diff

ワーキングツリー と リポジトリの差分を表示します。

$ git diff --cached

インデックス と リポジトリの差分を表示します。

$ git diff HEAD

ワーキングツリー&インデックス と リポジトリの差分を表示します。

$ git diff -w

行単位ではなく、単語単位で差分表示します。

$ git diff <branchname>

特定のブランチとの差分を表示します。

7. 履歴をちょっとすっきり見る

$ git log --oneline --decorate

logが一行ですっきり表示されます。

git logにはいろいろと出力フォーマットを変更するオプションがあります。試してみましょう。

8. リビジョンを移動する

$ git log

ひとつ前のリビジョンの状態に戻りたいとします。

$ git checkout HEAD^

ファイルの状態が一つ前のコミットの状態に変わり、 git loggit statusの出力が変わったことが確認できると思います。

HEAD というのは、現在の作業ブランチの履歴の先頭を表す言葉です。
HEAD^ というのは、HEADからひとつ前のリビジョンを表します。
2つ前ならHEAD^^ もしくはHEAD~2 とします。

さらに、リビジョン番号を指定して移動することもできます。

$ git checkout b785bc2

git checkoutは、指定するリビジョンにワーキングツリーの状態を移動し、そこにHEADの印をつけます。HEADやmasterなどのブランチ名は、リビジョンにつけられた別名とも言えます。

基本的に、ワーキングリーにコミット前の修正が残っている場合、履歴を移動するcheckoutはできません。


[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson2-md)

git初心者への道 Level 3

初登場するコマンド: reset, show, revert

1. インデックスにaddしたものを戻す

$ git add .

修正をaddします。

あ!やっぱりやめたい。やり直したい。人生やり直したい。
gitは人は必ずミスをするという指針の元に設計されており、操作を取り消す方法が豊富に用意されています。

ただし、バージョン管理において、操作を取り消す=履歴を書き換える
ということが何を意味するのか、しっかり理解した上で作業してください。

インデックスへのaddを取りやめるには下記のコマンドを利用します。

$ git reset HEAD

ワーキングツリーの変更もクリアしたい場合は、--hardオプションを使います。

$ git reset --hard HEAD

--hard をつけるとクリアされてしまった修正は消えてしまうので注意です。

2. commitを戻す

commitまで変更できるのがgitのすごいところです。

commitを変更する=履歴を書き換える
ということが何を意味するのか、しっかり理解した上で作業してください。
大事な事なので2回言いました。

まず修正をコミットします。

$ git commit -m "どうせ消しちゃうんでしょ"

commitを戻すときも、git resetコマンドを使います。

$ git reset HEAD^

これで、ひとつ前のリビジョンまで戻り、差分はaddする前の状態になります。

他にも--soft ---hardオプションの挙動を比較してみましょう。

$ git reset --soft HEAD^
$ git reset HEAD^
$ git reset --hard HEAD^

3. 特定のリビジョンまで戻す

HEAD^ と同様に、リビジョン番号を指定する事でできます。

$ git reset <revision>

git checkoutとどう違うのでしょう。

$ git checkout  <revision>

git statusでブランチ名を確認するとよくわかります。ブランチ名の表記が違いますね。
git resetでは、戻した後の状態がブランチのHEADになります。
一方git chekoutでは、特定のリビジョンをHEADとして移動するだけです。

これで、add,commit,resetを使って、戻したりやり直したりができるようになりました。

4. 一つ前のコミットを修正する

あ、この修正忘れてた!いっけねぇ〜うっかり(・ω<)てへぺろ ということは良くあります。
そんなときは、直前のコミットを修正できる--amendオプションを使いましょう。

$ git add <filename>
$ git commit --amend

addされた修正が直前のコミットに含まれます。

コミットメッセージだけ変更したい場合は、addの無い状態でamendしましょう。

$ git commit --amend -m "メッセージ変えます"

注目したいのは、amendの前後で、リビジョン番号が変わっている事です。

$ git log -1

これは、直前のコミットが修正されたのではなく、
直前のコミットが新しいコミットに差し替えられた、という表現の方がイメージしやすいでしょう。

A---B---C---D
A---B---C   D
         \
          D'

履歴を書き換えるということが何を意味するのか、しっかり理解し(ry

5. 以前のコミットを打ち消す

特定のコミットの修正に問題があったため、元に戻したいことが良くあります。
しかしそのコミットはすでにいくつかリビジョンが以前のコミットであるときは、
コミットを 打ち消すgit revertを使います。

コミットの内容を見る場合は、git showなどを使います。

$ git show <revision>

指定したリビジョンの修正を打ち消す修正がコミットされます。プラマイゼロです。

$ git revert <revision>

git revertは自動でコミットされます。コミットしたくない場合は--no-commitオプションを使いましょう。

$ git revert --no-commit <revision>

6. 特定のファイルだけ指定のリビジョンに戻す

あるファイルだけ、指定のリビジョンの状態にしたいことも良くあります。 その場合はファイル名を引数にとって、git checkoutコマンドを実行します。

$ git checkout <revision> <filename>

参考サイト

git reset についてもまとめてみる - murankの日記 http://d.hatena.ne.jp/murank/20110327/1301224770


[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson3-md)

git初心者への道 Level 4

初登場するコマンド: branch, tag, merge, cherry-pick, rebase

1. ブランチを作る

ブランチを作ってみましょう。

$ git branch lesson master

作成したブランチに移動しましょう。

$ git checkout lesson

ブランチの一覧を確認しましょう。

$ git branch
* lesson
  master

何かコミットしてみましょう。

$ git commit -m "lessonブランチでコミット"

履歴を確認しましょう。

$ git log

元いたブランチ(master)に戻ってみましょう。

$ git checkout master

履歴を確認しましょう。

$ git log

masterブランチの履歴には、lessonブランチでコミットした履歴がありません。
このように、履歴の枝分かれさせて管理する事ができます。

A---B---C---D   master
             \
              E lesson

この時点では、masterブランチから派生したlessonブランチは、
masterブランチのコミットをすべて持っていることになります。 このような状態をfast-fowardといいます。

ここでmasterブランチに新しい修正(F)をコミットすると、
masterブランチには、lessonブランチが知らないコミットが履歴として追加されることになります。
このような状態をnon-fast-fowardといいます。

A---B---C---D---F   master
             \
              E     lesson

2. ブランチとは

ブランチとは、上記のように、履歴を分岐させて管理させる機能です。

開発を行う上で、ソースコードには様々な修正が加えられます。
機能追加、バグフィックス、検証用、ミス(!)などなど。

これらを一つの履歴で管理することを想像してください。無理ゲーですよね。
リリース版のソースコードに検証用のコードが入り、
Aの機能追加中にBの機能追加のコードが入り、
挙げ句の果てにはミスのあるコードが入り…

このような複雑な管理を安全に行うために、履歴を枝分かれさせ、ブランチとして個別の履歴を作ります。

A---B---C        リリースブランチ
     \
      D---E      開発ブランチ
     \
      F---G---H  機能追加ブランチ
           \
            I    機能追加ブランチからの派生ブランチ(検証用)

gitでのブランチの運用方法はいろいろ議論のあるところですが、
一般的な開発においては、Vincent Driessenさんの提唱する「A successful Git branching model」というブランチモデルが評判のようです。

A successful Git branching model >> nvie.com http://nvie.com/posts/a-successful-git-branching-model/

このモデルを導入する、git-flowというgitのプラグインも存在します。

git-flow cheatsheet http://danielkummer.github.io/git-flow-cheatsheet/index.ja_JP.html

3. ブランチを削除する

ブランチの削除を行います。

$ git branch -d <branchname>

4. ブランチ名を変更する

$ git branch -m <branchname> <newname>

5. ブランチのログや差分を見る

特定のブランチのログを確認します。

$ git log <branchname>

ブランチ間の差分を確認します。

$ git diff <branchA> <branchB>

6. tagをつける

ブランチ名というのは、履歴の枝につけられた名前です。
ブランチを移動するのは、単純にその履歴の先頭に移動するということ。

同様に、特定のリビジョンに名前を付ける事ができます。git tag コマンドを使います。

$ git tag <tagname> <revision>

たとえば、リリースリビジョンにバージョン名をつけて管理したりします。

$ git tag v1.1.0 460ac4

7. ブランチをマージする

マージという言葉は様々な用途で使われますが、
ブランチに別のブランチの変更を取り込む事をブランチのマージと言います。

A---B---C---D           master
             \
              E---F     lesson

masterブランチにlessonブランチの変更をマージする場合は、次のようにします。

$ git checkout master
$ git merge lesson

これで、lessonブランチの変更(E,F)が、masterの履歴に取り込まれ、masterブランチとlessonブランチは同じ履歴を持つ事になります。

A---B---C---D---E---F   master, lesson

8. 異なる履歴を持つブランチをマージする

異なる履歴を持つブランチ同士のマージを考えましょう。

A---B---C---D---G       master
             \
              E---F     lesson

前回のマージでは、lessonブランチの履歴に追加された修正を、masterブランチの先頭に追加するだけですみました。 では、masterブランチにも独自の修正(G)が追加されている場合はどうなるでしょう。

$ git checkout master
$ git merge lesson

マージの方法は同じです。

A---B---C---D---G---H   master
             \     /
              E---F     lesson

この場合、lessonブランチの修正(E, F)を、masterブランチにマージした(H)というコミットが追加されます。

masterブランチのログには、lessonブランチの修正(E,F)も含まれます。

$ git log --oneline
8a9bca6 H
dffdcb5 F
24ec04a G
128601a E
4b55f65 D
f1fda71 C
cab6f6b B
bc73968 A

ここで、次の操作を試してみましょう。

$ git checkout HEAD^
$ git checkout HEAD^^
$ git checkout <Fのリビジョン>

履歴の枝分かれがそのまま保持されている事が分かると思います。
git log で枝分かれの情報を確認するには、--graph オプションを使います。

$ git log --oneline --graph 
* 8a9bca6 H
|\
| * dffdcb5 F
* | 24ec04a G
| * 128601a E
|/
* 4b55f65 D
* f1fda71 C
* cab6f6b B
* bc73968 A

ブランチ名も表示したい場合は、--decorateオプションを追加しましょう。

9. コンフリクトを解決する

異なる履歴をマージする際、それぞれのブランチで同じ部分に修正があるとどうなるでしょう?

例えば次のようなテキストファイルに、ブランチA、ブランチBで修正を入れたとします。

テキストファイル.txt

hoge1
hoge2

ブランチAでの修正

hoge1
piyo
hoge2

ブランチBでの修正

hoge1
fuga
hoge2

このように、同じ部分に修正を入れた場合など、修正をどう反映すればよいかgitが判断できない場合を、
コンフリクト(競合)が発生するといい、gitはコンフリクトの解決をユーザにゆだねます。

$ git merge ブランチB
Auto-merging テキストファイル.txt
CONFLICT (content): Merge conflict in テキストファイル.txt
Automatic merge failed; fix conflicts and then commit the result.

statusを確認すると次のようになっています。

$ git status
# On branch ブランチA
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#         both modified:      テキストファイル.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

テキストファイル.txtを開いてみましょう。

hoge1
<<<<<<< HEAD
piyo
=======
fuga
>>>>>>> ブランチB
hoge2

これは、<<<<<<< HEAD から======= までの間が、自分自身(ブランチA)の変更、
======= から、>>>>>>> ブランチB までの間が、ブランチBの変更であるという状態を表しています。

piyoが正しいのか、fugaが正しいのか、それとも両方必要なのか、順番はどちらが上なのか、などの情報は、コードを書いている本人にしか分かりませんよね。

このような場合、ユーザが<<<<<<< HEAD などの記号を消し、正しい状態にしてコミットしてやる必要があります。

エディタで次のように修正し、コミットしましょう。

hoge1
piyo
fuga
hoge2
$ git commit -a

自動的に、マージしましたという旨のコミットメッセージが挿入されます。

ブランチ運用に、コンフリクトはつきものです。しかしながら、マージの際にあまりにたくさんのコンフリクトが発生すると、正確なマージが難しくなってきます。ブランチの粒度を小さくするなど、運用には工夫が必要です。

10. 特定のコミットだけをマージする

ブランチ同士のマージではなく、とある別のブランチの、特定のコミットだけを取り込みたいなーなんてこともあります。 その場合は、git cherry-pick を使います。つまみ食いですね。

$ git cherry-pick <revision>

マージの操作はブランチのマージと同様です。

11. 派生元のブランチの修正を取り込む

masterブランチから派生したlessonブランチで作業中、masterブランチに新しい修正(G)がコミットされました。

A---B---C---D---G       master
             \
              E---F     lesson

このとき、lessonブランチにも修正(G)を取り込みたいと思います。

git merge を使うと、次のように取り込む事ができます。

$ git checkout lesson
$ git merge master

このように、lessonブランチに、masterブランチをマージしたというコミットが追加されます。

A---B---C---D------G     master
             \      \
              E---F--H   lesson

さらに、ここからそれぞれのブランチに修正が入り、それを、今度はmasterブランチにマージすることを考えましょう。

A---B---C---D------G---J---K  master
             \      \     /
              E---F--H---I    lesson

非常に複雑になりますね。

gitにはgit rebase というコマンドがあります。

$ git checkout lesson
$ git rebase master

マージは、lessonブランチにmasterブランチの修正を追加する。というイメージでしたが、
rebaseは、masterブランチの先頭に、lessonの修正を追加し直す。というイメージです。

A---B---C---D---G       master
             \
              E---F     lesson
A---B---C---D---G           master
                 \
                  E'---F'   lesson

こうすることで、lessonブランチは最新の状態のmasterブランチから派生したことになり、履歴がスッキリしますね。

注目すべきは、rebase後のlessonブランチの履歴が、E'、F'となっていることです。
実際に異なるリビジョン番号が付与されていると思います。つまり、修正の内容は同じですが、異なるコミットとして反映されているという事です。

履歴を書き換えるということが何を意味するのか、しっかり理解した上で作業してください。

↑これですね。

rebaseでは何が行われているのかというと、
まず、Eの差分、Fの差分をpatchにします。
そして、masterの最新の履歴に、Eのpatch、Fのpatchの順にpatchを当てて行く作業を行います。
patchを当てるたびに、コンフリクトが発生する場合は解決の必要があります。

$ git rebase master
Eのpatch反映 -> コンフリクト発生 -> エディタで修正
$ git add .
$ git rebase --continue
Fのpathc反映 -> コンフリクト発生 -> エディタで修正
$ git add .
$ git rebase --continue

途中でわけがわからなくなって最初からやり直したい場合は、--abort オプションを指定します。

$ git rebase --abort

[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson4-md)

git初心者への道 Level 5

初登場するコマンド: clone, push, pull, fetch

1. リモートリポジトリの情報をとってくる

リモートリポジトリ?

これまで行ってきた操作は、自分のマシン内でローカルリポジトリに対して行ってきたものでした。
複数人でソース管理を行う場合、リポジトリの情報を共有する必要があります。そのときに使われるのがリモートリポジトリです。

リモートリポジトリは、複数の環境から参照できるサーバに置かれます。
社内サーバだったり、外部サーバだったり、GitHubやBitbucketなど、gitのリポジトリを提供するwebサービスも便利です。

そのリモートリポジトリの情報を、ローカルマシンに複製する場合は、git clone を使います。

$ git clone <repository>

たとえば、このテキストのリポジトリをcloneする場合は次のようにします。

$ git clone https://gist.github.com/6486028.git

6486028というフォルダに、gitのリポジトリが複製されたと思います。 フォルダ名を指定したい場合は、引数を追加しましょう。

$ git clone https://gist.github.com/6486028.git git_shoshinsha

ローカル環境でgit init とした時と同様に、gitのリポジトリが作られています。

2. ローカルリポジトリの情報をリモートリポジトリへ反映させる

では、手元で修正した内容を、リモートリポジトリへ反映し、メンバーと共有したいとします。
その場合はgit push コマンドを利用します。

$ git push origin lesson

lessonブランチの修正が、リモートリポジトリへ反映されました。

git push コマンドは、ローカルリポジトリの情報をリモートリポジトリへ反映させます。
引数無しで実行した場合、ローカルにあるブランチの修正すべてがリモートへ反映されることになります。

必ず引数にブランチを指定し、ブランチ単位でのpushを心がけましょう。

3. リモートリポジトリの情報をローカルリポジトリへもってくる

リモートリポジトリの更新をローカルリポジトリへ落とすには、git pull を使います。

$ git pull origin lesson

4. originって何?

さきほどからたびたび現れるorigin という単語は、何を意味しているのでしょうか。

$ git push origin lesson

じつはこれは、下記を省略した書き方なのです。

$ git push [email protected]:hogehoge/hoge.git lesson:lesson

[email protected]:hogehoge/hoge.git というリモートリポジトリに対して、 ローカルのlessonブランチをリモートのlessonブランチにpushする。という意味です。

毎回長ったらしいURLを指定するのは大変なので、originという名前を付けてあげよう。という感じです。
デフォルトでoriginという名前が使われます。他の名前にすることも可能です。

5. リモートリポジトリのブランチを削除する

リモートリポジトリのブランチを削除するにはこのように指定します。

$ git push origin :lesson

リモートのlessonブランチに対して、pushするブランチを未指定にしてやるというイメージです。
ちょっと変わった指定の仕方ですね。

6. リモートリポジトリの情報をローカルリポジトリへ反映させる その2

先ほどは、リモートの情報をとってくるのに、git pull コマンドを利用しました。

取得したリモートリポジトリの情報は、トラッキングブランチと呼ばれる場所に格納されます。
リモートリポジトリとの同期用データの置き場所の用なものです。

トラッキングブランチを参照するにはorigin/masterのように指定します。

$ git log origin/lesson

ブランチの一覧を確認するには、-a オプションを使います。

$ git branch -a

リモートリポジトリの情報をローカルリポジトリのトラッキングブランチに反映させるには、git fetch コマンドを使います。

$ git fetch

git pull では、作業ブランチの状態もリモートの状態で更新されましたが、git fetch では、 トラッキングブランチが更新されるだけなので、作業ブランチの状態はそのままです。

作業ブランチの状態をトラッキングブランチと同期させるためには、git reset コマンドを使います。

$ git reset --hard origin/lesson

7. pushできない時の対処法

git push コマンドは、ローカルリポジトリの情報をリモートリポジトリへ反映させます。

pushするまでの間に、リモートリポジトリに別のメンバーの修正が反映されてしまうと、履歴のコンフリクトが発生します。
履歴のコンフリクトが発生するような状況では、pushはできません。

一度最新のリモートリポジトリの情報を取ってきて、そこにローカルの修正を加え直してからpushする必要があります。

ただし、rebaseなど履歴を書き換える操作を行った場合、履歴のコンフリクトは避けられません。 このような場合は、強制的にローカルの履歴をpushする必要があります。--force(-f) オプションを使います。

$ git push --force origin lesson

--force オプションは、その名の通りリモートリポジトリを強制的に書き換えます。非常に強力な操作です。

誤ったコミット履歴を消し去ることもできれば、メンバーが一生懸命作ってきたソースコードを全消しすることもできます。
使用は十分に注意し、なるべく--force オプションを使わなくてもよい運用を心がけるべきでしょう。

8. git status のメッセージを読み解く

同期が撮れている場合。

$ git status
# On branch master
nothing to commit (working directory clean)

ローカルの履歴が進んでいる場合。
リモートの情報(トラッキングブランチ origin/master)に対して、ローカルが1コミット分進んでいるというメッセージです。
ローカルのコミットをpushして反映します。

$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

リモートの履歴が進んでいる場合。
リモートの情報(トラッキングブランチ origin/master)に対して、ローカルが1コミット分遅れているというメッセージです。
fast-forwardで追いつく事が可能です。pullすると追いつきます。

$ git status
# On branch master
# Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
#
nothing to commit (working directory clean)

それぞれに異なるコミットがある場合。 リモートとローカルが分岐している(non-fast-foward)であるというメッセージです。 この場合、履歴のコンフリクトを解決してやる必要があります。

$ git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 1 different commit each, respectively.
#
nothing to commit (working directory clean)

[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson5-md)

git中級者への道

初登場するコマンド: stash, reflog, blame

1. gitコマンドのショートカットを設定する

git config でaliasを設定すると、gitコマンドのショートカットを設定する事ができます。

$ git config --global alias.co "checkout"
$ git config --global alias.ci "commit -a"

入力を短縮し、ガンガン生産性をアップしましょう。

エイリアスの短縮コマンドは自由につけてかまいませんが、
subversionのコマンドに合わせてつけるのが一般的のようです。
.gitconfig alias でweb検索するといろいろな参考情報が出てきます。

オススメをいくつか上げておきます。

st = status -sb
l = log --color --pretty=\"format:%Cgreen%ai%Creset %h %Cred(%an):%Creset%C(yellow)%d%Creset %s\" -40

参考サイト

dotfiles/.gitconfig at master · yatemmma/dotfiles https://github.com/yatemmma/dotfiles/blob/master/.gitconfig

天下一gitconfig大会
https://gist.github.com/teppeis/4117588

2. gitコマンド、ブランチ名の補完を有効にする

git-compilation というgit公式の拡張機能があります。

https://github.com/git/git/tree/master/contrib/completion

これをシェルに読み込ませると、gitコマンドやブランチ名がtabキーで補完されるようになります。 また、プロンプトに現在のブランチ名を表示することも可能になります。超benryです。

以下はMac(Homebrewインストール)の.bashrcサンプルです。

# prompt
. /usr/local/etc/bash_completion.d/git-prompt.sh
. /usr/local/etc/bash_completion.d/git-completion.bash
GIT_PS1_SHOWDIRTYSTATE=true
export PS1='\[\e[1;33m\]\W\[\033[0;31m\]$(__git_ps1)\[\033[00m\]\$ '

こんな感じ。

git_shoshinsha (master *)$ 

3. git browse-remote

Git リポジトリの Web サイト (GitHub とか) を簡単に開けるコマンドを作った - NaN days - subtech http://subtech.g.hatena.ne.jp/motemen/20120917/1347889804

ターミナルから現在のリポジトリのGitHubページをブラウザで開ける神ツール。

4. 作業ブランチ以外のブランチをpushしないようにする対策

$ git config --global push.default current

これをやっておけば、git push しても作業ブランチしかpushされません。
でも安全のため、git push origin <branchname> とする習慣をつけましょう。

参考サイト

引数なしのgit pushは危険なので気をつけましょう - DQNEO起業日記 http://dqn.sakusakutto.jp/2012/10/git_push.html

5. 修正をいったん退避する

あるブランチで作業中に、他のブランチに切り替えて動作検証しなくちゃいけなくなったりと、
作業中のコミット前の修正を退避しておきたいことがよくあります。そんなときはgit stash が便利。

$ git stash save "メッセージ"

取り出して適用する。退避時と違うブランチでもOK。

$ git stash pop

退避一覧。

$ git stash list

参考サイト

transitive.info - git stash 使い方
http://transitive.info/article/git/command/stash/

6. resetやらamendをやっぱりやめる

gitの便利代表格でもあるresetコマンド、amendコマンドですが、やっぱりやめれば良かった!と思う事もなきにしもあらずです。
特に--hard オプションをつけたときのやってしまった感は非常につらいものがあります。

push前なら、git reset コマンドでトラッキングブランチにresetしてやればOKです。

$ git reset --hard origin/<branchname>

しかしpushしてしまった後では、トラッキングブランチにも反映済み。resetはできません。

そんなときは、git reflog を実行してみましょう。

$ git reflog

HEADがどのように移り変わってきたのかの記録が参照できます。
これで、履歴から外れてしまったコミットも見つけ出す事ができ、reset前に戻る事も可能です。

なお、次のコマンドでさらに詳細な情報が得られます。

$ git log -g

参考サイト

gitでアレを元に戻す108の方法 - TIM Labs
http://labs.timedia.co.jp/2011/08/git-undo-999.html

7. 直前の作業ブランチに戻る

$ git checkout -

8. pullでrebaseする

git pull した際にリモートの履歴が進んでいると、自動的にマージされます。 --rebase オプションをつけておくと、マージではなくrebaseしてくれます。

$ git pull --rebase

9. コミットをまとめる

無駄なコミットログは残すべきではありません。push前にコミットログの精査をすると、
いくつかのコミットをまとめたいことがよくあります。

私はまとめてresetしてからcommitし直すのが好きですが、rebaseを使う方法もあります。

$ git rebase -i HEAD~3

HEADから3つ分のコミットを編集します。

pick 42462d4 コミットB
pick 58706a3 コミットC
pick c6a77c4 コミットD

pick の部分をsquach に変更すると、そのコミットは一つ前(上)のコミットに統合されます。

順番を入れ替えたりすることも可能です。

参考サイト

gitのコミットの歴史を改変する(git rebase) 1 / 2 - けんごのお屋敷 http://tkengo.github.io/blog/2013/05/16/git-rebase-reference/ http://tkengo.github.io/blog/2013/06/08/git-rebase-reference2/

10. マージをやっぱりやめる

マージして動作確認したら動かなかった。そんなときでも大丈夫。そうgitならね。

$ git reset --hard ORIG_HEAD

ORIG_HEAD にはマージ前のリビジョンが保持されています。ORIG_HEADにresetすることで元にもどすことが可能です。

このような変数は他にも、FETCH_HEAD, MERGE_HEAD, CHERRY_PICK_HEAD などがあります。

11. 犯人探しする

hoge.m になんだか良く分からないメソッドeatCurryが追加されていたとします。
コードを読んでも意図が分からず・・・ そんなときはコミットログから修正時の情報を読み取ります。

$ git blame hoge.m

git blame コマンドを使うとファイルの各行に対する最新のコミットを参照する事ができます。

しかしそのコミットがフォーマットの修正などによるもので、 eatCurry コマンドが追加されたときのコミットでは無かった場合、もっと過去の履歴を探す必要があります。

git log-S オプションを使うと、その文字列が最初に追加されたコミットを参照できます。

$ git log -S --patch "eatCurry" hoge.m

じっちゃんはいつも一つ!

参考サイト

見えないチカラ: 【翻訳】あなたの知らないGit Tips
http://keijinsonyaban.blogspot.jp/2010/11/git-tips.html

あまり知られていないGitのTips - アジャイルSEを目指すブログ http://d.hatena.ne.jp/sinsoku/20111206/1323104408

図で分かるgit-mergeの--ff, --no-ff, --squashの違い - アジャイルSEを目指すブログ
http://d.hatena.ne.jp/sinsoku/20111025/1319497900

チーム開発に必要なgit コマンドを神速で習得しよう! - 酒と泪とRubyとRailsと http://morizyun.github.io/blog/how-to-git-review-book/


[INDEX](https://gist.github.com/yatemmma/6486028#file-git-lesson-md) | [TOP](https://gist.github.com/yatemmma/6486028#file-git-lesson6-md)
@d00fy
Copy link

d00fy commented Sep 6, 2017

thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment