hollyさんのwiki

gitコマンドを使うにあたってのもろもろ

インストール

yumでインストール

まあ、centosだとyumとかでいれたらいいんじゃないあかなと
yum install --enablerepo=rpmforge -y git perl-DBI perl-Error perl-Git
とかで適当にはいるはず。ほかにも
# yum search --enablerepo=rpmforge git | grep -E "^git"
git.i386 : Git core and tools
git-all.i386 : Meta-package to pull in all git tools
git-arch.i386 : Git tools for importing Arch repositories
git-cvs.i386 : Git tools for importing CVS repositories
git-daemon.i386 : Git protocol daemon
git-email.i386 : Git tools for sending email
git-gui.i386 : Graphical frontend to git
git-svn.i386 : Git tools for importing Subversion repositories
gitk.i386 : Git revision tree visualiser
gitweb.i386 : Simple web interface to git repositories
こんだけあるので、必要に応じてインストールする。

ソースからインストール

とにかくどうしてもソースからインストールしたい場合は
# まあ自分の環境にあわせて、足りなさそうなのをいれておく
yum install zlib-devel openssl-devel curl curl-devel gcc
cd /usr/local/src
# バージョンはその都度最新のをいれる
wget http://kernel.org/pub/software/scm/git/git-1.7.3.2.tar.bz2
tar jxvf git-1.7.3.2.tar.bz2
cd git-1.7.3.2
# webdavでやり取りしたい場合はこれがないとだめ
./configure --with-openssl --with-curl --with-expat
make
make install

man

cd /usr/local/src
# バージョンはその都度最新のをいれる
wget http://www.kernel.org/pub/software/scm/git/git-manpages-1.7.3.tar.bz2
mkdir -p git-manpages/man
tar -C git-manpages/man -jxvf git-manpages-1.7.3.tar.bz2
chown -R root.root git-manpages
mkdir /usr/local/share/git-core
cp -a /usr/local/src/git-manpages/man /usr/local/share/git-core/man

man.config

cp -p /etc/man.config /etc/man.config.org
echo "MANPATH   /usr/local/share/*/man" >> /etc/man.confg

インストール後の設定

最低限の設定

これくらいはしておく
git config --global core.autocrlf false
git config --global user.name holly
git config --global user.email mailaddress
git config --global color.ui auto
で$HOME/.gitconfig(中はini形式)というファイルが作成される。この設定はどのリポジトリに対しても有効な設定になる
[core]
        autocrlf = false
[user]
        name = holly
        email = mailaddress
[color]
        ui = auto
msysgitだと
cat <<EOL >>"$USERPROFILE/.bash_profile"
export TERM=msys
export EDITOR=vi
EOL
. "$USERPROFILE/.bash_profile"
もしといたほうがいい。commit時にeditorが起動しなかったりlog見るときにlessが出来なかったりする
less
日本語対応版を落としてくる。http://www.greenwoodsoftware.com/less/download.htm... のBinariesというコーナーがあるので、そこから最新版をダウンロードする。解凍するとless.exeとlesskey.extがあるので、C:\Program Files\Git\bin に設置する。その後
cat <<EOL >>~/.bash_profile
export JLESSCHARSET=japanese-utf-8
export LESSCHARSET=dos
EOL

# 設定を反映
. ~/.bash_profile
とする

2012/08/17。どうやらwindowsのbinaryがなくなっているようなのでhttp://nonn-et-twk.net/twk/windows-less-utf8のを使わせてもらう
nkf
http://www.asuka.cx/software/nkf/ からダウンロード&解凍後、C:\Program Files\Git\bin に設置する
inputrc
とりあえず日本語が表示できるようにする。C:\Program Files\Git\etc\inputrcを設定する
set convert-meta off
set meta-flag on
set output-meta on
set kanji-code utf-8
editor
このあたりからは好みで。自分はgvimを使っているので
# commit logはUTF-8なのでgvim起動時にファイル文字コードが自動的にutf-8になるようにする
git config --global core.editor "'c:/Program Files/Vim/vim73/gvim.exe' -c 'set fileencoding=utf-8'"
としたけど、EDITORやGIT_EDITORという環境変数に定義する方法もあり。etc/profileやbash_profileあたりか。優先順位的にはGIT_EDITOR -> core.editorのようだ。それとログは必ずUTF-8になるように保存すること
pager
git config --global core.pager 'nkf -s | less'
環境変数の場合はGIT_PAGERなど。

2012/08/20 ちょっと修正
nkfもgitのバージョンによってはうまく認識されない?よくわからないので、↓だけでもいける試したところ、いけたっぽい?lessも日本語に対応しているのか?よくわからないがいけたのでよしとする
git config --global core.pager "LESSCHARSET=utf-8 less"

git-am
git rebaseで
usage: git update-ref [options] -d <refname> [<oldval>]
   or: git update-ref [options]    <refname> <newval> [<oldval>]

    -m <reason>           reason of the update
    -d                    deletes the reference
    --no-deref            update <refname> not the one it points to

Cannot save the current status
こんなのがでて、実行できないことがあるので、C:\Program Files\Git\libexec\git-core\git-amに
--- git-am	2010-06-12 14:40:56.000000000 +0900
+++ git-am	2010-11-02 01:59:13.453125000 +0900
@@ -698,7 +698,7 @@
 
 	if test -f "$dotest/final-commit"
 	then
-		FIRSTLINE=$(sed 1q "$dotest/final-commit")
+		FIRSTLINE=$(sed 1q "$dotest/final-commit")" "
 	else
 		FIRSTLINE=""
 	fi
とpatchをあてる。stashも同じことが発生することがあるので、C:\Program Files\Git\libexec\git-core\git-stashに
--- git-stash	Sat Oct  2 11:06:32 2010
+++ git-stash	Wed Nov  3 01:04:25 2010
@@ -161,7 +161,7 @@
 		shift
 	done
 
-	stash_msg="$*"
+	stash_msg="$* "
 
 	git update-index -q --refresh
 	if no_changes
をあてておけばよい。http://d.hatena.ne.jp/miau/20100514/1273860616を参考にした
git extension
msysgit, kdiff, リポジトリビューアがそろっているのでこれをいれるほうがいいかも。少なくともtortoisegitやgit guiよりは使いやすい http://code.google.com/p/gitextensions/
windowsは開発環境を整えるのがかなりめんどくさいが、まあこれで多少はましになるかもしれない

おまけの設定

alias
こんな感じで設定
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci 'commit -a'
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -n1 HEAD'
設定したけどいらないとかって場合は--unsetをつける
# これに限らずだが
git config --global --unset alias.di
外部コマンドを実行したい場合は
# commit数を取る
git config --global alias.cinum '!git log --pretty=oneline | wc -l | sed -e "s/ //g"'
のように!を先頭につける

git-completion.bash

zshを使うのならいらないが
curl -o /etc/profile.d/git-completion.sh  -L "http://git.kernel.org/?p=git/git.git;a=blob_plain;f=contrib/completion/git-completion.bash;hb=HEAD"
これでbashでも
git <TAB>
とすればサブコマンドが補完される

設定情報

config

インストール後の設定のところでも触れているが、設定をしたり、設定を参照したりする
git config -l
core.symlinks=false
core.autocrlf=false
color.diff=auto
pack.packsizelimit=2g
help.format=html
http.sslcainfo=/bin/curl-ca-bundle.crt
sendemail.smtpserver=/bin/msmtp.exe
core.autocrlf=false
user.name=holly
user.email=mailaddress
color.ui=auto
設定する場合は
git config foo.bar

var

git変数(環境変数みたいなもんか?)を参照する
git var -l
core.symlinks=false
core.autocrlf=false
color.diff=auto
pack.packsizelimit=2g
help.format=html
http.sslcainfo=/bin/curl-ca-bundle.crt
sendemail.smtpserver=/bin/msmtp.exe
core.autocrlf=false
user.name=holly
user.email=emperor.kurt@gmail.com
color.ui=auto
GIT_COMMITTER_IDENT=holly <mailaddress> 1286468556 +0900
GIT_AUTHOR_IDENT=holly <mailaddress> 1286468556 +0900
GIT_EDITOR=vi
GIT_PAGER=less
どうやらconfigの値も表示されるようだ

ファイルやディレクトリのパスなどを指定する場合

例えばgit diff
git diff foo.txt
これでもいいけど、
git diff -- foo.txt
--を付けるくせをつけておくこと。残念なことにHEADやmasterなどといった、gitで元から定義されているbranchやcommit objectと同じ名前のファイルにこういう処理が必要な場合、--を付けないと絶対にエラーになるため

リポジトリ作成

initする

ローカルリポジトリ

git init <repo>

共有リポジトリ

git init --bare <repo>
同じgroupで複数のメンバーが更新する場合は
git init --bare --shared=true <repo>
とする

indexに登録する

addで。indexに変更分を登録

全部登録

git add .

ほぼ全部登録

# git add . && git add -u と同じ意味
git add -A

対象ファイルを登録

git add <file>

以前登録していたファイルが更新されている分だけ登録

git add -u
リネームや削除する場合はgit mvやgit rmをするべきだが直接操作してしまった場合はとにかくgit add -uをすると一気にindexを更新してくれるらしい

移動

直接リネームや移動を行うのではなくgit mvやgit rmを使うこと。基本的なオプションはそれぞれのコマンドと同じ
git mv <path> <newpath>

削除

同じくgit rmを使うこと
git rm <path>
git rm -rf <path>

cachedを付けるとindexからは削除するが実物は削除しない
git rm <path> --cached

削除確認。削除はされない
git rm -n <path>

エラーを無視
fatal: pathspec 'foo.txt' did not match any files
indexに登録されていないからこういうエラーがでるケースがあるわけだが、とりあえず無視したい場合は
git rm --ignore-unmatch *.txt
などとする

部分登録

git add -p
Stage this hunk [y,n,q,a,d,/,e,?]?
これだけ使えるらしい。
y - stage this hunk
n - do not stage this hunk
q - quit, do not stage this hunk nor any of the remaining ones
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
たぶんyとnでこれは登録、これは登録しない。って使うんだとおもう

addしたファイルを取り消す

resetする
git reset -- <file>
一気にやりたい場合は
git reset HEAD
ただしcommitの歴史がまだ無い場合はこれは使えない。エラーになるので
git rm <file> --cached
とする

指定したファイルの行数ごとにどのcommitで編集したか調べる

blameで
git blame -- hello.txt
00000000 (Not Committed Yet 2010-08-19 00:30:27 +0900 1) 1
b989e3a4 (holly             2010-08-19 00:22:21 +0900 2) 2
24308a89 (holly             2010-08-19 00:22:29 +0900 3) 3
9ec7d287 (holly             2010-08-19 00:22:44 +0900 4) 4
65642e07 (holly             2010-08-19 00:22:56 +0900 5) 5
9404a204 (holly             2010-08-19 00:23:05 +0900 6) 5.11
00000000 (Not Committed Yet 2010-08-19 00:30:27 +0900 7) 5.12
変更、追加はしたけどまだcommitしていない変更分の行はcommit objectは00000000として表示される。行数を絞りたい場合は
$ git blame -L2,5 -- hello.txt
b989e3a4 (holly 2010-08-19 00:22:21 +0900 2) 2
24308a89 (holly 2010-08-19 00:22:29 +0900 3) 3
9ec7d287 (holly 2010-08-19 00:22:44 +0900 4) 4
65642e07 (holly 2010-08-19 00:22:56 +0900 5) 5
  • Lで始まりと終わりの行ナンバーを指定する

差分をみる

diffする

普通にdiffする

git diff
diff --git a/VERSION b/VERSION
index c068b24..c239c60 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4
+1.5

差分内容はいらない

stat。対象ファイル一覧だけ表示
git diff --stat
 VERSION |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
name-statusやname-onlyでも一覧だけ取得可能
git diff --name-status
A       VERSION
D       foo.txt
M       dir/bar.txt
name-onlyだとファイルのパスだけが表示される

addしてしまったあとにdiff

indexに登録してしまうと前回のcommitからの差分が見れなくなるので
git diff --cached
# ↑とするか前回のcommitからの差分比較を明示的に指定してもOK
git diff HEAD
としてもよい

commit単位でdiff

たとえば現在のcommitと1世代前のcommitと
git diff HEAD^ HEAD

ファイル名変更検知によるdiff

  • Mを使う
git diff -M HEAD^ HEAD
diff --git a/VERSION b/VERSION
index e7158be..697ed2d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.92
+2.921
diff --git a/unko.txt b/unko2.txt
similarity index 92%
rename from unko.txt
rename to unko2.txt
index a9da621..f237abb 100644
--- a/unko.txt
+++ b/unko2.txt
@@ -1,3 +1,4 @@
 unko.txt
 dddd
 unko bug
+2
renameということからunko.txtはunko2.txtに変わったことがわかる。-Mだとこのようなdiffの結果はわからない

現在の状態を表示

status
git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    VERSION
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       VERSION
Untraced filesとか表示された場合はgit addする
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   VERSION
#
となればcommitできる状態

addしたファイル、ディレクトリなどをcommitする

commit
git commit -m "message"
  • mを付けない場合は環境変数EDITORに指定されている外部コマンドが起動する(普通はvi)
  • vを付けるとeditor起動時に変更点も表示される

git addしなくてもcommit

すでにindexが存在を知っている対象をcommitするなら以下でもよい
# git add -u && git commit -m "message"と同じ
git commit -a -m "message"

直前のcommit情報をやり直す

amendを使う
git commit --amend -m "new message"
メッセージ以外にauthor, 日付を変更することも可能
git commit --amend --author="kurt <newmailaddress>" --date="1993/8/4 00:00:00" -m "new message"

直前のcommitを無かったことにする

git reset HEAD^
この方法は直前のcommitの状態に戻るがファイルに編集した情報はそのまま残っているので、それすらもしない場合は--hardをつける
git reset HEAD^ --hard

特定のcommitを無かったことにする

特定の編集した歴史を消したい場合とか。まずは変更が加えられた歴史を探すところから。まあ例えばblameを使う。revertはresetと違い、commitを消したことが履歴に残る
5e669da (holly 2010-08-12 18:01:22 +0900 1) read me!
728909e6 (holly 2010-08-12 18:09:35 +0900 2) aaa
728909e6を消したいということにして、念のため確認
git show 728909e6
間違いないことを確認したらrevertする
git revert 728909e6

2世代以上前のcommitを変更する

おもにrebaseを使う
git rebase -i HEAD~3
この場合だと3世代前を基点に(現在のmasterが3世代前まで戻るイメージ)どのcommitを変更するか選択することができる(3世代前のcommitは変更対象にはならない)
edit 331ec99 v1.91 update # <- 今回はここをeditに変更する
pick c0612c3 v1.92 update
pick 8c67263 v1.93 update

# Rebase 76c9ace..8c67263 onto 76c9ace
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
保存すると
Stopped at 331ec99... v1.91 update
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue
と出るので言うとおりにする。editではなくsquashとした場合はsquashにした一つ前のcommitとsquashにしたcommitが統合される。↓の場合だとc0612c3 8c67263が統合される(editorが開くようだ)
pick 331ec99 v1.91 update
pick c0612c3 v1.92 update
squash 8c67263 v1.93 update

機械的に大量の歴史を書き換える

filter-branchという最強オプションがあるそうだ。麻雀でいう一気通貫。的なやつ。

全commitからいらないファイルを削除

.bakファイルをcommit初期時はいれた状態であとから.gitignoreしたけど、昔の.bakとかは残ってたり、いらんbinaryいれてしまったりとか
git filter-branch --tree-filter 'rm -f path/to/file' HEAD
のようにするとよい

commit時のauthorやcommiterの情報を変更

commiter-filterを使うとよいらしい
git filter-branch --commit-filter '
GIT_AUTHOR_NAME="emperor"
GIT_AUTHOR_EMAIL="foo@bar"
GIT_COMMITTER_NAME="kurt"
GIT_COMMITTER_EMAIL="bar@foo"
git commit-tree "$@"
' HEAD
Rewrite 3c060f461c83801b6c9c095b992ba495ca79fc01 (46/46)
Ref 'refs/heads/master' was rewritten
これだとすべての歴史が変わるので特定のauthorの情報を変えたいとかって場合は
git filter-branch --commit-filter '
if [ $GIT_AUTHOR_NAME = "old_name" ]; then
    GIT_AUTHOR_NAME="new_name"
fi
git commit-tree "$@"
' HEAD
のようにするとよい。shellを書くのと同じ感じ

履歴をみる

logで今までのcommitの歴史を見ることができる。以下のオプションは組み合わせることが可能なので、かなり柔軟に検索することができる

普通に

git log
WARNING: terminal is not fully functional
commit ed011c6aaf6ceccf196a438fc00825017631f6ce
Author: holly <mailaddress>
Date:   Thu Aug 12 21:11:09 2010 +0900

    v1.5 update

commit 40d64bbb08b4873ab7953a966905add8c42a8b04
Author: holly <mailaddress>
Date:   Thu Aug 12 20:49:32 2010 +0900

    v1.4 update
件数指定の場合は-n[num]を指定する。-n1とか-n2とか

検索指定

commit logをgrepする
git log --grep="message"
grepを2つ指定するとOR検索になるので、AND検索にしたい場合は--all-matchを指定するとよい
git log --all-match --grep="message" --grep="message"
行範囲指定
指定した文字列が管理対象のファイルに含まれている場合。指定した文字列が一番初めに記録されたcommit objectのみが検索対象として表示される
git log -S"message"
日付検索
指定した日付以降、もしくはそれ以前
# 指定した日付以降にcommitしたlog。--sinceでもよい。フォーマットはYYYY-MM-DDとかでもよい
git log --after="YYYY/MM/DD"
# 指定した日付以前にcommitしたlog。--untilでもよい
git log --before="YYYY/MM/DD"
# 相対的に。例は1日前以上のlog
git log --before="1 day"
範囲指定
commit objectベースで
# 5世代前から2世代前の間
git log HEAD~5..HEAD~2
# 5世代前から最新
git log HEAD~5..
# 指定したcommit objectからの親commit
git log HEAD~5
master - branch間での検索(double dot)
double dot表記で。branchの作成方法はbranch参照
歴史がこのようになっているとして
# master  - 正規のcommit(master branch)
# feature - 開発版commit(feature branch)
A - B - C - D <- master
      ` E - F <- feature
featureからは辿れてmasterからは辿れないログの検索は以下のようになる
# 実際はこのように表示されるわけではない。あくまでわかりやすくするため
git log master..feature
F <- Fのlog
E <- Eのlog
逆にmasterからは辿れてfeatureからは辿れないログの検索は以下となる
git log feature..master
D
C
リモートのmasterにはなくてローカルのmasterにはあるcommitを検索する場合。この結果がpushするとリモートリポジトリに反映されることになる
# HEADじゃなくてmasterでもよい
git log origin/master..HEAD
master - branch間での検索(triple dot)
ふたつの参照のうちどちらか一方からのみ辿れる。表示順は従来どおりコミット日時順となる。
git log master...feature
F
E
D
C
ただしこのままだとどっちのcommit objectかわからないのでその場合は--left-rightを付ける。--pretty=onelineと組み合わせて使うと
git log --pretty=oneline master...feature --left-right
>5f6c8689fa5b4774344631e7136ca4770959bdb6 v2.21-dev update
<d6e4b40717f2a035928a6462ad22c694736ed0f8 v2.21 update
>699b5796002af3a97d7166b37d6a5726c9f796a6 v2.2-dev update
<c87153420d38a19678a5f9616549d91978100a48 v2.2 update
>が...の右側、<が...の左側の記録となる
author
git log --author="holly"
パス名で制限した履歴の検索
何かしら追加、変更があった場合の履歴だけがでてくる(たぶん)
git log <path>
# dir
git log <dir>/

# 複数指定も可能
git log <path> <path>
commit objectと同じような名前のファイル(ややこしいことにHEADとかmasterとか)だと検索できないので以下のように--を付ける
git log -- master

graph

めんどくさい。とりあえずのせておこう
git log --graph
git log --graph --pretty=oneline
git log --graph --pretty=format:%s

これがよさそうだ
# --abbrev-commit commit objectの省略形
# --date=short    日付を簡易表示
git log --graph --pretty=oneline --decorate --date=short --abbrev-commit --branches
* ed011c6 (HEAD, v1.5, master) v1.5 update
* 40d64bb v1.4 update
* 75b20a9 v1.3 update
* 5e998c2 (v1.2) v1.2 update
* 728909e (v1.1) v1.1 update
* 5e669da (initial) initial commit

表示変更

summary
ちょっとした情報が出る。あんまりいらんかも
git log -n1 --summary
commit 5e669dae62f8e0d4a09820fdfc80bd1bbe5e54fa
Author: holly <mailaddress>
Date:   Thu Aug 12 18:01:22 2010 +0900

    initial commit

create mode 100644 README
authorとcommiter
普通はAuthorしか表示されないが、Author, Committer両方の名前がログに表示される。普通にコミットすればAuthor = Committerとなるのだが、git commit --author=AuthorNameとすることで、Authorの名前を指定できる。
git log --pretty=full
commit bb88dd9d4e476202f798263114b3ce1ed18ed52c
Author: holly <mailaddress>
Commit: holly <mailaddress>

    v1.97 update
patch
git log -n1 -p
commit ed011c6aaf6ceccf196a438fc00825017631f6ce
Author: holly <mailaddress>
Date:   Thu Aug 12 21:11:09 2010 +0900

    v1.5 update

diff --git a/VERSION b/VERSION
index c068b24..c239c60 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4
+1.5
一行表示
git log --pretty=oneline
ed011c6aaf6ceccf196a438fc00825017631f6ce v1.5 update
40d64bbb08b4873ab7953a966905add8c42a8b04 v1.4 update
75b20a92dcb178f4b0fab308a9701fe6dc8f6a4e v1.3 update
自分でフォーマット定義
    • pretty=format:"$custom"。使えるフォーマット
%H	コミットのハッシュ
%h	コミットのハッシュ (短縮版)
%T	ツリーのハッシュ
%t	ツリーのハッシュ (短縮版)
%P	親のハッシュ
%p	親のハッシュ (短縮版)
%an	Author の名前
%ae	Author のメールアドレス
%ad	Author の日付 (?date= オプションにしたがった形式)
%ar	Author の相対日付
%cn	Committer の名前
%ce	Committer のメールアドレス
%cd	Committer の日付
%cr	Committer の相対日付
%s	件名
author とはその作業をもともと行った人、committer とはその作業を適用した人のことを指します。あなたがとあるプロジェクトにパッチを送り、コアメンバーのだれかがそのパッチを適用したとしましょう。この場合、両方がクレジットされます (あなたが author、コアメンバーが committer です)。
git log --pretty=format:"%h %t - %an, %ar : %s"
ARNING: terminal is not fully functional
d011c6 4b38f3f - holly, 25 minutes ago : v1.5 update
0d64bb 83b08dd - holly, 47 minutes ago : v1.4 update
5b20a9 43781a0 - kurt, 17 years ago : v1.3 update
e998c2 31bc872 - holly, 3 hours ago : v1.2 update
28909e 2ca4a36 - holly, 3 hours ago : v1.1 update
e669da 031740d - holly, 4 hours ago : initial commit
reflog情報も表示
git log -g
commit 9256c255e416fe170a59951cf61cc05d025373b7
Reflog: HEAD@{0} (holly <mailaddress>)
Reflog message: HEAD@{1}: updating HEAD
Author: holly <mailaddress>
Date:   Mon Aug 30 00:33:16 2010 +0900

    unko3.txt update3

commit 495036711af080fe97b097ff47d91c9bfb33ac65
Reflog: HEAD@{1} (holly <mailaddress>)
Reflog message: HEAD^^: updating HEAD
Author: holly <mailaddress>
Date:   Mon Aug 30 00:31:54 2010 +0900

    unko3.txt update1

commit 9256c255e416fe170a59951cf61cc05d025373b7
Reflog: HEAD@{2} (holly <mailaddress>)
Reflog message: commit: unko3.txt update3
Author: holly <mailaddress>
Date:   Mon Aug 30 00:33:16 2010 +0900

    unko3.txt update3

履歴を見るけど簡易版

shortlogで。どっちかいうと統計的な感じで
git shortlog
holly (38):
      initial commit
      v1.1 update
kurt (1):
      v1.3 update
emailも情報に出す場合は
git shortlog --email
holly <mailaddress> (38):
      initial commit
      v1.1 update
kurt <kurt@localhost> (1):
      v1.3 update
commiterごとの件数
git shortlog --summary
  38  holly
   1  kurt

commit objectの情報をみる

show。git log -n1 -pとかするくらいならこれのほうがいいかも。表示は同じ
git show <commit object>
commit objectを指定しない場合はmasterの情報。HEAD^とか031740dとかtagなどでも表示可能

指定したcommit objectの特定のファイルの中身を見る

git show <commit object>:<path>
ちなみに標準出力結果をsha1sumなりに渡せば、blob objectとしてのhash値ではなく、本来のhash値を得ることができる
# master branchのREADMEというファイルのsha1sum
git show master:README | sha1sum
# master branchの一世代前のREADMEのsha1sum
git show HEAD~1:README | sha1sum

objectの情報をみる

commit objectだけじゃなく全てのobjectの情報をみる。objectはHEAD, master, tagなどの指定でもよい

objectの種類

  • tをつける
git cat-file -t master
commit

# blog objectの場合。ls-treeをするとblog objectを求めることができる
git cat-file -t ee1e40
blob

objectの中身

  • pをつける
# commit objectの場合
git cat-file -p master
tree 15847238e1ceb35c822f9ac96d21e9631a852fe8
parent 1dc19d9cd5b97107b913d1edf23418058d0803f1
author holly <mailaddress> 1281759738 +0900
committer holly <mailaddress> 1281759738 +0900

v1.97 update

# git show <commit object>:<path>と同じでファイルの中身を参照することになる
git cat-file -p ee1e40
read me!
pオプションじゃなくても
# 732647b2がcommit objectの場合
git cat-file commit 732647b2

# 54c4daeがblog objectの場合
git cat-file blob 54c4dae
としてもよい

hash-object

hash値関係のねたが続いているので
git hash-object /path/to/file
とするとls-treeやls-files --stageで出力されるオブジェクトのhash値を求めることができる。
どうしても自分でgitのhash値を求めたいという変わったことをしたい場合は
path="/path/to/file"
printf "blob %s\000" $(stat -c "%s" $path) | cat - $path | sha1sum | cut -d" " -f1
とすればgitがls-treeとかで出力するhash値を求めることができる

掃除

fsck

まずは確認する
git fsck
dangling commit 27bc10f5348a517732989f8f57377f9b90a6f7c5
dangling commit 5460e843cae443f3cfd68e8a97ba363fa83b1887
dangling blob b990ee08e16b9598738ef879569bfd9542806daf
dangling commit 2d91f3ef9353bafe78599ecf8e5c5665830e9289
dangling commit 3e097022f7cefa5869c9a545cce7f72b30622258
dangling commit 03a2b06345f5b7d45adeb9fc75a82139edc4ce2c
dangling commit 51131f8eab78d5f80903d41e490695c6fe3fed1b
dangling blob e73b001e84477d0bf0430ff9d95a0208b8f10058
dangling objectは残っていても参照されることのない不要なobject。おいたままでも害はない。rebase/reset/stashしたあとにstash clearなどをすると残るようだ

gc

長いこと運用していると必ずたまるので、定期的に行ってもよい。ただいreflogやdangling objectから復旧させたい場合にできない。ということもありえる
git gc
# 完全にきれいにしたいのなら。git pruneでもいいけど
git gc --prune
する

編集以前のファイルの状態に戻す

checkout。branchの切り替えなどでも使うけど。こういう使い方もできる
git checkout -- <path>
# addしてしまったファイルに対してはHEADを指定する
git checkout HEAD -- <path>
HEADじゃなく、特定のcommit objectから戻すことも可能。仮に消してしまったとしてもcheckoutで復活することが可能。少し危険だが一気にもどしたい場合は
git checkout -- .
としてもいい

commit objectに別名を付ける

tag。commitしてから
git tag v1.0
この場合はあくまでalias的な扱いとなる

anotation tag

tag objectとして生成する。コメントが付けれる以外はメリットはよくわからない
git tag -a v1.0 -m "tagged v1.0"

以前付け忘れてたとかいう場合

過去のcommitにtagを付けたいとか
# commit objectを特定する。こういう方法じゃなくていいけど
git log --pretty=oneline
5e669dae62f8e0d4a09820fdfc80bd1bbe5e54fa
# commit objectを指定する
git tag  v1.0 5e669dae

tag一覧

git tag -l
initial
v1.1
v1.2
v1.3
v1.5
commitした時のメッセージも表示したい場合は-nにする
git tag -n
initial         initial commit
v1.1            v1.1 update
v1.2            v1.2 update
v1.3            v1.3 update
v1.5            v1.5 update

tag削除

git tag -d v1.0

commit objectの名前を取得

# HEAD~2とかtagとか
git rev-parse HEAD

commit objectの構造を表示する

再帰的に表示するには-r、treeのみ表示の場合は-dを付ける
git ls-tree <commit object>
100644 blob ee1e40b8b0678ab7e9ee6bee534411318c717ecd    README
100644 blob 038d8c2ab2bc34234a02d558abfeeb6628c0ce99    VERSION
040000 tree 6a46764d637fcbaba52b043adbd4f506ccdbc8b2    lib
100644 blob d2eb92c3f437753a118e0fb686bbc3d3bba96b63    new.txt
デフォルトではobjectはフルネームで表示されるが
git ls-tree --abbrev=<n> <commit object>
などと指定すると指定した長さでobject名が表示される。まあ7くらいがいいかなと。git logの--abbrev-commitと同じ。
また--name-status or --name-onlyを指定するとgit ls-filesのデフォルトと同じ表示になる

現在管理しているobject一覧

っていってもblobとかtreeとか。ls-filesで参照できる
git ls-files
README
VERSION
etc/app.conf

現在のstaging状態から変更がかかったobjectだけを取り出す。いずれもgit addしてない状態で。

-c or --cached   デフォルト
-d or --deleted  削除されたobjectのみ(ただしgit rmで消した場合はこれをしてもでてこない)
-m or --modified 変更
-o or --other    その他。たとえばuntrackedな状態とか

stage

ls-treeとにたような状態で表示。or -s
git ls-files --stage
100644 5ac2aa66a7243ea6c1c90be69f4a1719f5058ff3 0       .gitignore
100644 732647b222ffeabc90c66a280dc50f9ead16361c 0       README
100644 2c36cfac76a6dfe8c1c2c1ebdafac2891e87f09e 0       VERSION

statusの種類

git ls-files -t
H .gitignore
H README
H VERSION
種類はこんだけ
H  cached  
S  skip-worktree  
M  unmerged  
R  removed/deleted  
C  modified/changed  
K  to be killed  
?  other 

with-tree

標準では現在のブランチの先頭の情報が表示されるが、commit objectを指定することも可能
# ls-treeと同じでabbrevが使用できる
git ls-files --with-tree=HEAD^1 -t --abbrev=7
staging状態を表すoptionと組み合わせれば、その時のcommitで削除されたファイルはどれか?とか変更したファイルはどれか?などをみることができる
# 1世代前のcommitで削除したファイル情報
git ls-files --with-tree=HEAD~1 -t -d
R lib/MyApp.pm

# 2世代前のcommitで変更したファイル情報
$ git ls-files --with-tree=HEAD~2 -t -m
C testdir/.gitignore
with-treeは-s(--stage)、-u(--unmerged)と組み合わせることはできない

歴史を分けて開発

とか。branchを使う

現在どのbranchにいるか

git branch
* feature
  master
現在いるbranchに*がつく
  • rを付けるとリモート追跡用ブランチを参照することができる。切り替わることは不可
git branch -r
origin/master

作成

git branch <branch>
作成後、すぐに切り替える場合は
git checkout -b <branch> <target>
とする。<target>は無ければmasterからbranchを作成することになる

削除

git branch -d <branch>
# 強制削除の場合は
git branch -D <branch>
それぞれのbranchとそのcommitの一覧
show-branch。masterにいる場合でshow-branchを使うとこうなる
git show-branch
$ git show-branch
* [master] v3.01 update
 ! [temp] foo.txt rename and update
--
 + [temp] foo.txt rename and update
 + [temp^] add .gitignore
*  [master] v3.01 update
*+ [temp~2] neo.txt edit
どっかからぱくってきた。こういうことらしい
全体の構成
  最初の何行かはブランチやタグの最新情報が表示
  残りはブランチが分岐してから現在までの記録
それぞれの意味
  行頭の * は現在自分が居るブランチ。たとえば一文字目に * があると、一つ目のブランチ、上の例では bui-test に属しているという意味。
  行頭の ! はその他の最新(HEAD)
  行頭の + はその行が属するブランチ。
  行頭の - はその文字があるブランチでマージが行われた事。上の例では最終行に三つ - があるので、三つのブランチ(とタグ)がそこでマージされている。
  行頭の [] の中身は short name。SHA1 の代わりにコミット(記録) を指定するのに使う。
  行の残りはコミットログ。

branch変更分をmasterに反映

mergeを使う

# 必ず現在のワークツリーをmasterにし
git checkout master
# branchで開発した内容をmasterに取り込む
git merge <branch>
# 不要なbranchは削除
git branch -d feature

# あとは共有リポジトリに反映する 
git push --tags origin master

# 共有レポジトリにもbranchを作成したり、branchにtagを付けていた場合は
git push origin :refs/tags/v1.0-feature
git push origin :feature
git push --tags

mergeではなくrebase

# master  - 正規のcommit(master branch)
# feature - 開発版commit(feature branch)
A - B - C - D - E <- master
      ` F - G - H <- feature
このように正規版と開発版両方のbranchがそれぞれ歴史を更新させていったとして、どこかでmergeでもよいが
A - B - C - D - E  <- master
                 ` F - G - H <- feature
こうしたい場合、必ずmaster branchを最新版に保っておいて
git checkout master
git pull --tags origin master
rebaseする
git rebase master feature
mergeなどと同じくconflictする可能性もあるので、その場合は
First, rewinding head to replay your work on top of it...
Applying: v2.31-bug update
Using index info to reconstruct a base tree...
<stdin>:23: trailing whitespace.
use warnings;
warning: 1 line adds whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging VERSION
CONFLICT (content): Merge conflict in VERSION
Auto-merging unko.txt
CONFLICT (add/add): Merge conflict in unko.txt
Failed to merge in the changes.
Patch failed at 0001 v2.31-bug update

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".
こんな感じで出力されるので、rebaseする場合はconflictしたファイル(中身は↓みたいになっている)git statusなどで調べてconflictを解消してからadd、rebase --continueをする。
<<<<<<< HEAD
2.32
=======
2.31-bug
>>>>>>> v2.31-bug update

# 変更できてから
git add <path> # とか
git rebase --continue # やっぱりやめる場合は--abortを指定する
これでbranch(feature)にmaster更新分が適用されたので、今度はmasterとfeatureを併合する
git checkout master
git merge feature
あとは共有リポジトリに更新など
git push --tags origin master
共有リポジトリにはいらん歴史を残さないようにするには便利そうだ

特定のcommitを現在のbranchにmerge

mergeではなくcherry-pickいうものを使うとよさそうだ
# master  - 正規のcommit(master branch)
# feature - 開発版commit(feature branch)
A - B - C - D - E <- master
      ` F - G - H <- feature
このようになっているとして、masterにfeature branchのHの変更分だけを取り込みたい場合
git checkout master
# 事前にHのcommit objectを調べておく。git rev-parse feature とか
git cherry-pick 64868e85ba711d48a745f008e866b68ffd3a4397
とするとHの情報だけ(F, Gは取り込まれない。ここがかなりみそ)がmaster branchに取り込まれ
A - B - C - D - E - H' <- master
      ` F - G - H <- feature
となる。ここで普通のmergeと同じくconflictが発生する可能性があることに注意。Hは必要ないので
git checkout feature
git reset HEAD^ --hard
とし、歴史は以下のようになる
A - B - C - D - E - H' <- master
      ` F - G <- feature
もうfeature branchの用が事足りたのならbranch自体を削除しておく。ちなみにcommitはしないでstagingのみにとどめておきたい場合は
git cherry-pick --no-commit 64868e85ba711d48a745f008e866b68ffd3a4397
no-commitオプションを指定しておくとよい

間違って消してしまったcommitやstashなどを復旧

reflogからでもできるけど、cherry-pickでもできそうだ。これはfsckなどと組み合わせた場合。どっかで見つけたstashで一時的に脇に置いたデータを間違って消してしまったのをなんとか復旧させた場合のを試してみる。とにかく何か編集中でcommitまではしてない状態で
git stash
とし、保存してからstashを誤って削除してみる。
git stash clear
とするととりあえず消えてしまう。がなんとかstashしていたものはかなり大事で復旧したい。まずはgit fsckでdangling object(用は参照されなくなった。git gcをしていないことが前提)を見てみる
git fsck | grep "dangling commit" | cut -d ' ' -f3
27bc10f5348a517732989f8f57377f9b90a6f7c5
5460e843cae443f3cfd68e8a97ba363fa83b1887
2d91f3ef9353bafe78599ecf8e5c5665830e9289
3e097022f7cefa5869c9a545cce7f72b30622258
03a2b06345f5b7d45adeb9fc75a82139edc4ce2c
51131f8eab78d5f80903d41e490695c6fe3fed1b
こんだけ出てくるので、commit objectが出てくるので、あとはそれらしいcommitを探し当てる
git show --summary 27bc10f5
commit 27bc10f5348a517732989f8f57377f9b90a6f7c5
Merge: 94b3219 11fc3c2
Author: holly <mailaddress>
Date:   Fri Sep 3 00:27:04 2010 +0900

    WIP on master: 94b3219 neo.txt edit
それらしいものを見つけたらcherry-pickする
# -m1をつけないと怒られた
git cherry-pick --no-commit -m1 27bc10f5
とすると復旧可能

リモートリポジトリのshorturl作成

remote。push/pull/fetchなどの操作をする時に必要。remoteとなっているが共有リポジトリがリモート(別サーバ)にある必要はない

名前作成

git remote add <name> <url>
# よく使うのはこういうの。cloneした場合はこんなことしなくてもorigin = clone先のURLとなるけど
git remote add origin git@foo.bar:share.git

URL変更

git remote set-url [name] [newurl]

名前変更

git remote rename [old_name] [new_name]

削除

git remote -r <name>

一覧表示

git remote
origin
share

# もう少し詳細に
git remote -v
origin  d:/git/test.git (fetch)
origin  d:/git/test.git (push)
share   git@git.app.vm:share.git (fetch)
share   git@git.app.vm:share.git (push)||=

情報表示

git remote show [shortname] # <- originとか
 remote origin
 Fetch URL: d:/git/test.git
 Push  URL: d:/git/test.git
 HEAD branch: master
 Remote branch:
   master tracked
 Local ref configured for 'git push':
   master pushes to master (up to date)

ssh portなどが違う場合

22portでgitのやり取りしたいが、firewallの制限やサーバ側で意図的にssh portを標準のportから変えてる場合
git remote set-url origin ssh://git@domain:20022/path/to/app.git
というようにしておくとよい。それか~/.ssh/configに
Host domain
  User git
  Port 20022
  Hostname domain
  IdentityFile ~/.ssh/id_dsa
みたいに書いてもいいと思う。試してないけど

リモートリポジトリを複製

cloneする
# リモートリポジトリがfoo.gitな場合はfooというローカルリポジトリで作成される。pathを明示的に指定することも可能
git clone <url>
git clone <url> <path>

リモートリポジトリの変更分をローカルリポジトリに反映する

pull

pullする。pull以外に引数が無い場合はgit pull origin masterと認識される
git pull <url or shortname> # <- originとか
git pull <url or shortname> master
# tagの情報も取得する場合 
git pull --tags
余談だけどこういう方法でもgit pullしたことになる。
git fetch origin
# mergeは指定したbranchを現在のbranchに併合する
git merge origin/master
# もしくはfetchしたあとにrebaseでも同じ
# ブランチの派生元(上流)を変更する。第1引数が派生元branch、第2引数が派生先branchに適用する(無い場合は現在いるbranch)
git rebase origin/master

pull --rebase

git pull --rebase。普通のpullとの違いは
git fetch origin
git merge origin/master
pull --rebaseは
git fetch origin
# git rebase origin/master でもいいけど一応
git rebase origin/master master
をしたことになる。originをmergeするかrebaseするか。のちがいっぽい。なので
# remote repo
A - B - C - D - E <- origin/master

# local repo
A - B - C  <- origin/master
         ` F - G <- master
となっている場合
git pull origin master
とすると
A - B - C - D - E ` <- origin/master
         `  F - G - H(merge commit) <- master
となるが
git pull --rebase origin master
とすると
A - B - C - D - E ` <- origin/master
                  `  F - G <- master
となる。あんまり同branchでcommitが分かれるのはあとで歴史を見直すと複雑になるので、pull --rebaseとしておくほうがよさそうだ

リモートリポジトリの変更分をローカルリポジトリに保存する

fetch。pullと違うのは保存であって、masterは更新しない。この場合origin/master or FETCH_HEADというcommit objectで取得した対象を扱うことができる。
git fetch origin
fetchしたobjectを元にbranchを作成することが可能
git fetch origin
git checkout -b feature origin/master

リモートリポジトリにローカルリポジトリの変更分を反映する

push。pullの反対で基本的な文法はかわらない
git push <url or shortname> # <- originとか
git push <url or shortname> master
# tagの情報も取得する場合 
git push --tags

refspec

反映先のobject指定をmaster:masterという表記であらわすこともできる。これをrefspecという。意味は<local_ref>:<remote_ref>の意味。originがssh://git@foo.bar:share.gitの場合
git push origin master:master
はfoo.bar:share.git(origin)にローカルリポジトリmasterの変更分をoriginのmasterに反映することを意味する
  1. <local_ref>とすると強制的にローカルリポジトリ反映分をリモートに反映することができる。名前じゃなく
refs/tags/<tagname>

# リモートのtagを消したい場合とか
git push origin :refs/tags/<branchtag>
のような表記も可能

branchをpush

refspecを利用してローカルリポジトリのbranchをリモートに作成することが可能
# branchの名前がfeatureという場合
git push origin feature
# 別名で作成したい場合
git push origin feature:change
# 削除したい場合
git push origin :feature
名前指定とか関係なくローカルリポジトリの全てのbranchをpushしたい場合は
git push --all
とする

作業を隠す

stashを使う。

普通に隠す

こんな風になっているとして
git status
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   etc/app.conf
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   VERSION
#
一時的にこのようにcommitもしていない状態を隠したい場合は
git stash
# もしくは明示的にsaveをつける
git stash save
とする

stash一覧

indexの数値が小さいほど新しいstash
git stash list
stash@{0}: WIP on master: 0cf1ce3 v2.31-bug update
stash@{1}: WIP on master: 0cf1ce3 v2.31-bug update

stashを取り出す

# 指定が無い場合はstash@{0}を取り出す
git stash apply <stash>
すでにaddしていてcommitはしていないけど、indexに登録している場合にapplyした場合にindexに登録されていない状態になるのでその場合は
git stash apply --index
とするが、自分の環境ではちゃんとステージング状態は保持してくれていたようだ

stashを取り出して削除

# 指定が無い場合はstash@{0}を取り出す
git stash pop <stash>
git stash pop <stash> --index

stashを削除

git stash drop <stash>

全stashを削除

git stash clean

stashからbranchを作成

git stash branch <branch> <stash>

reflog

reflogです。すべての操作履歴が何ヶ月か残っているらしい。git gcとかしてなければ、過去の情報を復旧できたりも可能

普通にみる

git reflog
8b195da HEAD@{0}: checkout: moving from d971d2114d3d18d7e1c3087ca7d64d5ca0dbe072
d971d21 HEAD@{1}: checkout: moving from master to HEAD@{1}
8b195da HEAD@{2}: commit (amend): unko3.txt update

ためしに復旧してみる

今こういう歴史にになっている
A - B - C - D - E <- master
Eがmasterだが、どうやら間違ったcommitをしているらしく、いったんDに戻したい。ということで
git reset HEAD^ --hard
としたいのだが、戻しすぎて
git reset HEAD^^ --hard
としてCまで戻ってしまったようだ。
        # Cがmaster。D, Eはもう参照不可能
A - B - C - Dx - Ex 
もちろん--hardをつけてるから変更分が残っているわけがない。がなんとかEに戻したい。という場合まずはreflogを確認する
git reflog
4950367 HEAD@{0}: HEAD^^: updating HEAD
9256c25 HEAD@{1}: commit: E
6b3141a HEAD@{2}: commit: D
41e50d7 HEAD@{3}: commit: C
となっているとしてHEAD@{1}というのがreset前の状態っぽいと確認できるので、
git reset HEAD@{1} --hard
とするとreset前に戻すことが可能。というようにreflogさえ残っていれば、復旧がとりあえず可能

untracked filesを削除

clean

確認

git status
# On branch temp
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       1.txt
みたいなのをごっそり削除。ローカルリポジトリでソースファイルをいじりながら、makeとかする場合、後片付けなんかによさそうだ。いきなりやってしまうとあれなので
# もしくは-n
git clean --dry-run
Would remove 1.txt
とし実行するとどうなるのか確認する

実行

git clean -f
Removing 1.txt
とする。untrackedなディレクトリも消したい場合は
# -dはディレクトリも対象、-xは.gitignoreの設定で無視されているファイルも消す
git clean -f -d -x
とする

.gitignore

無視したいファイルを記述しておく
cover_db
META.yml
Makefile
blib
inc
pm_to_blib
MANIFEST
Makefile.old
nytprof.out
MANIFEST.bak
*.sw[po]
perlモジュールとかだとこんな感じのを入れている。これに該当するファイル名のものはステージング対象とはならない

余計なのをaddしてしまってる場合

git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   .a.swp
#       new file:   a.bak
#
のような状態であとで.gitignoreを
cat <<EOL >.gitignore
*.sw[po]
*.bak
EOL
git add .gitignore
としても当然ながら除外されない。この場合はいったんindexから.a.swpとa.bakを削除してみる
git rm --cached .a.swp a.bak
としてからstatusで再度確認すると
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   .gitignore
#
みごと.gitignoreにマッチしているのでuntracked扱いにもならず無視してくれる。すでにcommitまでしてしまっている不要なファイルは、git rmすればいいと思う

空ディレクトリを管理対象にいれたい場合

gitignoreとはまったく関係ないんだけど、このままではindexに含めることができないので
mkdir testdir
touch testdir/.gitignore
git add testdir
とすればその後commitすることができる。別に.gitignoreじゃなくてもいいんだけど

sample

https://github.com/github/gitignore/ に各言語ごとのgitignoreがおいている

構造

refs

.git/refs/heads
この下にブランチごとのファイルがあり、ファイルの中身はそれぞれのbrancheの先頭のcommit objectが記載されている
git branch
  hoge
* master
  temp
このように出力される場合はhoge master tempというファイルがそれぞれ存在していることになり
git rev-parse master
a5d14ff08ff29f47c5bea91d1aff58865662f4dc
cat .git/refs/heads/master
a5d14ff08ff29f47c5bea91d1aff58865662f4dc
となる
.git/refs/tags
tagごとのファイルがある。考え方はheads以下と同じ
git tag -l
v3.01
v3.011
となる場合はv3.01 v3.011というファイルが存在している。中は同じくcommit objectが記載されている

HEAD

現在チェックアウトしているブランチを示す。masterブランチの場合は
cat .git/HEAD
ref: refs/heads/master
となり、現在チェックアウトしているブランチはmaster。ということになる。違うブランチにいる場合はもちろんmasterではなく
git checkout temp
Switched to branch 'temp'

cat .git/HEAD
ref: refs/heads/temp
となる。過去のコミットなどにさかのぼってHEADを見ると
# 1世代前のcommitをcheckoutする
git checkout HEAD^

cat .git/HEAD
8b727086a1b1709a3c533e702e1627007a330ff0
と現在のHEADのcommit objectが記載される。もちろんgit rev-parse HEADとすると同じ結果が返ってくるはず

git-dir

.gitディレクトリのパスを指定することで直接リポジトリ配下に移動しなくても各種gitの操作が可能
git --git-dir=/path/to/App-CLI-Extension/.git log
各サブコマンドを指定する前に--git-dirを指定しないといけない

hooks

post-receive

pushした時にイベントを起こす。たぶん一番つかうと思う
pushしてdeploy
公開領域をローカルリポジトリにしておく
(cd /path/to/repo; git --git-dir=.git pull);
メール送信
特定のメンバーに更新情報をメールしたい場合など。yumでインストールしている場合は/usr/share/git-core/contrib/hooks/post-receive-emailというのがあったと思うのでそれを使う

patchをあてる(日本語commit log文字化け防止)
--- post-receive-email	2010-04-24 11:38:35.000000000 +0900
+++ post-receive-email	2010-07-30 16:35:25.000000000 +0900
@@ -197,6 +197,8 @@
 	cat <<-EOF
	Subject: ${emailprefix}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
+	Mime-Version: 1.0
+	Content-Type: text/plain; charset=utf-8
	X-Git-Refname: $refname
	X-Git-Reftype: $refname_type
	X-Git-Oldrev: $oldrev
@@ -684,6 +686,6 @@
 else
	while read oldrev newrev refname
	do
-		generate_email $oldrev $newrev $refname | send_mail
+		generate_email $oldrev $newrev $refname | nkf -w | send_mail
	done
fi

git post-receive mail メール設定
mkdir /var/lib/git/post-receive

## repo-update@foo.bar リスト作成
cat <<EOL >/var/lib/git/post-receive/repo-update.list
nirvana@gmail.com
melvins@gmail.com
EOL

権限、onwer/group設定
chmod 755 /var/lib/git/post-receive
chmod 644 /var/lib/git/post-receive/*.list
chown -R git.git /var/lib/git/post-receive

リスト作成後、/etc/aliasesに設定を追加する
cat <<EOL >>/etc/aliases

## git repositories post-receive-email
repo-update:        :include:/var/lib/git/post-receive/repo-update.list
EOL

/etc/aliases.dbに反映する
newaliases

リポジトリ設定
mkdir /var/lib/git/repositories/repo.git
cd /var/lib/git/repositories/repo.git
git init --bare

# 更新時メール送信設定
git config hooks.mailinglist repo-update@foo.bar
echo ". /usr/share/git-core/contrib/hooks/post-receive-email" >> hooks/post-receive

これで共有リポジトリにpushするとメールがrepo-update@foo.barに登録されているメールアドレスに送信される。
MLメンバー内の変更はrepo-update.listを編集するだけでいい。
タグ

Wiki内検索

Menu

ここは自由に編集できるエリアです。

管理人/副管理人のみ編集できます