──「心をgitで管理する世界」の物語で、commitしなかったものは戻らない
〈ショートストーリー〉
朝、目が覚めて最初にすることは、checkoutだ。
git checkout 会社
背筋が少し伸びる。語尾が丁寧になる。昨日の夜、恋人の前で笑っていた私は、いったん引っ込む。引っ込むだけだ。消えるわけじゃない。
会社で、私は会社の私を生きる。きちんと挨拶して、要領よく断って、誰も傷つけない冗談を言う。これも、私だ。芝居じゃない。
夕方、git checkout 恋人。
口ぐせが変わる。「えーと」が「ねえ」になる。会社では絶対に出ない弱音が、するりと出る。これも私だ。どっちが本物か、なんて問いは意味がない。両方本物だ。
切り替えの一瞬だけ、たまに変なことが起きる。
恋人に、つい、会社の口調が出る。
<<<<<<< 会社
お疲れさまです
=======
ただいま
>>>>>>> 恋人
同じ一行を、二人の私が一瞬、奪い合う。すぐに片方が引っ込む。たいていは笑ってごまかせる。
夜、その日をcommitする。
ぜんぶはしない。何を残すかは選べる。git add。
私は、その日の出来事を選り分けた。大きいこと ── 仕事の成果。節目になった一日。そういうのはaddする。
ちいさいことは、addしなかった。なんでもない夕方。意味のない雑談。「今日、空がきれいだった」みたいな、一行にもならない何か。ごみだ、と思った。残すほどのことじゃない。addしなかった変更は、翌朝のcheckoutできれいに消えた。
そういう日が続いた。私のlogには、大きいことだけが、節目だけが、整然と並んだ。
ずっとあとになって、私は、なんでもない夕方を、もう一度見たくなった。
誰かとどうでもいい話をして、ただ笑っていた、あの夕方。何を話したかも覚えていない。ただ、あれはよかった、という感触だけが残っていた。
checkoutしようとして ── 無いことに気づいた。
commitしていなかった。ごみだと思ってaddしなかった。だからlogのどこにも無い。
捨てたのではない。はじめから、無かったことになっていた。戻る場所さえ無い。
その日から、私はちいさいこともcommitするようになった。
「今日、空がきれいだった」。一行にもならない、何か。それが、いつか取り返したくなるものかどうか、その日の私には分からないから。
分からないから、とりあえず刻んでおく。
〈技術ノート〉── branch / commit
ノートは答え合わせではない。物語が嘘をついた、ちょうどその場所の地図である。
物語が嘘をついた場所
「会社の私」「恋人の私」── 物語は、ブランチを別々に実在する別人のように描いた。
ここが嘘だ。
ブランチは、人ではない。特定のcommitを指す、ただの可動ポインタ(ref)にすぎない。会社も恋人も、同じひとつのリポジトリの中にある。同じオブジェクトDBを共有していて、違うのはHEADがどの枝先を指しているか、それだけだ。
git checkout(今はgit switchが推奨)がしているのは、人格の交換ではないHEADを別のブランチに付け替え、作業ツリーをその時点の中身に合わせることだ。語彙や口ぐせが変わって見えても、土台のオブジェクトは全部ひとつ。
だから「多面性=分裂」ではない。会社の私も恋人の私も、別々の自分が住んでいるのではなく、ひとつの私の、HEADの位置違いだ。芝居でないのも、本当だ。
「刻む」は二段階 ── そして、捨てたものは戻らない
「その日をcommitする」のは、一息ではない。二段階ある。
-
git add── その日の変更から「これは残す」と選んで、ステージング(index)に載せる。 -
git commit── 載せたものだけを、履歴に確定する。
起きたこと全部が、自動で履歴になるのではない。何を残すかを、addで選ぶ。 gitは、作業を三つの場所で持っている ──作業ツリー(実際に起きたこと)/ステージング(index)(残すと選んだもの)/履歴(commitしたもの)。
問題は、選ばなかった ──「残さない」ほうだ。
gitの世界で、本当に取り返しがつかないのは、間違えたcommitではない。一度commitしてしまえば、後から手当てする道がいくつもある。だが、一度もcommitしなかったものには、その道すら無い。 ごみだと思ってaddせず、checkoutやcleanで消した変更は、捨てたのではなくはじめから無かったことになる。戻る場所が、無い。
そして人は、その瞬間に、何が後で大切になるかを、たいてい見誤る。だからgitの実務でも言う ──commitは、こまめに。 残すコストは小さく、失う代償は永遠だから。
物語が、ここでは嘘をついていない場所
addしなかった変更が翌朝消える ── これは、ほぼ事実だ。ステージングにも履歴にも載っていない未commitの変更は、まだどこにも属していない。その状態で別のブランチにcheckoutすると、未保存の変更は上書き・喪失されうる。残したいならgit commit、まだcommitしたくないならgit stash(一時退避)。
正しい名前
| 物語の言葉 | gitの正名 |
|---|---|
| 会社の私/恋人の私 | branch(commitを指す可動ポインタ。実体は同一repo) |
| 切り替える | checkout / switch(HEADの付け替え+作業ツリーの更新) |
| 何を残すか選り分けて載せる | add(staging / index)(作業ツリーと履歴のあいだの、選り分けの場) |
| 載せたものを確定する | commit(ステージングの内容を履歴に刻む。「刻む」はadd → commitの二段) |
| ごみだと思ってaddしなかった夕方 |
未commitの変更(checkout / cleanで消え、復旧する道が無い。commit済みの手当ては → 第9章) |
| 一時的に取っておく(※本文未使用) | stash |
要点
- ブランチは別人ではなく、ポインタだ。 多面性は分裂ではない。どの「私」も、同じひとつのリポジトリのHEAD違い。
-
「刻む」は二段階(add → commit)。 起きたこと全部ではなく、
addで選んだぶんだけが残る。作業ツリー/ステージング/履歴の、三層。 - 本当に戻らないのは、commitしなかったもの。 commitしたものには後で手当ての道があるが(→ 第9章)、一度もaddしなかった変更には戻る場所が無い。何が後で大切になるかは、その時には分からない ── だから、こまめに刻む。
- 消したくないならcommitかstash。 未保存の作業ツリーは、切り替えの瞬間にいちばん簡単に失われる。