gitコマンドを使うにあたってのもろもろ
2012/08/20 ちょっと修正
nkfもgitのバージョンによってはうまく認識されない?よくわからないので、↓だけでもいける試したところ、いけたっぽい?lessも日本語に対応しているのか?よくわからないがいけたのでよしとする
まあ、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
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
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 = automsysgitだと
cat <<EOL >>"$USERPROFILE/.bash_profile" export TERM=msys export EDITOR=vi EOL . "$USERPROFILE/.bash_profile"もしといたほうがいい。commit時にeditorが起動しなかったりlog見るときにlessが出来なかったりする
日本語対応版を落としてくる。http://www.greenwoodsoftware.com/less/download.htm... のBinariesというコーナーがあるので、そこから最新版をダウンロードする。解凍するとless.exeとlesskey.extがあるので、C:\Program Files\Git\bin に設置する。その後
2012/08/17。どうやらwindowsのbinaryがなくなっているようなのでhttp://nonn-et-twk.net/twk/windows-less-utf8のを使わせてもらう
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のを使わせてもらう
http://www.asuka.cx/software/nkf/ からダウンロード&解凍後、C:\Program Files\Git\bin に設置する
とりあえず日本語が表示できるようにする。C:\Program Files\Git\etc\inputrcを設定する
set convert-meta off set meta-flag on set output-meta on set kanji-code utf-8
このあたりからは好みで。自分は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になるように保存すること
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 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を参考にした
msysgit, kdiff, リポジトリビューアがそろっているのでこれをいれるほうがいいかも。少なくともtortoisegitやgit guiよりは使いやすい http://code.google.com/p/gitextensions/
windowsは開発環境を整えるのがかなりめんどくさいが、まあこれで多少はましになるかもしれない
windowsは開発環境を整えるのがかなりめんどくさいが、まあこれで多少はましになるかもしれない
こんな感じで設定
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"'のように!を先頭につける
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>とすればサブコマンドが補完される
インストール後の設定のところでも触れているが、設定をしたり、設定を参照したりする
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
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と同じ名前のファイルにこういう処理が必要な場合、--を付けないと絶対にエラーになるため
git add -uリネームや削除する場合はgit mvやgit rmをするべきだが直接操作してしまった場合はとにかくgit add -uをすると一気にindexを更新してくれるらしい
同じくgit rmを使うこと
cachedを付けるとindexからは削除するが実物は削除しない
削除確認。削除はされない
エラーを無視
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 filesindexに登録されていないからこういうエラーがでるケースがあるわけだが、とりあえず無視したい場合は
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でこれは登録、これは登録しない。って使うんだとおもう
resetする
git reset -- <file>一気にやりたい場合は
git reset HEADただしcommitの歴史がまだ無い場合はこれは使えない。エラーになるので
git rm <file> --cachedとする
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で始まりと終わりの行ナンバーを指定する
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.txtname-onlyだとファイルのパスだけが表示される
indexに登録してしまうと前回のcommitからの差分が見れなくなるので
git diff --cached # ↑とするか前回のcommitからの差分比較を明示的に指定してもOK git diff HEADとしてもよい
- 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 +2renameということから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) # # VERSIONUntraced filesとか表示された場合はgit addする
# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: VERSION #となればcommitできる状態
commit
git commit -m "message"
- mを付けない場合は環境変数EDITORに指定されている外部コマンドが起動する(普通はvi)
- vを付けるとeditor起動時に変更点も表示される
すでにindexが存在を知っている対象をcommitするなら以下でもよい
# git add -u && git commit -m "message"と同じ git commit -a -m "message"
amendを使う
git commit --amend -m "new message"メッセージ以外にauthor, 日付を変更することも可能
git commit --amend --author="kurt <newmailaddress>" --date="1993/8/4 00:00:00" -m "new message"
git reset HEAD^この方法は直前のcommitの状態に戻るがファイルに編集した情報はそのまま残っているので、それすらもしない場合は--hardをつける
git reset HEAD^ --hard
特定の編集した歴史を消したい場合とか。まずは変更が加えられた歴史を探すところから。まあ例えば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) aaa728909e6を消したいということにして、念のため確認
git show 728909e6間違いないことを確認したらrevertする
git revert 728909e6
おもに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
.bakファイルをcommit初期時はいれた状態であとから.gitignoreしたけど、昔の.bakとかは残ってたり、いらんbinaryいれてしまったりとか
git filter-branch --tree-filter 'rm -f path/to/file' HEADのようにするとよい
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を書くのと同じ感じ
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とか
git log --grep="message"grepを2つ指定するとOR検索になるので、AND検索にしたい場合は--all-matchを指定するとよい
git log --all-match --grep="message" --grep="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
double dot表記で。branchの作成方法はbranch参照
歴史がこのようになっているとして
歴史がこのようになっているとして
# master - 正規のcommit(master branch) # feature - 開発版commit(feature branch) A - B - C - D <- master ` E - F <- featurefeatureからは辿れて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
ふたつの参照のうちどちらか一方からのみ辿れる。表示順は従来どおりコミット日時順となる。
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
>が...の右側、<が...の左側の記録となる
何かしら追加、変更があった場合の履歴だけがでてくる(たぶん)
git log <path> # dir git log <dir>/ # 複数指定も可能 git log <path> <path>commit objectと同じような名前のファイル(ややこしいことにHEADとかmasterとか)だと検索できないので以下のように--を付ける
git log -- master
めんどくさい。とりあえずのせておこう
これがよさそうだ
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
ちょっとした情報が出る。あんまりいらんかも
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しか表示されないが、Author, Committer両方の名前がログに表示される。普通にコミットすればAuthor = Committerとなるのだが、git commit --author=AuthorNameとすることで、Authorの名前を指定できる。
git log --pretty=full commit bb88dd9d4e476202f798263114b3ce1ed18ed52c Author: holly <mailaddress> Commit: holly <mailaddress> v1.97 update
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
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 updateemailも情報に出す場合は
git shortlog --email holly <mailaddress> (38): initial commit v1.1 update kurt <kurt@localhost> (1): v1.3 updatecommiterごとの件数
git shortlog --summary 38 holly 1 kurt
show。git log -n1 -pとかするくらいならこれのほうがいいかも。表示は同じ
git show <commit object>commit objectを指定しない場合はmasterの情報。HEAD^とか031740dとかtagなどでも表示可能
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
- tをつける
git cat-file -t master commit # blog objectの場合。ls-treeをするとblog objectを求めることができる git cat-file -t ee1e40 blob
- 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値関係のねたが続いているので
どうしても自分でgitの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値を求めることができる
まずは確認する
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 e73b001e84477d0bf0430ff9d95a0208b8f10058dangling objectは残っていても参照されることのない不要なobject。おいたままでも害はない。rebase/reset/stashしたあとにstash clearなどをすると残るようだ
長いこと運用していると必ずたまるので、定期的に行ってもよい。ただい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にtagを付けたいとか
# commit objectを特定する。こういう方法じゃなくていいけど git log --pretty=oneline 5e669dae62f8e0d4a09820fdfc80bd1bbe5e54fa # commit objectを指定する git tag v1.0 5e669dae
git tag -l initial v1.1 v1.2 v1.3 v1.5commitした時のメッセージも表示したい場合は-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
再帰的に表示するには-r、treeのみ表示の場合は-dを付ける
また--name-status or --name-onlyを指定するとgit ls-filesのデフォルトと同じ表示になる
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のデフォルトと同じ表示になる
-c or --cached デフォルト -d or --deleted 削除されたobjectのみ(ただしgit rmで消した場合はこれをしてもでてこない) -m or --modified 変更 -o or --other その他。たとえばuntrackedな状態とか
ls-treeとにたような状態で表示。or -s
git ls-files --stage 100644 5ac2aa66a7243ea6c1c90be69f4a1719f5058ff3 0 .gitignore 100644 732647b222ffeabc90c66a280dc50f9ead16361c 0 README 100644 2c36cfac76a6dfe8c1c2c1ebdafac2891e87f09e 0 VERSION
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
標準では現在のブランチの先頭の情報が表示されるが、commit objectを指定することも可能
# ls-treeと同じでabbrevが使用できる git ls-files --with-tree=HEAD^1 -t --abbrev=7staging状態を表す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/.gitignorewith-treeは-s(--stage)、-u(--unmerged)と組み合わせることはできない
git branch * feature master現在いるbranchに*がつく
- rを付けるとリモート追跡用ブランチを参照することができる。切り替わることは不可
git branch -r origin/master
git branch <branch>作成後、すぐに切り替える場合は
git checkout -b <branch> <target>とする。<target>は無ければmasterからbranchを作成することになる
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 の代わりにコミット(記録) を指定するのに使う。 行の残りはコミットログ。
# 必ず現在のワークツリーを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
# 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 masterrebaseする
git rebase master featuremergeなどと同じく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共有リポジトリにはいらん歴史を残さないようにするには便利そうだ
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 64868e85ba711d48a745f008e866b68ffd3a4397no-commitオプションを指定しておくとよい
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とすると復旧可能
git remote add <name> <url> # よく使うのはこういうの。cloneした場合はこんなことしなくてもorigin = clone先のURLとなるけど git remote add origin git@foo.bar:share.git
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)
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以外に引数が無い場合は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
git pull --rebase。普通のpullとの違いは
git fetch origin git merge origin/masterpull --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 originfetchした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
反映先の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に反映することを意味する
- <local_ref>とすると強制的にローカルリポジトリ反映分をリモートに反映することができる。名前じゃなく
refs/tags/<tagname> # リモートのtagを消したい場合とか git push origin :refs/tags/<branchtag>のような表記も可能
refspecを利用してローカルリポジトリのbranchをリモートに作成することが可能
# branchの名前がfeatureという場合 git push origin feature # 別名で作成したい場合 git push origin feature:change # 削除したい場合 git push origin :feature名前指定とか関係なくローカルリポジトリの全てのbranchをpushしたい場合は
git push --allとする
こんな風になっているとして
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とする
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@{0}を取り出す git stash apply <stash>すでにaddしていてcommitはしていないけど、indexに登録している場合にapplyした場合にindexに登録されていない状態になるのでその場合は
git stash apply --indexとするが、自分の環境ではちゃんとステージング状態は保持してくれていたようだ
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 <- masterEが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さえ残っていれば、復旧がとりあえず可能
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とする
無視したいファイルを記述しておく
cover_db META.yml Makefile blib inc pm_to_blib MANIFEST Makefile.old nytprof.out MANIFEST.bak *.sw[po]perlモジュールとかだとこんな感じのを入れている。これに該当するファイル名のものはステージング対象とはならない
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じゃなくてもいいんだけど
https://github.com/github/gitignore/ に各言語ごとのgitignoreがおいている
この下にブランチごとのファイルがあり、ファイルの中身はそれぞれのbrancheの先頭のcommit objectが記載されている
git branch hoge * master tempこのように出力される場合はhoge master tempというファイルがそれぞれ存在していることになり
git rev-parse master a5d14ff08ff29f47c5bea91d1aff58865662f4dc cat .git/refs/heads/master a5d14ff08ff29f47c5bea91d1aff58865662f4dcとなる
tagごとのファイルがある。考え方はheads以下と同じ
git tag -l v3.01 v3.011となる場合はv3.01 v3.011というファイルが存在している。中は同じくcommit objectが記載されている
現在チェックアウトしているブランチを示す。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ディレクトリのパスを指定することで直接リポジトリ配下に移動しなくても各種gitの操作が可能
git --git-dir=/path/to/App-CLI-Extension/.git log各サブコマンドを指定する前に--git-dirを指定しないといけない
特定のメンバーに更新情報をメールしたい場合など。yumでインストールしている場合は/usr/share/git-core/contrib/hooks/post-receive-emailというのがあったと思うのでそれを使う
patchをあてる(日本語commit log文字化け防止)
git post-receive mail メール設定
権限、onwer/group設定
リスト作成後、/etc/aliasesに設定を追加する
/etc/aliases.dbに反映する
リポジトリ設定
これで共有リポジトリにpushするとメールがrepo-update@foo.barに登録されているメールアドレスに送信される。
MLメンバー内の変更はrepo-update.listを編集するだけでいい。
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を編集するだけでいい。
タグ
最新コメント