2010年03月06日

Gitのユーザマニュアルを読んでのメモ

Gitのユーザマニュアルの非公式日本語訳を読んでの個人的メモ。訳してくれた人に感謝。以下、個人的に実験した内容も含む。
gitkの起動時のオプション
gitkを起動するとき、「--all」をつけると、現在のブランチの履歴だけでなく、全てのブランチの履歴を見ることができる。gitkを起動するとき、「--not <ブランチ名>」とすると、指定されたブランチは表示されない。「gitk --all --not master」で、masterブランチ以外の全てのコミットを表示する。
強制pushと強制fetch
強制pushする時、「-f」の代わりに「+」でもいけるらしい。
git push -f ssh://(略) master
git push ssh://(略) +master

同様に、強制fetchする時、「-f」の代わりに「+」でもいけるらしい。
git fetch -f git://(略) master:ref/(略)
git fetch git://(略) +master:ref/(略)
リベースでコンフリクトした時の作業手順
1.「git status」でコンフリクトしているファイルを確認
2.「git mergetool」やその他のマージツール、または手作業で修正
3.「git add [修正したファイル名]」でコンフリクトが解消した事を通知
4.「git rebase --continue」でリベースを継続
※どの時点でも「git rebase --abort」でリベース前に戻せる
「.git/objects/」内のファイルの格納ルール
「.git/objects/」の下にはサブフォルダがあり、そのフォルダ名はオブジェクトIDの最初の2文字となっている。ファイル名はオブジェクトIDの最初の2文字を削除したものになっている。つまり、オブジェクトIDが「123456...」のファイルは、「.git/objects/12/3456...」に格納される。
リポジトリが破損した時用のメモ
「git fsck」でリポジトリの検証。「git fsck --full」で完全な検証を行える。
破損していた場合、破損したBLOBオブジェクトのIDやそれを参照しているツリーオブジェクト等の情報が表示される。リポジトリのクローン先やクローン元に破損したオブジェクトを入手し、「.git/objects/」配下に格納する。
破損したファイルが見つからなかった場合、「git ls-tree <ツリーID>」で破損したBLOBオブジェクトのファイル名を確認する。作業ディレクトリ内に運良く元のファイルらしきものが残っている場合、「git hash-object <ファイルパス>」でオブジェクトID確認できる。「git hash-object -w <ファイルパス>」でオブジェクトを生成し「.git/objects」配下に格納する。
元のファイルが見つからなかった場合、「git log --raw --all --full-history -- <ファイルパス>」でコミットの履歴を表示する。これにより、履歴の前後のコミットIDやコミット時のコミットメッセージが確認できるので、破損したファイルを再現できる可能性がある。再現できた場合、「git hash-object <ファイル>」でオブジェクトIDの確認、「git hash-object -w <ファイル>」でオブジェクトの登録を行う。
復旧できなかったとしても、紛失したオブジェクトは、特定のバージョンの特定のBLOBオブジェクトであるため、状況により「git fsck」の警告を無視することも可能らしい。
破損したBLOBオブジェクトの子孫にあたるファイルが残っているのであれば、履歴が分断する事にはなるが、リポジトリから一度ファイルを削除した後に子孫ファイルを再度登録したほうが安全ではないかと思った。
雑多なメモ
「git show」や「git log」に「--pretty=raw」をつけると、ツリーID、親コミットID等の詳細な情報を見ることができる。

「git mv」等でファイル名の変更があった場合、「git diff」は異なるオブジェクトとして認識するが、「git diff -M」とすると名前の変更を認識し、同一ファイルとして扱う。

Gitで管理するファイルのパーミッションは755か644のいずれかになる。Gitは実行権限だけを管理する。

「git ls-tree <コミットID>」でtreeの情報を表示できる。コミットIDを省略すると現在のコミット。
「git ls-show <レビジョン:パス>」でtreeやblobの中身を確認できる。

「git cat-file [blob|tree|commit|tag] <id>」でそれぞれの詳細な情報を表示できる。

「git tag」では、「軽量タグ」というものを作成できるらしい。詳細は不明。

「git count-objects」で、オブジェクト数を確認できる。

「git gc」は、「git repack」と「git prune」を実行する高レベルのコマンド。

「git ls-files --stage」で索引(index,ドキュメントによってはステージ(stage)と呼ぶこともある)の中を確認できる。

「git log branch1..branch2」branch1には含まれないがbranch2に含まれるコミットを一覧する。
「git log branch1...branch2」branch1かbranch2のどちらかにのみ含まれるコミットを一覧する。

「git diff branch1 branch2」と「git diff branch1..branch2」と「git diff branch1...branch2」の出力の違いがわからない。そのうち調べる。
その他
「Linuxのサブシステム管理者がtopicブランチを管理する方法」の部分が難しい。
サブモジュールは運用方法を気をつけないとまずそう。「Chapter 8. サブモジュール」をよく読むこと。
「Chapter. 9」以降は未整理。

2010年03月03日

Firefox限定 加速度センサーとCSSのTransform2Dをあわせて使う

Firefox3.6からJavaScriptから加速度センサーの値を取得できるようになりました。この手のセンサーは、移動方向というよりも筐体の傾き検出の方が向いているはずなのですが、そのようなデモがあまりないようなので簡単に実装してみました。Firefox3.6から加速度センサーを利用できる環境が必須です。MacBook系であれば大丈夫なはずです。
バージョン3.6のFirefoxは、加速度センサーに対応していますが、Transform3Dには対応していません。逆に、最新のSafariでは既にTransform3Dに対応しているのですが加速度センサーには対応していません。iPhone用のSafariはTransform3Dに対応していますが、加速度センサーは縦横の方向しか取得できません。加速度センサーとTransform3Dの両方に対応したブラウザが登場し、面白いアイディアのものが色々出てくるのが楽しみですね。
関連エントリー
iPhone/iPod touchで、Transform3Dと加速度センサーの両方を使った例。

2010年03月02日

「git rebase --onto newbase upstream branch」の意味

やっと「git rebase」のちゃんとした動きを把握したと思うので書いておく。

前回のエントリーで「git rebase」は正確にはコミットの履歴の移動でないと書いたが、ここでは説明のしやすさから、『移動』という言葉を使用する。
履歴ツリー上でリベースするためには、「『どこから』『どこまで』を『どこに』移動するのか」を知る必要がある。もう少し整理すると、「移動する上流側(祖先側)の位置」「移動する下流側(子孫側)の位置」「移動先(新しい親)の位置」となる。

これら全てを指定するのが「git rebase [--onto <newbase>] <upstream> [<branch>]」という書き方になる。

定義は以下の通りのはず。

「移動先の位置」
<newbase>が使用される。
ただし、省略された場合は、<upstream>が使用される。
ブランチでなくてもよい。

「移動する上流側の位置」
<upstream>が使用される。
ただし、<upstream>が「移動する下流側の位置」の直接の祖先でない場合、<upstream>と「移動する下流側の位置」の共通の祖先の位置となる。
ブランチでなくてもよい。

「移動する下流側の位置」
<branch>が使用される。
ただし、省略された場合は、現在のブランチが使用される。
ブランチでなくてはならない。

また、移動するのは「移動する下流側の位置」から「移動する下流側の位置」の一本だけであり、履歴の枝が生えていてもそれらは無視される。これはリベースが実際にはコミットの履歴の移動ではなく、コミット内に記録されている変更内容を移動先に順番に適用していくため。
「ブランチのHEADをチェックアウト」し、「<newbase>と<branch>を省略」して「git rebase <ustream>」を実行した場合の動きは、履歴を「木」のメタファーで説明していると「接ぎ木をしている」ように見え、そう説明する人もいる。しかし、内部の動作はそうはなっておらず、同じ変更内容を持った別のコミットを生成している。Gitを学習する時に、表面上な動きだけではなく、内部構造がどうなっているのか把握しておいた方が良いと言われるのは、このようなところに理由があるのだろうと思った。

「git rebase」はコミットの移動ではない

「git rebase」はコミットの移動だと思っていたがコミットの再適用だった。以下実験。
$ git init
$ touch aaaaa
$ git add aaaaa
$ git commit -m "a"
$ touch bbbbb
$ git add bbbbb
$ git commit -m "b"
$ touch ccccc
$ git add ccccc
$ git commit -m "c"
$ git branch branch1
$ git branch branch2 HEAD^^
$ git checkout branch2
$ touch ddddd
$ git add ddddd
$ git commit -m "d"
これで次のような状態になる。「[]」は現在のブランチ、「.」に続くのはブランチ名。
 [d.branch2]
 /
a---b---c.branch1.master
次にbranch1をbranch2の先端にリベースしてみる。
$ git checkout branch1
$ git rebase branch2
結果は次のようになる。
  d.branch2---b---c.branch1
 /
a---b---c.master
ここでそれぞれのブランチの履歴を見てみる。
$ git checkout master 
$ git log --pretty="oneline"
7693a9a91c96c7650de8115545e254b58c822b3d c
fe9f674ad0b724fe995ccc94240d673ea5bde02e b
5652af90e342454863003be1218a7cf7851ac9b8 a
$ git checkout branch1
$ git log --pretty="oneline"
3466d40431341822e9acaed3837b5c0b3f9fc478 c
de4ffa617d694be1b23de94b1062c0e97fe1e7eb b
6c7d5011324965a2ec5a198f089d30e6437aee38 d
5652af90e342454863003be1218a7cf7851ac9b8 a
$ git checkout branch2
$ git log --pretty="oneline"
6c7d5011324965a2ec5a198f089d30e6437aee38 d
5652af90e342454863003be1218a7cf7851ac9b8 a
注目したいのはbranch1とmasterそれぞれのコミットのbとcのコミットIDが違うこと。つまりリベースは、コミットを単純に移動するのではなく、コミット内に格納している変更内容を移動先に順番に適用していくということらしい。根本的な考え方は、前回のエントリーに書いた「git commit -amend」や「git reset」と同じようだ。

「git commit --amend」と「git reset」の挙動

間違えてたらごめんなさい。

以下、現在のブランチの位置を「[]」で括って、到達不可能なコミットを「()」で括って表す。
「git commit --amend」の挙動
「git commit --amend」は、正確にはコミットを修正するのではなく修正したコミットを履歴ツリー上の「別の枝」にする作業らしい。例えば、以下のようなcが「あるブランチ」のHEADの時、
a---b--[c]
cをxに修正すると次のように見える。
a---b--[x]
でも、「--amend」を指定したときの実際の挙動は次のようになる模様。
     [x]
     /
a---b--(c)
この時、ブランチがx側に切り替わるために、cは到達不可能なコミットとなるため、「git log」等でも表示されないようだ。cのコミットIDが分かっている場合、チェックアウトでコミットcに切り替えられる。また、cにタグや別のブランチがあれば、cは参照可能なコミットなのでコミットIDを調べなくても切り替えることができる。
「git commit --amend」は過去のコミットも修正可能
最初に『「git commit --amend」では過去のコミットも修正できる』と聞いたときには次のような動作をすると思っていた。
修正前
a---b--[c]--d---e

修正後
a---b--[x]--d---e
しかし、実際には次のようになるらしい。
         [x]
         /
a---b---c--(d)-(e)
後はdとeを「git rebase」でxのHEADの位置に移動すれば良い。後からコミットIDを調べるのが面倒なので「git commit --amend」を実効する前に、eの位置に別のブランチやタグを作成しておくとリベースしやすい。
「git reset」の挙動
「git reset」も同様の動きを示す。
a---b--[c]
「git reset HEAD^」を実行すると次のようになる。
a--[b]-(c)
つまりresetはコミットを取り消すのではなく、「履歴を遡る」コマンドということらしい。この状態で新しいコミットxを作成すると分岐する。
     [x]
     /
a---b--(c)
Gitは全ての履歴を記録しているという意味がやっとわかった気がする。

2010年02月28日

Gitのサブコマンドの概略を訳してみた

自分の環境のzshで「git 」と入力後にtabを押したら表示されるサブコマンドの一覧を訳した自分用のメモ。
これくらいの英語はサラッと読めるようになりたいけどそうも言っていられないので...。
意訳と直訳が混在しているし、多分内容も随分間違えているはず。
間違いがあったら遠慮なく指摘して下さい。
gitのコマンドはコマンドを多く覚えるよりも、基本的なコマンドのオプションを覚えた方が良さそうなのであまり役に立たないかも...。
バージョンは1.6.2.1。
add                 -- インデックスにパスを追加 -- add paths to the index
am                  -- メールボックスからパッチを適用する(applymboxよりもかっこいい) -- apply patches from a mailbox (cooler than applymbox)
apply               -- Gitインデックスファイルとワークツリーにパッチを適応する -- apply patch on a git index file and a work tree
applymbox           -- メールボックスからパッチを適用する -- apply patches from a mailbox
applypatch          -- Eメールから抜き出したひとつのパッチを適応する -- apply one patch extracted from an e-mail
archimport          -- Arch(というバージョン管理システム)のレポジトリをGitにインポートする -- import an Arch repository into git
bisect              -- バグが混入した変更を探す find the change that introduced a bug
branch              -- ブランチの作成と表示をする -- create and show branches
cat-file            -- リポジトリオブジェクトのコンテンツまたはタイプの情報を提供する -- provide content or type information for repository objects
check-ref-format    -- 参照名が正しいかを確認する -- makes sure that a reference-name is well formed
checkout            -- ブランチのチェックアウトと切り替えをする -- checkout and switch to a branch
checkout-index      -- インデックスからワーキングディレクトリにファイルを複製する -- copy files from the index to the working directory
cherry              -- 上流(のリポジトリ)にマージされていないコミットを探す -- find commits not merged upstream
cherry-pick         -- 既存のコミットの効果をつまみ食いする(一部だけ適応するの意) -- cherry-pick the effect of an existing commit
clone               -- リポジトリを新しいディレクトリに複製する -- clones a repository into a new directory
clone-pack          -- リポジトリを現在のリポジトリに複製する(移す) -- clones a repository into the current repository (transport)
commit              -- 変更をリポジトリに記録する -- record changes to the repository
commit-tree         -- 新しいコミットオブジェクトを作成する -- creates a new commit object
convert-objects     -- 古い形式のGitリポジトリを変換する -- converts old-style git repository
count-objects       -- パックされていないオブジェクトの数とそれらのディスク消費量を表示する -- count unpacked objects and display their disk consumption
cvsimport           -- CVS(というバージョン管理システム)のリポジトリをGitにインポートする -- import a CVS "repository" into a git repository
daemon              -- Gitリポジトリのための本当に簡単なサーバを起動する -- starts a really simple server for git repositories
diff                -- コミットとコミットや作業ツリー等との間の変更を表示する -- show changes between commits, commit and working tree, etc.
diff-files          -- 作業ツリーとインデックス内のファイルを比較する -- compares files in the working tree and the index
diff-index          -- インデックスとリポジトリ間のコンテンツとBLOBのモードを比較する -- compares content and mode of blobs between index and repository
diff-stages         -- インデックスファイル内のふたつの"マージステータス"を比較する -- compares two "merge states" in the index file
diff-tree           -- ふたつのツリー経由でコンテンツとBLOBのモードを比較する -- compares the content and mode of blobs found via two tree objects
fetch               -- 別のリポジトリからオブジェクトとHEADをダウンロードする -- download objects and a head from another repository
fetch-pack          -- 他のリポジトリから紛失したオブジェクトを受け取る -- receive missing objects from another repository
format-patch        -- Eメールで提出するパッチを用意する -- prepare patches for e-mail submission
fsck-objects        -- データベース内のオブジェクトの接続性と妥当性を検証する -- verifies the connectivity and validity of the objects in the database
get-tar-commit-id   -- tarツリーを使用して作成されたアーカイブからコミットIDを抽出する -- extract commit ID from an archive created using tar-tree
grep                -- パターンに一致した行を書き出す -- print lines matching a pattern
hash-object         -- ファイルからオブジェクトIDを算出する -- computes the object ID from a file
http-fetch          -- HTTP経由でリモートのGitリポジトリをダウンロードする -- downloads a remote git repository via HTTP
index-pack          -- 既存のパックされたアーカイブのインデックスファイルのパックをビルドする -- build pack index file for an existing packed archive
init-db             -- 空のGitオブジェクトデータベースを作成する -- creates an empty git object database
local-fetch         -- ローカルシステム上の別のGitリポジトリを複製する -- duplicates another git repository on a local system
log                 -- コミットログを表示する -- shows commit logs
lost-found          -- 運良くまだprune(コマンド)されていない紛失した参照を回復する -- recovers lost references that luckily have not yet been pruned
ls-files            -- インデックス/作業ディレクトリ内のファイルの情報 -- information about files in the index/working directory
ls-remote           -- リモートかローカルのリポジトリ内の参照を表示する -- shows references in a remote or local repository
ls-tree             -- 人が読める形式でツリーオブジェクトを表示する -- displays a tree object in human-readable form
mailinfo            -- ひとつのEメールメッセージからパッチを抽出する -- extracts patch from a single e-mail message
mailsplit           -- メールボックスファイルからファイルの一覧に分割する -- splits an mbox file into a list of files
merge               -- すばらしく統合されたマージドライバ -- grand unified merge driver
merge-base          -- マージ可能な共通の祖先を探す -- finds a good common ancestor as possible for a merge
merge-index         -- マージが必要なファイルのマージを実行する -- runs a merge for files needing merging
merge-one-file      -- マージインデックスを使用する標準のヘルパープログラム -- standard helper-program to use with merge-index
mktag               -- タグオブジェクトを作成する-- creates a tag object
mv                  -- ファイルやディレクトリやシンボリックリンクを移動やリネームをする -- moves or renames a file, directory, or symlink
name-rev            -- 指定されたリビジョンのシンボリック名を探す -- find symbolic names for given revisions
octopus             -- ふたつ以上のコミットをマージする -- merges more than two commits
pack-objects        -- オブジェクトのパックされたアーカイブを作成する -- creates a packed archive of objects
parse-remote        -- 「$GIT_DIR/remotes/」の解析を支援するルーチン -- routines to help parsing $GIT_DIR/remotes/
patch-id            -- パッチ用の一意なIDを算出する -- computes unique ID for a patch
peek-remote         -- upload-pack(コマンド)のプロトコルを使用しリモートリポジトリ上の参照を一覧する -- lists references on a remote repository using the upload-pack protocol
prune               -- オブジェクトデータベースから全ての到達不可能なオブジェクトを刈り取る(prune:枝を切り落とす|コミットの履歴が木に準えているため) -- prunes all unreachable objects from the object database
prune-packed        -- パックファイル内の既に余分なオブジェクトを削除する -- removes extra objects that are already in pack files
pull                -- リモートリポジトリからフェッチしマージする -- fetch from and merge with a remote repository
push                -- 関連づけられたオブジェクトを一緒にリモートの参照を更新する -- update remote refs along with associated objects
read-tree           -- ディレクトリインデックスからツリーの情報を読み取る -- reads tree information into the directory index
rebase              -- ローカルコミットを新しい上流のHEADに接ぎ変える -- rebases local commits to new upstream head
receive-pack        -- send-pack(コマンド)によりプッシュされたものを受信するために呼び出されるコマンド -- command invoked by send-pack to receive what is pushed to it
relink              -- ローカルリポジトリ内の共通のオブジェクトをハードリンクする -- hardlinks acommon objects in local repositories
repack              -- リポジトリ内のパックされていないオブジェクトをパックする -- packs unpacked objects in a repository
request-pull        -- 保留中の変更の要約を生成する -- generates a summary of pending changes
reset               -- 現在のHEADを指定されたステージにリセットする -- resets current HEAD to the specified state
resolve             -- ふたつのコミットをマージする -- merges two commits
rev-list            -- 時系列の逆順にコミットオブジェクトを一覧する -- lists commit object in reverse chronological order
rev-parse           -- 他のGitコマンドのためにパラメータを取り出し操作を加える -- picks out and massages parameters for other git commands
revert              -- 既存のコミットに戻す -- reverts an existing commit
send-email          -- 「format-patch --mbox」の出力のパッチEメールを送信する -- sends patch-e-mails out of "format-patch --mbox" output
send-pack           -- リモートリポジトリにすぐれたpushをする -- pushes to a remote repository, intelligently
shortlog            -- Gitログの出力を要約する -- summarizes git log output
show-branch         -- ブランチとそれらのコミットを表示する -- shows branches and their commits
show-index          -- パックのインデックスファイルの内容を表示する -- displays contents of a pack idx file
ssh-fetch           -- SSH接続でリモートリポジトリからpullする -- pulls from a remote repository over an SSH connection
ssh-upload          -- ssh-fetch(コマンド)により使用されるサーバ側のヘルパープログラム -- helper "server-side" program used by ssh-fetch
status              -- 作業ツリーのステータスを表示する -- shows the working-tree's status
stripspace          -- 空行をフィルタリングする -- filters out empty lines
svnimport           -- SVN(というバージョン管理システム)のリポジトリをGitにインポートする -- imports a SVN repository into git
symbolic-ref        -- シンボリック参照を読み込み修正する -- reads and modifies symbolic references
tag                 -- GPGで著名されたタグオブジェクトを作成する -- creates a tag object signed with GPG
tar-tree            -- 指定されたツリー内のファイルのtarアーカイブを作成する -- creates a tar archive of the files in the named tree
unpack-file         -- BLOBの中身を持つテンポラリファイルを作成する -- creates a temporary file with a blob's contents
unpack-objects      -- パックされたアーカイブのパックされていないオブジェクトを出力する -- unpacks objects out of a packed archive
update-index        -- 福数の指定された方法でインデックスを修正する -- modifies the index in some given way
update-ref          -- 参照に格納されたオブジェクト名を安全に更新する -- updates the object name stored in a reference safely
update-server-info  -- ダンプサーバの補助情報を更新する -- updates auxiliary information on a dumb server
upload-pack         -- clone-pack(コマンド)とfetch-pack(コマンド)に呼び出されるコマンド -- command invoked by clone-pack and fetch-pack
var                 -- Gitの論理変数を表示する -- displays a git logical variable
verify-pack         -- パックされたGitのアーカイブファイルを検証する -- validates packed git archive files
verify-tag          -- タグのGPG署名を照合する -- checks the GPG signature of a tag
whatchanged         -- コミットログとそれらにより導入された差分を表示する -- shows commit-logs and differences they introduce
write-tree          -- 現在のインデックスからツリーを作成する -- creates a tree from the current index
2010/02/28 追記
am,applymboxが「メールボックスからパスを適応する」となっていたのを修正。(id:ujihisaさんからの指摘)
patch-idが「Apatch(パッチ?)用の一意なIDを算出する -- computes unique ID for a apatch」となっていたがapatchではなくpatchらしい。zshの補完関数のbugかもとのこと。(id:ujihisaさんからの指摘)
2010/03/01 追記
am,applymboxが「メールボックスからパッチを適応する」となっていたのを修正。(id:nankiさんからの指摘)