git コマンド

バージョン管理ね。

HOWTO

カラフルにログを見るには

1コミット1行表示でコミットツリーを見るのに自分がよく使っている方法。

$ git log --graph --date-order --branches --pretty=format:"%Cblue%h %d %Cgreen%ai %Cblue%ae %Creset%s"

diffでインデントなどの空白の違いを無視するには

以下のオプションを git diff に付ける。このオプションは普通のdiffコマンドと同じ。

-b
連続する空白の長さの違いは無視する
-w
-b と同じだが、空白の定義がこっちのほうが広い。タブとか?

diffで差分表示を前後3行ではなくもっとたくさんの行を表示するには

デフォルトでは差分のある行の前後3行ずつまで表示されるが、これをもっと広い範囲で表示させたい場合には、 -U というオプションで行数を指定する。

前後10行表示させる例

$ git diff HEAD~1..HEAD -U10

diffでリネームされたファイルを表示されないようにするには

$ git diff --cached --find-renames

リモートにあってローカルにはないブランチをチェックアウトするには

$ git checkout -b <branch-name> origin/<branch-name>

ローカルにはすでに存在せずリモートに残っているブランチを削除するには

$ git push origin :<branch-name>

ローカルに残っているリモート追跡用のブランチを削除するには

リモートで削除されているブランチがあり、それらのリモート追跡用ブランチをまとめて削除するには

$ git fetch --prune

または

$ git fetch --prune origin

特定のリモートブランチだけ fetch を介さずに直接削除するには

$ git branch -d -r origin/<branch-name>

-d-D にする必要はないみたい。

リモートブランチ名がoriginでない場合は、originのところはその名前にする。

まだコミットしていない修正を一時保存しておいて、最後のコミットの状態に戻すには

$ git stash save 名前

これで、最後にコミットした状態に戻る。この状態で他のブランチをチェックアウトしたり、別の修正をしてコミットしたりできる。

git stash save する前の状態に戻すには、

$ git stash pop

または、後ろに名前をつけて、

$ git stash pop stash@{0}

のようにする。git stash save で1つしか保存していない場合は、git stash pop の後になにもつけなくてもよい。

pop すると、保存してあった状態は削除される。削除せずに適用だけしたい場合は、

$ git stash apply

または、後ろに名前をつけて、

$ git stash apply stash@{0}

のようにする。

2つ以上ある場合は、popapply も名前で識別する必要があるり、以下の一時保存した修正のリストで確認できる。

$ git stash list

git stash save したときの名前が popapply で使えない理由がわからない。

git stash save では差分を保存するので、別のブランチに移動してから git stash pop すると、そのブランチに対して差分を適用するので、まったく同じ状態に戻るわけではない。

stashに保存されている修正の差分を見るには、

$ git stash show -p

または、後ろに名前をつけて、

$ git stash show -p stash@{0}

stashに保存されている修正を削除するには、

$ git stash drop

または、後ろに名前をつけて、

$ git stash drop stash@{0}

いろいろと元に戻す方法

Git のさまざまなツール - 歴史の書き換え
http://git-scm.com/book/ja/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E6%AD%B4%E5%8F%B2%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88
git rebase, git filter-branch について

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

gitで共用リポジトリにpushした変更を取り消す
http://d.hatena.ne.jp/shunsuk/20101202/1291278345

リモートリポジトリのブランチをチェックアウトする方法
http://yoshimov.com/?page=Git%2F%A5%EA%A5%E2%A1%BC%A5%C8%A5%D6%A5%E9%A5%F3%A5%C1%A4%CE%CA%D1%B9%B9

リモートリポジトリのブランチを削除する方法
http://d.hatena.ne.jp/strkpy/20090719/1247970185

間違ってコミットしてしまったときにやり直すための各種方法
http://d.hatena.ne.jp/idesaku/20091106/1257507849

前回コミットした時の状態に戻す方法
http://d.hatena.ne.jp/mickey24/20081022/1224668137

前回のコミットを取り消す方法
[http://es.sourceforge.jp/projects/setucocms/wiki/Git%E9%96%8B%E7%99%BA%E4%B8%AD%E3%81%AEGit%E6%93%8D%E4%BD%9C%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9#h3-.E7.B7.A8.E9.9B.86.E5.BE.8C.E3.80.81.E8.AA.A4.E3.81.A3.E3.81.A6.E3.82.B3.E3.83.9F.E3.83.83.E3.83.88.E3.81.97.E3.81.A6.E3.81.97.E3.81.BE.E3.81.A3.E3.81.9F.E3.81.A8.E3.81.8D.E3.80.81.E3.82.B3.E3.83.9F.E3.83.83.E3.83.88.E3.82.92.E5.8F.96.E3.82.8A.E6.B6.88.E3.81.99.EF.BC.88git.20reset.20.28–soft.29.20HEAD.EF.BC.89](http://es.sourceforge.jp/projects/setucocms/wiki/Git%E9%96%8B%E7%99%BA%E4%B8%AD%E3%81%AEGit%E6%93%8D%E4%BD%9C%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9#h3-.E7.B7.A8.E9.9B.86.E5.BE.8C.E3.80.81.E8.AA.A4.E3.81.A3.E3.81.A6.E3.82.B3.E3.83.9F.E3.83.83.E3.83.88.E3.81.97.E3.81.A6.E3.81.97.E3.81.BE.E3.81.A3.E3.81.9F.E3.81.A8.E3.81.8D.E3.80.81.E3.82.B3.E3.83.9F.E3.83.83.E3.83.88.E3.82.92.E5.8F.96.E3.82.8A.E6.B6.88.E3.81.99.EF.BC.88git.20reset.20.28–soft.29.20HEAD.EF.BC.89)

特定のコミットでの差分をいまの作業ディレクトリに適用するには

$ git diff コミットハッシュ~..コミットハッシュ | patch -p1

でも、これだと新規ファイル作成があった場合にパーミッションは引き継がれない。

git clone のときに作成されるディレクトリの名前を指定するには

clone の2つ目の引数にディレクトリを指定する。

$ git clone git://github.com/foo/bar.git hoge

これで hoge というディレクトリが作られる。

無視するファイルをみんなで共有せずに自分のディレクトリにだけ設定するには

.git/info/exclude.gitignore と同じフォーマットで書けば、自分のワーキングディレクトリにだけ無視ファイルを設定できる。自分のディレクトリにだけ一時的に何かファイルを置きたい場合などに使える。

~/.ssh/config をgit専用に設定するには

環境変数 GIT_SSH を使用する。

http://qiita.com/items/c397370862095c305cbe

gitの過去のログから特定の名前のファイルを削除するには

拡張子が .pw のファイルをすべて削除する例

$ git filter-branch --tree-filter 'rm -f *.pw' HEAD

この例の場合は、ディレクトリの中までは削除してくれない。サブディレクトリも含めて全て削除するには

$ git filter-branch --tree-filter 'find . -name "*.pw" -exec rm -f {} \;' HEAD

初めてコミットする前に間違って git add してしまったファイルをもとに戻そうと git reset しようとしてもエラーになってしまう場合

fatal: Failed to resolve 'HEAD' as a valid ref.

git reset しようとすると、上記のエラーが出てしまう。reset してもとに戻すべきコミットが見つからないためと思われる。その場合は

$ git rm --cached -r directory_name

またはファイル1つの場合は

$ git rm --cached file_name

とする。

エンバグしたコミットを探すには

git-bisect は、エンバグしたコミットを二分探索して探す支援をするコマンド。

$ git bisect start バグのあるコミット バグのないコミット

とすると、中間のコミットがチェックアウトされるので、ここでバグが再現するかどうかをテストして、

$ git bisect good

または

$ git bisect bad

とすると、また適当なコミットをチェックアウトされるので、また再現テストをする。これを繰り返すと、最終的にバグを組み込んだコミットが表示される。最後に

$ git bisect reset

として、bisect を終了させる。

git push したときに warning: push.default is unset などと表示された場合

warning: push.default is unset; its implicit value is changing in Git 2.0 from 'matching' to 'simple'.

Git 2.0 からpushの仕様が少し変わり、 push.default のデフォルト値が matching から simple に変わる予定とのこと。simple にする場合は以下のようにでもしておく。

$ git config --global push.default simple

ただし、simpleは、Git 1.8からなのでこの ~/.gitconfig を複数のホストで共有している場合でGit 1.7のホストが混ざっていると、そこでは git push ができなくなってしまう。Git 1.7と互換性を保ちたければ、以下のようにしておく。

$ git config --global push.default matching

git clone するときにディレクトリを作成するのではなく、カレントディレクトリにそのまま展開させるには

uriの次にclone先のディレクトリを指定できる。

$ git clone <remote-repository-uri> .

zshのプロンプトにgitのメールアドレスを表示させるには

~/.zshrc に以下のような記述をしている。ブランチ名をプロンプトに表示させるところまではよくある例だが、その中に無理やり git config user.email という記述を入れて、メールアドレスも追加で表示させている。プライベートのリポジトリと会社のリポジトリとが混在していて、会社のリポジトリに間違ってプライベートのメールアドレスでコミットしちゃわないようにするためのものである。

autoload -Uz vcs_info
zstyle ':vcs_info:*' formats '[%b]'
precmd () {
    psvar=()
    LANG=en_US.UTF-8 vcs_info
    [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_`if git status >/dev/null 2>&1; then git config user.email; fi`"
}
export PROMPT="[%D{%m/%d %H:%M:%S}] %n@%m:%1(v|%F{blue}%1v%f:|)%F{green}%~%f $ "

svnなどgit以外のワーキングディレクトリではメールアドレスを表示できないので、 git config user.email する前にif文で分岐させている。

ファイル単位ではなくファイルの中の差分ごとに git add するには

以下のコマンドで差分を1つずつインタラクティブに確認しながら git add できる。

$ git add -p

特定のファイルまたはディレクトリに限定して、インタラクティブに git add することもできる。

$ git add -p ./hoge.txt

-p のかわりに --patch でも同じ。

ブランチの名前を変更するには

git branch -m 古い名前 新しい名前 でリネームできる。いまどのブランチをチェックアウトしているかは関係ない。

$ git branch -m oldbranchname newbranchname

古いの名前のほうを省略すると、いまチェックアウトしているブランチをリネームすることになる。

$ git branch -m newbranchname

特定のディレクトリだけをチェックアウトするには

いったんチェックアウトしたディレクトリにて以下を実行する。

$ git config core.sparsecheckout true
$ echo hoge > .git/info/sparse-checkout
$ git read-tree -m -u HEAD

こうすると、hogeディレクトリのみになる。hogeディレクトリ自体がチェックアウトしたディレクトリのルートになるわけではなく、単にその他のディレクトリが削除されるだけである。おそらく.gitディレクトリにはすべてのファイルが保存されたままである。

追跡するリモートリポジトリを追加するには

$ git remote add <remote-name> <remote-repository-uri>

<remotename> はワーキングディレクトリの中で通用するリモートリポジトリの名前。

リモートリポジトリがローカルホストの別のディレクトリの場合、リモートリポジトリのURIはそのリポジトリのあるディレクトリのパスになる。

すべてのリモートリポジトリに対して git fetch するには

すべてのリモートリポジトリに対して git fetch するには --all オプションを付ける。

$ git fetch --all

これを付けないと、originリモートリポジトリのみfetchされる。

特定のリモートリポジトリのみfetchするには git fetch リモートリポジトリ名 とする。

自分がよく使うコマンドは

$ git fetch --prune --all

これはすべてのリモートリポジトリでの変更を取り込んだ上で、リモートで削除されたブランチがあればそれに対応する追跡ブランチを削除する。 (-> ローカルに残っているリモート追跡用のブランチを削除するには)

追跡するリモートリポジトリの設定を削除するには

$ git remote remove <remote-name>

または

$ git remote rm <remote-name>

<remotename> はリモートリポジトリの名前。リモートリポジトリ自体が削除されなくなるのではなく、ワーキングディレクトリがそのリモートリポジトリを追跡しなくなるだけ。

cloneするときにリモートリポジトリの名前を origin 以外にするには

-o で指定する。

$ git clone -o <remote-name> <remote-repository-uri>

git diff で差分を見るときにリネームして編集されたファイルを削除と作成ではなく、編集の差分を見るには

--find-renames を付ける。

## ステージングされた編集の差分をリネームを考慮して表示
$ git diff --cached --find-renames

ローカルでのファイルの編集をgitで無視したい場合

すでにgit管理下にあるファイルは .gitignore に入れても無視してくれない。 gitにコミットされているファイルを一時的にローカルで変更してもそれの差分をgitでは無視してほしい場合には以下のようなコマンドを打つ。

$ git update-index --assume-unchanged <file-path>
## または
$ git update-index --skip-worktree  <file-path>

上記により無視されているファイルを再び無視されないようにしたい場合は以下のような解除のコマンドを打つ。

$ git update-index --no-assume-unchanged <file-path>
## または
$ git update-index --no-skip-worktree  <file-path>

--assume-unchanged / --no-assume-unchanged--skip-worktree / --no-skip-worktree は厳密には違うものなので、解除コマンドはそれぞれに対応するものを打つ必要がある。

過去の特定のバージョンでの特定のファイルをチェックアウトせずに閲覧するには

$ git cat-file -p <commit sha1>:<path>
## または
$ git show <commit sha1>:<path>

git show のほうが自動でページングもしてくれて便利。

$ git cat-file -p 859ffa2:lib/abc.php
## または
$ git show 859ffa2:lib/abc.php

特定の日時でコミットするには

環境変数 GIT_AUTHOR_DATE を設定するとその日時を author date にしてコミットできる。

$ GIT_AUTHOR_DATE=2013-11-26T15:18:04 git commit

GIT_COMMITTER_DATE を設定しうると committer date を指定できる。

Git のコミットのタイムスタンプには author date と committer date の 2 種類があるという話
http://vividcode.hatenablog.com/entry/git/author-date-and-committer-date

git diff で差分の内容ではなく差分のあるファイル名だけを確認するには

例:

## ファイル名と変更なのか新規なのか削除なのかを表示
$ git diff --name-status

## 本当にファイル名だけ表示
$ git diff --name-only

diffコマンドでの同様のことをさせるには -rq を付けるとよい。

git clone しようとしたら fatal: Unable to find remote helper for 'https' と表示された場合

git clone を実行したら以下のようなエラーが表示されることがある。

fatal: Unable to find remote helper for 'https'

gitインストール時に必要なライブラリを参照できないと、こうなるらしい。

自分はgitはソースからコンパイルしてインストールしているが、こういうエラーが出てしまった場合、Ubuntuの場合は

$ sudo apt-get install libcurl4-openssl-dev

として、gitを再コンパイル&インストールすればよい。 gitコンパイル&インストールはconfigureオプションを付けることなく ./configure && make && sudo make install だけで解決した。

(git 1.8.3.2 & Ubuntu 14.04 で確認)

git checkout で特定のブランチをチェックアウトしようとしたらローカルでの変更と衝突してエラーが表示された場合

ローカルでファイルを編集してそれをコミットもなにもしていない状態で、他のブランチをチェックアウトしようとしたときに、そのブランチでもそのファイルが変更されている場合は、衝突が起きてチェックアウトできずに以下のようなエラーメッセージが表示される。

error: You have local changes to 'foo/bar.txt'; cannot switch branches.

ローカルでの編集を一切保存せずに上書きしてもよい場合、いったん

$ git checkout foo/bar.txt

として元に戻してからブランチをチェックアウトしてもいいけど、それをせずにチェックアウトのときに -f を付ければ、強制的にファイルを上書きしてくれる。

$ git checkout -f hogehoge-branch

過去のログが不要な場合

$ git clone --depth 1 リポジトリURL

とすると、過去のログを除いて最新のソースのみをcloneできる(shallow repository)。 cloneしたワーキングディレクトリでファイルを修正して、commit, push もできる。

しかし、これでcloneしたディレクトリをオリジナルとしてさらにcloneすることはできないみたい。cloneしようとすると、以下のエラーメッセージが出る。

fatal: attempt to fetch/clone from a shallow repository
fatal: The remote end hung up unexpectedly

shallow repository には .git/shallow というファイルがあり、省略された過去のコミットが参照されていて、このファイルにより shallow repository であることを示している。このファイルを削除すると、ローカルではcloneすることができるが、リモートへのcloneでは過去のコミットが見つからない、というエラーが出て、やっぱりcloneできない。

git管理対象外のファイルを削除するには

まだcommitしていない作業途中の状態を、直前のcommitの状態に完全に戻したい場合など。

新しく作ったファイルでまだgit addしていないファイルを一括して削除するには git clean -f を使う。その前に git clean -n を使うと削除するファイルを事前に確認することができる。ディレクトリまるごとgit管理対象外の場合はこれでは削除できず、git clean -df を使う。

$ git status -s
?? foo.txt
?? bar/

## 削除されるファイルを確認
$ git clean -n
Would remove foo.txt

## 削除を実行
$ git clean -f
Removing foo.txt

## ディレクトリまるごとgit管理対象外のものがある場合
# 削除されるファイルを確認
$ git clean -dn
Removing blog/

## 削除を実行
$ git clean -df
Removing blog/

.gitignore で指定されたファイルはこれを使っても削除されない。それらも削除するには -x を使う。

リモートリポジトリの名前を変更するには

$ git remote rename 古い名前 新しい名前

git log で表示するコミットの数を指定するには

## 最新の10個のコミットだけを表示
$ git log -10

## 最新のコミットだけを表示
$ git log -1

git merge で衝突して、とりあえず元に戻したい場合

git merge foo としたら

CONFLICT (content): Merge conflict in bar/example.txt
Automatic merge failed; fix conflicts and then commit the result.

などと表示されて手動での衝突解決を求められて、とりあえず元に戻したい場合、

$ git merge --abort

とすると、git merge する前の状態に戻ってくれる。

git diff の差分を反転するには

直近のコミットの差分を見るには git diff HEAD~1..HEAD などとすれば見れるが、このコミットを取り消すためのパッチファイルを作りたい場合などは、前後を入れ替えて

$ git diff -R HEAD..HEAD~1

とするか、または -R を付ける。

$ git diff -R HEAD~1..HEAD

.gitignore のサンプルファイル

Java

# Maven2で生成されるファイル
/target/

Scala sbt

# sbtで生成されるファイル
/target/
/project/target/

Ruby

# bundle install --path vendor/bundle
# で生成されるファイル
.bundle
/vendor/bundle

その他

# Windowsで勝手に作られる隠しファイル
Thumbs.db

# Macで勝手に作られる隠しファイル
.DS_Store

.gitignore のへぇ〜

.gitignore はトップのディレクトリにだけでなく、任意のディレクトリに置いて、そのディレクトリ以下にのみ追加の設定をすることができる。

入門

デザイナーでもgithubを覚えたい!コマンドの練習ができる『Learn Git Branching』
http://arisa.biz/%E3%81%8A%E5%BD%B9%E7%AB%8B%E3%81%A1/2013-03-19/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%8A%E3%83%BC%E3%81%A7%E3%82%82github%E3%82%92%E8%A6%9A%E3%81%88%E3%81%9F%E3%81%84%EF%BC%81%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E7%B7%B4%E7%BF%92%E3%81%8C

Git に関する良記事
http://d.hatena.ne.jp/kazu-yamamoto/20130402/1364887137

GitのURI

プロトコルを省略した以下の記法はSSHプロトコルとみなされる。pathの先頭に / がつかない。

username@hostname:path/foo/bar.git

よって、以下と同じ。

ssh://username@hostname/path/foo/bar.git

ポート番号を指定したい場合はプロトコルを省略できない。

ssh://username@hostname:port/path/foo/bar.git

Gitblit

Javaで実装されたGitリポジトリ管理ツール。リポジトリの pull request をWeb上ですることはできない。コミットログをグラフィカルに表示することはできない。WikiやIssueの機能がない。Hookのスクリプトを Groovy で書ける。

git svn で作成したリポジトリで使えるコマンド

## svnリモートリポジトリでの更新を取り込む
$ git svn fetch --localtime
## 自分の環境では --localtime を付けないと
## gitに取り込まれたコミットのタイムスタンプがずれてしまった

## SVNにコミット(?)
$ git svn dcommit
## 自分はあまり試していない

関連

このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。