😃

もうこれ以下は無理というぐらい最低限なバージョン管理

2020/09/23に公開

元記事はこちら

いいからgit使え

もうファイル名に日付とか「最終」とか付けるな.文字しか書いてないWordファイルとかExcel方眼紙とかはこの際目をつぶる.それはもう仕方ない.だがファイル名によるバージョン管理だけは駄目だ.

まずGitHubにアカウントを作れ.そんな名前も知らない会社のウェブサービスは使いたくないだって?お前Word使ってるだろ.

それからSourceTreeをインストールしろ.そんな名前も知らない(略)お前Trello使ってるだろ.使ってない?今すぐ使え.

よし,準備は出来たな.

新しい仕事を始める時,まず何をする?そう,空のフォルダを作るよな.ちょっと待った.今後は手元のコンピュータ上に空のフォルダを作るんじゃなくて,GitHubに作るんだ.GitHubに作るフォルダはリポジトリと言うぞ.リポジトリはただのフォルダじゃなくて,ファイルの履歴を管理できるんだ.うっかり全世界公開してしまわないように,大事なリポジトリはプライベートにしておくように.あとREADMEファイルは自動生成させておこう. “Initialize this repository with a README” にチェックを入れておけば完璧だ.


(GitHubで新たにリポジトリを作るところ)

GitHubは君から遠いところにある.だからGitHubに作ったリポジトリをリモートリポジトリと言う.そして,君はこれからそのリモートリポジトリのクローンを手元のコンピュータに作るんだ.手元にあるやつはローカルリポジトリと言うよ.リモートとローカルは常に同期させて使うんだ.gitに詳しいやつは黙ってろ.

なんでリモートとローカルの二本立てにするのか?

いい質問だ.

いいか,ネットはいつも繋がってるとは限らないだろ.だけどローカルつまり手元のコンピュータが生きてる限り,ファイルの更新は続けられるって事だ.ネットが復活した時にまたローカルとリモートを同期させたらいい.

と言うわけで,まずGitHubに作った空っぽのリモートリポジトリをローカルにクローンするぞ.まず空っぽの作業フォルダを作る.名前はリポジトリと同じにしておいたほうが良かろう.次にGitHubのリポジトリの画面で “Clone or download” プルダウンボタンを押してURLを表示させる.右上の緑色のボタンだ.


(GitHubからリポジトリをクローンするためのURLを取得する)

表示させたURLをコピーしたら,SourceTreeの “New…” プルダウンボタンから “Clone from URL” を選んで,表示されたシートの “Source URL” にコピーしたURLをペーストする.そして “Destination Path” に作ったばっかりの空のフォルダを指定する.その後 “Clone” ボタンだ.

これでローカルリポジトリが作られたぞ.

ではこのフォルダの中に新しいファイルを作ろう.WordファイルでもExcelファイルでも良いが,筆者はRTFファイル(リッチテキスト形式ファイル)にしてみた.RTFはWordでもWindows付属のワードパッドでも編集できる.Macならやはり付属のテキストエディットで編集できるよ.


(RTF(リッチテキスト形式)の文書を作る)

文書を書いたら保存.


(作業フォルダの中身)

保存したら,ローカルリポジトリを更新する.SourceTreeで保存したファイルにチェックマークを入れて,コメントを残して,更新するんだ.


(SourceTreeでいま作ったファイルにチェックマークを入れて,コメントを残して,更新(コミット)する)

ちょっと細かい話になるが,チェックマークを入れることをステージングと言って,コメントを書いてローカルリポジトリを更新することをコミットと言うんだ.これはgitというSourceTreeの裏で動いているコマンドのお作法な.ステージングとコミットが別々なのはgitの作者が変態野郎だから仕方ないと思ってくれ.

ある程度作業が進むたびに,ステージングして,コメントをつけてリポジトリにコミットしよう.コミットはゲームで言えばセーブポイントだと思ってくれ.コミットしてしまえば,いつでもそこに戻れる.

さて,ネットに繋がっていればローカルリポジトリの更新をリモートに反映させておこう.この作業をプッシュと言う.プッシュは “Repository” メニューの “Push…” からやってもいいし,ツールバーのアイコンでやってもいい.


(プッシュするところ)

実はこの作業は自動化できる.ネットに安定的に繋がっている場合,コミットとプッシュは同時にできるんだ.次の図のようにコミットするときに “Push changes immediately to origin/…” のチェックボックスをオンにしておけばいい.


(コミットとプッシュを同時にする)

ネットに繋がっていない場合,プッシュだけ失敗するから,ネットに繋がったときに改めてプッシュするといいよ.

さて,いくらか作業が進んだらリポジトリはこんなふうになるだろう.


(連続コミットした結果)

この一直線に伸びた履歴をコミットグラフと言うよ.SourceTreeというか,その裏で動いているgitはこのコミットグラフを縦横無尽に編集できる恐ろしいツールなのだが,その機能を全部使う必要はない.

そこで,ありがちなシチュエーションについてだけ対処方法を書いておくよ.

あああ!作業をロールバックしたい!

大丈夫だ.

途中で気が変わったとか,仕様が変更されたとか,メテオフォールだとかで作業をロールバックしなくちゃいけないことは多々ある.そんなときのためのセーブポイント,いやコミットだ.

まず今書きかけの内容もステージングしてコミットしてしまおう.捨てるには惜しいからね.次に,戻りたい場所を探そう.ほら,コメント書いといて良かっただろ?

さて,これからロールバックをするわけだが,念の為エディタアプリ(Wordとかワードパッドとかテキストエディットとか)は閉じておこう.ファイルが一瞬にして過去に戻るわけだが,アプリがそれを想定していない可能性がある.一旦眠っておいてもらおう.

ロールバックしたいコミットを見つけたら,SourceTreeでダブルクリックする.これでファイルをロールバックできる.これをチェックアウトと言う.なんでチェックアウトと言うかというと,太古の昔にコミットのことをチェックインと呼んでいたころの名残だ.(本当にチェックインしたことのあるやつだけが筆者に文句を言え.)


(歴史を巻き戻す)

で,ロールバックしたものをそのまま納品すればいいときは,特にやることはない.

いや,ひとつある.

後で振り返ったときに,どのコミットを納品したかわからなくなると困るよね.そこでタグを打っておこう.


(タグを打っているところ)


(打たれたタグの確認)

もちろん,ロールバックしなかったとしても,納品した時点でタグを打つのは良い習慣だ.

あああ!ロールバックしたところからやり直したい!

大丈夫だ.

先程のやり方でロールバックしたあと,枝分かれのための名前をつけよう.この分かれた枝をブランチと言う.元々の枝,いや幹と言ったほうが正しいが,こちらには master という名前が自動的に付けられている.新しいブランチには AfterFirstImpact という名前を付けてみよう.


( ロールバック後にブランチを作成しているところ)


(新しいブランチができたところ)

この後は,これまで通りファイルを更新して,ステージングして,コメントを付けてコミットすればいい.コミットグラフが分岐するのがわかるだろう.


(ブランチに新しい変更をコミットするところ)


(コミット後の状態)

作業が進んで,納品することになったらタグを打っておけばいい.

あああ!分岐したけどやっぱり元のトラックに戻りたい!

大丈夫だ

まず書きかけの内容をステージングしてコミットしておこう.続いて,元のトラックの任意のコミットをチェックアウトしよう.

以上だ.

もっと困ったら

一人で作業している場合は,これまでの説明でほとんどのケースには対処できると思う.おそらく99%は大丈夫だろう.残り1%のケースには

枝分かれしちゃった作業内容を統合したい

というのがあるだろう.これは実は厄介で,もしプレーンテキストならばある程度省力化できるのだが,WordやExcelファイルだと人手でやるしか無い.まず,重複しないようにふたつのバージョンをチェックアウトしなければならない.

複数のフォルダを作ってそれぞれチェックアウトする手もあるけれど,ファイル名が一緒だとWordやExcelが混乱するので,混ぜたいバージョンをそれぞれバージョンA,バージョンBとすると

  1. バージョンAをチェックアウトして,ファイル名の末尾にAとかを付けておく
  2. バージョンBをチェックアウトして,ファイル名の末尾にBとかを付けておく
  3. バージョンAとバージョンBを見比べて,再利用できそうな部分が多い方を再度チェックアウトする
  4. バージョンA,バージョンBを横に見つつ,チェックアウトしたファイルを書き直す
  5. 書き直したファイルをステージングして,コメントに「何々を合流した」と書き込んでコミットする
  6. バージョンA,バージョンBのファイルとも捨てる

ぐらいな手順が良いと思う.


(複数のブランチを手動で合流させたところ)

この方法の残念なところは,コミットグラフが合流しないところだ.コミットグラフが合流していると,それを見ただけで「バージョンAとバージョンBはここで合流したんだな」とわかるのだが,ここで紹介した方法だとコメントを読んでいかないとわからない.また捨てた方の枝が今後伸びた場合に,どこから合流させたのかがわかりづらくなってしまう.

こういう枝分かれはそう頻繁に起こることではないので,ここらへんで良しとしてほしいのだが,折角なのでコミットグラフの合流方法を最後に「もっともっと困ったら」編として書いておくことにする.

もっともっと困ったら

どうしても複雑なコミットグラフを扱わないと行けない場合は,マージコミットという特殊なコミットが必要になる.特殊と言っても,マージコミットそのものは難しくない.問題はコミットが競合することなのだが,先程の手順で競合を解決している場合は,後は手続きだけでコミットグラフを完成させられる.

いま main ブランチを幹だと思って,途中から枝分かれした AfterFirstImpact ブランチを幹の先端に手動で合流させたところだとしよう.なので,現在は main ブランチの先端にいることになる.これから AfterFirstImpact ブランチが main ブランチの先端を向くようにしたいので AfterFirstImpact ブランチの先端をチェックアウトする.


(AfterFirstImpactブランチの先端をチェックアウトする)

続けて AfterFirstImapct ブランチから main ブランチの先端をマージコミットする.


(AfterFirstImpactブランチからmainブランチの先端をマージコミットする)

そうするとコミットが競合してるよというメッセージが出るが,そのまま “OK” を押して先へ進む.


(競合を伝えるメッセージ)


(競合した状態)

作業ファイルに競合を示すマークが付けられているので,コンテキストメニュー(右クリック)で “Resolve Conflicts” から “Resolve Using ‘Theirs’” を選ぶ.ここで ‘Theres’ とは main ブランチのことで,つまり main ブランチのファイルをそのまま残すという意味だ.これで AfterFirstImpact ブランチは無事に main ブランチと統合された.


(AfterFirstImpactブランチがmainブランチをマージコミットによって取り込んだ状態)

だが実はここで話は終わらない.まだ main ブランチが AfterFirstImapct ブランチの一歩手前にいるのだ.そこで main ブランチをチェックアウトする.そして AfterFirstImpact ブランチをマージコミットする.今度は競合がないので何の文句もなく main ブランチが更新される.


(mainブランチをチェックアウトしてAfterFirstImpactブランチをマージコミットした状態)


(その結果をプッシュした状態)

この後は引き続き main ブランチを使い続ければいい.もちろん出来るだけ早く main ブランチをリモートリポジトリにプッシュしておこう.

というわけで,金輪際ファイル名でバージョン管理なんてしないように.

Discussion