2011-05-22
チェックアウトせずにマージ
dev-xxxブランチにいるときに、masterブランチに移動しないままでdev-xxxブランチをmasterにmergeできたら
http://hibari.2ch.net/test/read.cgi/tech/1284467898/810
低レベル操作によって、ワーキングディレクトリを一切無視して任意のインデクスに対してマージしてくれるコマンドが欲しい。
http://hibari.2ch.net/test/read.cgi/tech/1284467898/813
GIT_INDEX_FILE でどうにかなりそうな気がしたので実験してみたメモ。
マージする準備
最初のコミット。a.txtとb.txtを追加。
$ git init $ echo a > a.txt $ echo b > b.txt $ git add a.txt b.txt $ git commit -m 'initial' [master (root-commit) e1f7440] initial 2 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 a.txt create mode 100644 b.txt
こうなった
$ git whatchanged --oneline e1f7440 initial :000000 100644 0000000... 7898192... A a.txt :000000 100644 0000000... 6178079... A b.txt
topicブランチを作って、進める
$ git checkout -b topic --track master Branch topic set up to track local branch master. Switched to a new branch 'topic' $ echo 'BB(topic)' >> b.txt $ git commit -a -m 'BB(topic)' [topic ce78e31] BB(topic) 1 files changed, 1 insertions(+), 0 deletions(-)
1つ進んだ
$ git whatchanged --oneline topic ce78e31 BB(topic) :100644 100644 6178079... a86f970... M b.txt e1f7440 initial :000000 100644 0000000... 7898192... A a.txt :000000 100644 0000000... 6178079... A b.txt
topicはmasterより1つ進んでいる
$ git branch -v master e1f7440 initial * topic ce78e31 [ahead 1] BB(topic)
masterをチェックアウトせずに、masterにtopicをマージ
topicをチェックアウトした状態のまま、そしてインデックスも保持したまま、masterにtopicをマージする。
- 方針
インデックスが保全されることを確認したいので、ちょっといじっておく
$ echo 'あばばばばwwwwwwwwwwww' >> b.txt $ git add b.txt
編集したb.txtがインデックスに登録された
$ git status # On branch topic # Your branch is ahead of 'master' by 1 commit. # # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: b.txt #
$ git diff --cached diff --git a/b.txt b/b.txt index a86f970..cb6733f 100644 --- a/b.txt +++ b/b.txt @@ -1,2 +1,3 @@ b BB(topic) +あばばばばwwwwwwwwwwww
この状態を維持することにする。
GIT_INDEX_FILEで別のインデックスを使う
現在のインデックスの状態を表示
$ git ls-files -s 100644 78981922613b2afb6025042ff6bd878ac1994e85 0 a.txt 100644 cb6733f4cdef9366bbbaeef9c8a5af40a3f03b5f 0 b.txt
b.txtのblobを見るとさっきの変更が反映されているのが分かる
$ git cat-file blob cb6733f4cdef9366bbbaeef9c8a5af40a3f03b5f b BB(topic) あばばばばwwwwwwwwwwww
.index_tmpをインデックスファイルに指定して、masterの内容を読み込んでみる
$ GIT_INDEX_FILE=.index_tmp git read-tree master
.index_tmpが出来ていた
$ ls -1a . .. .git .index_tmp a.txt b.txt
通常のインデックスは.git/indexなので、GIT_INDEX_FILE=.git/index_altとかにすれば良かったかも。
.index_tmpインデックスの状態を表示
$ GIT_INDEX_FILE=.index_tmp git ls-files -s 100644 78981922613b2afb6025042ff6bd878ac1994e85 0 a.txt 100644 61780798228d17af2d34fce4cfbdf35556832472 0 b.txt
b.txtのblobを見るとmasterの内容なのが分かる
$ git cat-file blob 61780798228d17af2d34fce4cfbdf35556832472 b
別々に操作出来ていることが確認できた。
インデックス上でマージ
.index_tmpのほうで、masterとtopicをマージしてみる
$ GIT_INDEX_FILE=.index_tmp git read-tree -m -i master topic
マージ後の内容
$ GIT_INDEX_FILE=.index_tmp git ls-files -s 100644 78981922613b2afb6025042ff6bd878ac1994e85 0 a.txt 100644 a86f970145550ca53098e9bed4fcdd61a935b6f4 0 b.txt
b.txtの内容をそれぞれ確認してみる。
通常のインデックスのb.txt
$ git cat-file blob cb6733f4cdef9366bbbaeef9c8a5af40a3f03b5f b BB(topic) あばばばばwwwwwwwwwwww
保持したい内容のままになっている
マージ後のインデックスのb.txt
$ git cat-file blob a86f970145550ca53098e9bed4fcdd61a935b6f4 b BB(topic)
topicブランチの内容になっている。マージできたっぽい。
Low-levelコマンドでマージコミットを作る。
$ echo 'Merge! branch topic into master!' | git commit-tree `GIT_INDEX_FILE=.index_tmp git write-tree` -p master -p topic f59b2bb25340f8677c3b2842db81c2e9a8250781
コミットオブジェクトできた
$ git log --oneline --graph f59b2bb25340f8677c3b2842db81c2e9a8250781 * f59b2bb Merge! branch topic into master! |\ | * ce78e31 BB(topic) |/ * e1f7440 initial
Low-levelコマンドでmasterを更新
$ git update-ref refs/heads/master f59b2bb25340f8677c3b2842db81c2e9a8250781
できたー
$ git branch -v master f59b2bb Merge! branch topic into master! * topic ce78e31 [behind 1] BB(topic)
通常のインデックスはそのまま変化なし
$ git status # On branch topic # Your branch is behind 'master' by 1 commit, and can be fast-forwarded. # # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: b.txt # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # .index_tmp
$ git diff --cached diff --git a/b.txt b/b.txt index a86f970..cb6733f 100644 --- a/b.txt +++ b/b.txt @@ -1,2 +1,3 @@ b BB(topic) +あばばばばwwwwwwwwwwww
問題点
ファイル単位で更新がぶつかるとアウト
git merge-baseで3-Wayにしたりとか、Low-levelコマンドをくししてがんばればどうにかなるけど…
もっと本格的にコンフリクトするとアウト
人間が関与しないとダメなやつは無理ですねこれ。
ツール化したらどうなるか
個人的にはマージする時はstashしてチェックアウトすればいいかなーと思う。。。
2011-02-16
Gitにパッチを送るメモ
コードを書く
起点をどこにするか
- バグ修正の場合
- maint(無い場合はmaster)
- 新機能の場合
- master(puに依存する場合はpu)
コミットを作る
Documentation/SubmittingPatches を読む。
Signed-off-by: Your Name <you@example.com>
- コミット後
- バグを修正した場合、それが本当に直っているか、チェック
- テストツールがパスするか、チェック
テストツール
t/READMEを読む。
- makeすると全テストを実行(けっこう時間かかる)
- 最新版のproveなら並列実行できるらしい
prove --timer --jobs 15 ./t[0-9]*.sh
- 個別にテストするには、シェルで実行する
sh ./t3010-ls-files-killed-modified.sh
全て(?)のテストスクリプトでは test-lib.sh がsourceされている。これにより"t/trash directory.テスト名"というようなディレクトリが作られて、そこに cd して git init されるので、各テストスクリプトはその砂場でテストを実行する。この砂場はテスト成功時には削除されるが、スクリプトにデバッグオプション(--debug、-d)を付けると消されずに残る。
パッチを送る
電子メールの形式でパッチを作る
現在のブランチにあるコミットのうち、origin/masterに存在しないものを指定ディレクトリに出力
mkdir outgoing git format-patch -M origin/master -o outgoing
outgoingディレクトリにそれぞれのコミットがパッチとして出力されるので、確認し、必要があれば編集する。
出力されたファイルは電子メールの形式で、Subjectはコミットメッセージの一行目、bodyは以降のコミットメッセージになっている。
コミットメッセージの最後の行(Signed-off-byのはず)の後には、三本ダッシュだけの行があり、以降にdiffstat、続いてパッチ本体がある。
コミットメッセージには含めないけどメールには書きたい内容は、この三本ダッシュ以降パッチ本体以前に書く。diffstatの手前など。
メーリングリストにパッチを送る
git-send-emailを使う。
~/.gitconfig か .git/configに以下を追加
[sendemail]
from = Your Name <you@example.com>
smtpencryption = tls
smtpserver = smtp.gmail.com
smtpuser = you@gmail.com
smtpserverport = 587
まずは自分に送ってテスト
git send-email outgoing/0001-hoge.patch
送り先、In-Reply-To(誰かに返信する場合は入れたほうが良い)、SMTPのパスワード等を聞かれるので入力する。
自分宛に届いたら、そのメールをmbox形式でファイルに保存して、実際にパッチを当ててみる。
git checkout origin/master git am hoge.mbox
この結果は、git format-patchしたブランチの内容と同じになるはず
git diff HEAD..master
大丈夫そうなら、メーリングリストとメンテナ(あるいは自分の変更点を知るべき人が分かるならその人)宛に送る。
気をつけること
パッチを添付しない
パッチについてメーリングリストでディスカッションする際に、引用できなくなるので。
英語を頑張る orz
「以前はこう、そしてパッチ後はこう。〜がしたくて、やった」という説明を明確に書かないと、レビュアを混乱させる結果になる。
英語苦手でも、そこはちゃんと書くことorz
入門Git
今回、やはり入門Gitがとても参考になった。
- 作者: 濱野純(Junio C Hamano)
- 出版社/メーカー: 秀和システム
- 発売日: 2009/09/19
- メディア: 単行本
- 購入: 26人 クリック: 622回
- この商品を含むブログ (134件) を見る
版管理とは何か、ということ(新しいコミットを作るというのはどういう意味を持つ行為なのか、など)から、オープンソースのプロジェクトにおける役割分担、分散型システムでのコミットアクセス(コミット権限)がCVSやSubversionとどう違うのかなど、ワークフローの部分、そして特にすごいのが「Chapter 10.9 オープンな開発プロセス」で語られる、メーリングリスト上での議論の進め方。大半がネイティブスピーカーではない中で、どう議論を組み立てていくべきか、どうやったら無用な意地の張り合いを避けてプロジェクトを発展させられるのか、パッチレビューで反対意見を書く際に誤解されないための文章の組み立て方まで、ものすごいノウハウと、思想が詰まっている。
そうした互いの知識と経験を活かして、プロジェクト全体をより良くするための共同作業をしているのだ、という気持ちから始めれば、「譲れるところ」と「譲れないところ」という対立が出てくる余地はありません。あるのは、「こうするとプロジェクト全体に良い」か、「これだけではダメで別のやり方をしないとプロジェクト全体には役に立たない」かの違いだけです。
ー濱野 純 『入門Git』 秀和システム、 p.179
2011-01-25
GIT - The information manager from hell
Gitのソースコードを見てたら、どうもそんなことが書いてあるwww
面白いなと思っていろいろ探してるうちに、初期コミットに行き着いた。
commit e83c5163316f89bfbde7d9ab23ca2e25604af290
Author: Linus Torvalds
Date: Thu Apr 7 15:13:13 2005 -0700
Initial revision of "git", the information manager from hell
なんともこうLinusさんは、面白いなぁ。
2011-01-07
マージ後のreset HEAD^は危険だった
直前のマージを取り消す場合は、
× git reset --hard HEAD^
ではなく、
○ git reset --hard ORIG_HEAD
としないと危ない、という話。
「マージ後にgit reset --hard HEAD^で取り消し」は去年の日記でもけっこう使ってるけど、たまたま上手くいっていたからよかったが、ORIG_HEADが正しい指定方法だった。場合によってはちょっと危ない。



