git初心者への道 - お仕事で困らないレベルまでググっとします。
初登場するコマンド: init, add, commit, log, config, status, diff
初登場するコマンド: help, clean
初登場するコマンド: reset, show, revert
初登場するコマンド: branch, tag, merge, cherry-pick, rebase
初登場するコマンド: clone, push, pull, fetch
初登場するコマンド: stash, reflog, blame
git初心者への道 by yatemmma is licensed under a Creative Commons Attribution 3.0 Unported License.
初登場するコマンド: init, add, commit, log, config, status, diff
$ brew install git
$ 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を削除するとリポジトリの情報は消えるということ。
hello.txtを開いて修正してみましょう。 修正を記録するには下記のコマンドを実行します。
$ git add hello.txt
$ git commit -m "修正してみた"
ファイルの修正を記録できました。簡単ですね。
修正を記録し、履歴として参照できる状態にすることを、コミットすると言います。 commitの直前に行っているaddは、修正をコミットの対象に追加する、というニュアンスです。 addしていない修正は、commitを実行してもコミットされません。
新しいファイルを作成しましょう。
$ echo "I am curry." > curry.txt
curry.txtをコミットします。
$ git add curry.txt
$ git commit -m "追加してみた"
新しいファイルをコミットできました。簡単ですね。
ファイルの削除をしましょう。
$ rm -i curry.txt
ファイルの削除をコミットします。
$ git rm curry.txt
$ git commit -m "削除してみた"
ファイルの削除がコミットできました。簡単ですね。
$ git log
修正の履歴を確認する事ができます。
履歴が1ページにおさまらないときは、スペースで改ページ、q
で終了します。
(git logやgit diffのpagerにはデフォルトでlessが設定されています。)
commit 29ef86453d24354e67b5f913999ad86adce9f092 ・・・①
Author: yatemmma <yatemmma@gmail.com> ・・・②
Date: Mon Sep 9 00:10:19 2013 +0900 ・・・③
やってみた ・・・④
コミット時のAuthorを変更してみましょう。
$ git config --global user.name yatemmma
$ git config --global user.email yatemmma@gmail.com
出力を色付けしてくれる設定もしておきましょう。
$ git config --global ui.color auto
あとは安全対策
$ git config --global push.default current
Windowsクライアントで改行のワーニングが出る場合は、
git config --global core.autocrlf false
設定を確認するには、-l
オプションを使います。
$ git config -l --global
$ git status
git status
で、現在の作業状況が確認できます。
ファイルの追加や削除、修正、addなどを行って、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
git status
では修正がどのように扱われている状態なのかを確認する事ができます。
ファイルに修正が行われコミットされるまでの間に、gitでは3つの状態をいったりきたりします。 commitの前にaddが必要なのはこのためです。イメージできるようにしましょう。
ファイルを修正した状態で、コミットする前に差分を確認しましょう。
$ 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
初登場するコマンド: help, clean
$ git help
$ git help -a
$ git help <command>
何だっけ?と思ったら調べましょう。
$ git help help
git config
には下記の3種類の設定があります。
範囲 | オプション | ファイル |
---|---|---|
システム共通 | --system | /usr/local/etc/gitconfig |
ユーザー毎 | --global | ~/.gitconfig |
リポジトリ固有 | --local (デフォルト) | .git/config |
設定はシステム->ユーザー->リポジトリの順で読み込まれ、同じ項目は後で読み込まれた設定が優先されます。
共通で使いたい設定は、git config --global user.name watashi
とし、
リポジトリ個別で設定したいものはgit config user.name curry
とオプション無しで指定すると良いでしょう。
ファイルを直接編集することでも設定を変更できます。
gitで管理しない(コミット対象にしない)ファイルを指定するには、.gitignore
というファイルを作成します。
たとえば、Macが作成する.DS_Storeなどを除外するには、.gitconfigファイルを作成して、.DS_Store
と記述します。
代表的な言語、開発環境向けの.gitignoreのサンプルテンプレートがgithubから公開されています。MITライセンスです。
github/gitignore https://github.com/github/gitignore
また、gitは空のディレクトリを管理対象にしません。
空のディレクトリをコミットしておきたい場合は、.gitkeep
という名前の空ファイルを作成しておく事が一般的です。
ビルドによる生成ファイルや、IDEの設定ファイルなどのゴミをクリアする場合は、git clean
を使用します。
$ git clean -fdx
$ git commit -a
ワーキングツリーの修正をaddしてコミットしてくれます。 ただし、新規追加ファイルは個別にaddしてやる必要があります。
$ git diff
ワーキングツリー と リポジトリの差分を表示します。
$ git diff --cached
インデックス と リポジトリの差分を表示します。
$ git diff HEAD
ワーキングツリー&インデックス と リポジトリの差分を表示します。
$ git diff -w
行単位ではなく、単語単位で差分表示します。
$ git diff <branchname>
特定のブランチとの差分を表示します。
$ git log --oneline --decorate
logが一行ですっきり表示されます。
git log
にはいろいろと出力フォーマットを変更するオプションがあります。試してみましょう。
$ git log
ひとつ前のリビジョンの状態に戻りたいとします。
$ git checkout HEAD^
ファイルの状態が一つ前のコミットの状態に変わり、
git log
やgit status
の出力が変わったことが確認できると思います。
HEAD
というのは、現在の作業ブランチの履歴の先頭を表す言葉です。
HEAD^
というのは、HEADからひとつ前のリビジョンを表します。
2つ前ならHEAD^^
もしくはHEAD~2
とします。
さらに、リビジョン番号を指定して移動することもできます。
$ git checkout b785bc2
git checkout
は、指定するリビジョンにワーキングツリーの状態を移動し、そこにHEAD
の印をつけます。HEADやmasterなどのブランチ名は、リビジョンにつけられた別名とも言えます。
基本的に、ワーキングリーにコミット前の修正が残っている場合、履歴を移動するcheckoutはできません。
初登場するコマンド: reset, show, revert
$ git add .
修正をaddします。
あ!やっぱりやめたい。やり直したい。人生やり直したい。
gitは人は必ずミスをするという指針の元に設計されており、操作を取り消す方法が豊富に用意されています。
ただし、バージョン管理において、操作を取り消す=履歴を書き換える
ということが何を意味するのか、しっかり理解した上で作業してください。
インデックスへのaddを取りやめるには下記のコマンドを利用します。
$ git reset HEAD
ワーキングツリーの変更もクリアしたい場合は、--hard
オプションを使います。
$ git reset --hard HEAD
--hard
をつけるとクリアされてしまった修正は消えてしまうので注意です。
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^
HEAD^
と同様に、リビジョン番号を指定する事でできます。
$ git reset <revision>
git checkout
とどう違うのでしょう。
$ git checkout <revision>
git status
でブランチ名を確認するとよくわかります。ブランチ名の表記が違いますね。
git reset
では、戻した後の状態がブランチのHEADになります。
一方git chekout
では、特定のリビジョンをHEADとして移動するだけです。
これで、add
,commit
,reset
を使って、戻したりやり直したりができるようになりました。
あ、この修正忘れてた!いっけねぇ〜うっかり(・ω<)てへぺろ ということは良くあります。
そんなときは、直前のコミットを修正できる--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
特定のコミットの修正に問題があったため、元に戻したいことが良くあります。
しかしそのコミットはすでにいくつかリビジョンが以前のコミットであるときは、
コミットを
打ち消すgit revert
を使います。
コミットの内容を見る場合は、git show
などを使います。
$ git show <revision>
指定したリビジョンの修正を打ち消す修正がコミットされます。プラマイゼロです。
$ git revert <revision>
git revert
は自動でコミットされます。コミットしたくない場合は--no-commit
オプションを使いましょう。
$ git revert --no-commit <revision>
あるファイルだけ、指定のリビジョンの状態にしたいことも良くあります。
その場合はファイル名を引数にとって、git checkout
コマンドを実行します。
$ git checkout <revision> <filename>
git reset についてもまとめてみる - murankの日記 http://d.hatena.ne.jp/murank/20110327/1301224770
初登場するコマンド: branch, tag, merge, cherry-pick, rebase
ブランチを作ってみましょう。
$ 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
ブランチとは、上記のように、履歴を分岐させて管理させる機能です。
開発を行う上で、ソースコードには様々な修正が加えられます。
機能追加、バグフィックス、検証用、ミス(!)などなど。
これらを一つの履歴で管理することを想像してください。無理ゲーですよね。
リリース版のソースコードに検証用のコードが入り、
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
ブランチの削除を行います。
$ git branch -d <branchname>
$ git branch -m <branchname> <newname>
特定のブランチのログを確認します。
$ git log <branchname>
ブランチ間の差分を確認します。
$ git diff <branchA> <branchB>
ブランチ名というのは、履歴の枝につけられた名前です。
ブランチを移動するのは、単純にその履歴の先頭に移動するということ。
同様に、特定のリビジョンに名前を付ける事ができます。git tag
コマンドを使います。
$ git tag <tagname> <revision>
たとえば、リリースリビジョンにバージョン名をつけて管理したりします。
$ git tag v1.1.0 460ac4
マージという言葉は様々な用途で使われますが、
ブランチに別のブランチの変更を取り込む事をブランチのマージと言います。
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
異なる履歴を持つブランチ同士のマージを考えましょう。
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
オプションを追加しましょう。
異なる履歴をマージする際、それぞれのブランチで同じ部分に修正があるとどうなるでしょう?
例えば次のようなテキストファイルに、ブランチ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
自動的に、マージしましたという旨のコミットメッセージが挿入されます。
ブランチ運用に、コンフリクトはつきものです。しかしながら、マージの際にあまりにたくさんのコンフリクトが発生すると、正確なマージが難しくなってきます。ブランチの粒度を小さくするなど、運用には工夫が必要です。
ブランチ同士のマージではなく、とある別のブランチの、特定のコミットだけを取り込みたいなーなんてこともあります。
その場合は、git cherry-pick
を使います。つまみ食いですね。
$ git cherry-pick <revision>
マージの操作はブランチのマージと同様です。
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
初登場するコマンド: clone, push, pull, fetch
リモートリポジトリ?
これまで行ってきた操作は、自分のマシン内でローカルリポジトリに対して行ってきたものでした。
複数人でソース管理を行う場合、リポジトリの情報を共有する必要があります。そのときに使われるのがリモートリポジトリです。
リモートリポジトリは、複数の環境から参照できるサーバに置かれます。
社内サーバだったり、外部サーバだったり、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のリポジトリが作られています。
では、手元で修正した内容を、リモートリポジトリへ反映し、メンバーと共有したいとします。
その場合はgit push
コマンドを利用します。
$ git push origin lesson
lessonブランチの修正が、リモートリポジトリへ反映されました。
git push
コマンドは、ローカルリポジトリの情報をリモートリポジトリへ反映させます。
引数無しで実行した場合、ローカルにあるブランチの修正すべてがリモートへ反映されることになります。
必ず引数にブランチを指定し、ブランチ単位でのpushを心がけましょう。
リモートリポジトリの更新をローカルリポジトリへ落とすには、git pull
を使います。
$ git pull origin lesson
さきほどからたびたび現れるorigin
という単語は、何を意味しているのでしょうか。
$ git push origin lesson
じつはこれは、下記を省略した書き方なのです。
$ git push git@github.com:hogehoge/hoge.git lesson:lesson
git@github.com:hogehoge/hoge.git
というリモートリポジトリに対して、
ローカルのlessonブランチをリモートのlessonブランチにpushする。という意味です。
毎回長ったらしいURLを指定するのは大変なので、originという名前を付けてあげよう。という感じです。
デフォルトでoriginという名前が使われます。他の名前にすることも可能です。
リモートリポジトリのブランチを削除するにはこのように指定します。
$ git push origin :lesson
リモートのlessonブランチに対して、pushするブランチを未指定にしてやるというイメージです。
ちょっと変わった指定の仕方ですね。
先ほどは、リモートの情報をとってくるのに、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
git push
コマンドは、ローカルリポジトリの情報をリモートリポジトリへ反映させます。
pushするまでの間に、リモートリポジトリに別のメンバーの修正が反映されてしまうと、履歴のコンフリクトが発生します。
履歴のコンフリクトが発生するような状況では、pushはできません。
一度最新のリモートリポジトリの情報を取ってきて、そこにローカルの修正を加え直してからpushする必要があります。
ただし、rebaseなど履歴を書き換える操作を行った場合、履歴のコンフリクトは避けられません。
このような場合は、強制的にローカルの履歴をpushする必要があります。--force(-f)
オプションを使います。
$ git push --force origin lesson
--force
オプションは、その名の通りリモートリポジトリを強制的に書き換えます。非常に強力な操作です。
誤ったコミット履歴を消し去ることもできれば、メンバーが一生懸命作ってきたソースコードを全消しすることもできます。
使用は十分に注意し、なるべく--force
オプションを使わなくてもよい運用を心がけるべきでしょう。
同期が撮れている場合。
$ 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)
初登場するコマンド: stash, reflog, blame
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
git-compilation というgit公式の拡張機能があります。
これをシェルに読み込ませると、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 *)$
Git リポジトリの Web サイト (GitHub とか) を簡単に開けるコマンドを作った - NaN days - subtech http://subtech.g.hatena.ne.jp/motemen/20120917/1347889804
ターミナルから現在のリポジトリのGitHubページをブラウザで開ける神ツール。
$ 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
あるブランチで作業中に、他のブランチに切り替えて動作検証しなくちゃいけなくなったりと、
作業中のコミット前の修正を退避しておきたいことがよくあります。そんなときはgit stash
が便利。
$ git stash save "メッセージ"
取り出して適用する。退避時と違うブランチでもOK。
$ git stash pop
退避一覧。
$ git stash list
transitive.info - git stash 使い方
http://transitive.info/article/git/command/stash/
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
$ git checkout -
git pull
した際にリモートの履歴が進んでいると、自動的にマージされます。
--rebase
オプションをつけておくと、マージではなくrebaseしてくれます。
$ git pull --rebase
無駄なコミットログは残すべきではありません。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/
マージして動作確認したら動かなかった。そんなときでも大丈夫。そうgitならね。
$ git reset --hard ORIG_HEAD
ORIG_HEAD にはマージ前のリビジョンが保持されています。ORIG_HEADにresetすることで元にもどすことが可能です。
このような変数は他にも、FETCH_HEAD, MERGE_HEAD, CHERRY_PICK_HEAD などがあります。
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/