Chienomi

バージョン管理システム(Git/Mercurial)をローカルに活用する

Live With Linux::practical

以前、Git/Mercurialの記事を書いたときもそうだったが、どうも世の中の人(特に職業エンジニア)はGitがGitHubありきのもので、GitHubのためのツールであると認識している節がある。

もちろん、実際はそのようなことはない。Linuxカーネル開発のために誕生したGit及びMercurial(両方とも目的は同じである)は従来型の集中バージョン管理システム(Subversion, CVS)と比べ個人的な利用にも適している。

ここでは、GitHubのためではなく、また業務としてのチーム開発のためでなく、個人、あるいは家庭でGit/Mercurialを使うためのHowToを詳解する。

なお、このテーマからもわかるように、この記事は初心者向けである。 最近Chienomiは初心者向けの記事が多いと感じているかもしれないが、その理由は初心者向けの記事ばかりが読まれているためである。

もしも、「もっと高度な、extreamelyな記事を読みたい」という方がいれば、コメントいただくか、Twitterでメンションいただくか、もしくは高度な記事に対して称賛のコメントをいただければそういう記事も増やしていこうと思う。 (今後高度な記事をそもそも書く予定がないという意味ではない)。

リポジトリを用意する

マスターリポジトリを作成する

分散バージョン管理システムにおいては、マスターリポジトリ(権威リポジトリ)を作成する必要はない。 だが、同期いとう面で考えると、間違いなく各リポジトリはマスターリポジトリの複製であったほうがやりやすい。

マスターリポジトリはGitではorigin、Mercurialではdefaultと呼ばれることもあるが、これは単に省略時のpush/pull先であって、マスターリポジトリであるとは限らない。また、マスターリポジトリであることと、直接のupstreamであることは異なる。 もっとも、ここでは「あるひとつのリポジトリを各リポジトリのupstreamにする」という話をしているのだが。

マスターリポジトリ作成の手順はGitとMercurialで異なっている。 だが、気をつけるべき点は共通だ。

可能であれば、独立したディスクであるほうが良い。 これは、ディスククラッシュ時や事故時に消失を避けやすいからだ。 (もちろん、色んなマシンがリポジトリを同期しているのならばもとよりそのリスクは抑えられているが)

そして、適切なヒエラルキーを持つことが望ましい。

さらにリポジトリを配置する各ホストからアクセスしやすいことか望ましいので、SSHでログインできるターゲット、例えばサーバー、NAS、せめてメインデスクトップなどに配置したい。SSHでログインできないとしても、SFTPはできるとか、なんらかの方法でマウントできるならそれでも良い。

たとえば、~/ExtraDiskがその追加ディスクのマウントポイントだとする。 であれば、

$ mkdir ~/ExtraDisk/Repositories

のようにしておくわけた。

次にマスターリポジトリを作成する。 ここではあなたのレシピ集を管理することにしよう。 Gitならば次のようにすることになる。

$ cd ~/ExtraDisk/Repositories
$ git init --bare recipes.git

Mercurialならこうだ。

$ cd ~/ExtraDisk/Repositories
$ mkdir recipes
$ cd recipes
$ hg init

ローカルワーキングリポジトリを作成する

メインデスクトップにマスターリポジトリを作成した場合など、同一マシン上で作業をし、なおかつそのマシンが明確に権威マシンであるならば、次のようにする。

$ cd Documents
$ git clone ~/ExtraDisk/Repositories/recipes.git

Mercurialでも同様。

$ cd Documents
$ hg clone ~/ExtraDisk/Repositories/recipes

分散ワーキングリポジトリを作成する

メインでないマシン、あるいは明確なメインが存在しない場合は基本的には次のようにする。

$ cd ~/Docuemnts
$ git clone ssh://repo/home/jrh/ExtraDisk/Repositories/recipes.git

Mercurialの場合はホームディレクトリからの相対パスになることに注意だ。

$ cd ~/Docuemnts
$ hg clone ssh://repo/ExtraDisk/Repositories/recipes.git

だが、これはいくつかの問題がある。 一番は、ホストの変更や、ディレクトリの移動に弱いことである。

そのためまずは、マスターリポジトリ側で常に一定のパスでアクセスできるようにする。

$ sudo mount --bind ~/ExtraDisk/Repositories /mnt/repos

さらに、~/.ssh/configを使ってrepoというマシンとしてアクセスできるようにする。

Host repo
  HostName masterpc.local
  User jrh
  IdentityFile ~/.ssh/masterpc_ecdsa

これで、ssh://repo/mnt/repos(Mercurialの場合はssh://repo//mnt/repos)としてアクセスできるようになった。 マシンが変わった場合は~/.ssh/configHostNameを変更すればいいし、ファイルパスが変わった場合はbindマウントするソースディレクトリを変更すれば良い。

なお、GVFS(GNOME/Cinnamon)の場合、fstabに書いておけばNautilusやNemoからマウントした場合でもfstab上のマウントポイントを尊重する。ファイルマネージャ上からユーザーレベルでマウントできて便利である。 別ディスクにマスターリポジトリがある場合、そのマウントポイントが一定でないとバインドマウントも都度コマンドをいじる必要があるので、マウントポイントはfstabに書いて固定するのが鉄則だ。

LAN環境とインターネット環境で経路を切り替える

インターネットごしではSSHログインに踏み台ホストが必要となる場合には、次のようにするのが良いだろう。

Host masterpc repo
  HostName masterpc.local
  User jrh
  IdentityFile ~/.ssh/masterpc_ecdsa

Host master-via-net
  HostName localhost
  Port 2222
  User jrh
  IdentityFile ~/.ssh/masterpc_ecdsa
  ProxyJump proxyhost

Host proxyhost
  HostName proxyhost.example.net
  User jrh
  IdentityFile ~/.ssh/proxyhost_ecdsa
  ServerAliveCountMax 3
  ServerAliveInterval 15

この設定では、masterpcではLAN内のマスターPCに、master-via-netでは同PCに対してインターネットサーバーを踏み台ホストとしてアクセスするようになっている。 ここでは、マスターPCはssh -R 2222:localhost:22 proxyhostのようにして予め踏み台ホストからポートフォワーディングするようにしていなくてはいけない。

いずれにせよ、インターネット越しかどうかでAgent Forwardingを行うかどうかの違いがある、ということが要点だ。 masterpcmaster-via-netどちらになるかはインターネット越しか、LANかで変わる。

もちろん、.git/config.hg/hgrcmasterpcmaster-via-netで書き換えることで運用することも可能だが、リポジトリの数が多いとなかなか面倒なことになる。

ここでポイントになるのが、Hostは複数書ける、ということだ。 これにより、リポジトリではupstreamの名前をrepoという名前に固定してしまう。 この名前を抽象化に利用し、

Host masterpc repo

としていればLAN内の方法でアクセスするし、

Host master-via-net repo

とすればインターネット越しのAgent Forwardingでアクセスする。 repoを書く位置を変更するだけで済むのだ。

NASなどSFTP可能なホストをマスターリポジトリにする

別の方法として、クローンする側がSSHFSなどで対象ディレクトリをマウントする、という方法もある。 これは対象のホストがSFTPによるアクセスのみを許可している場合でも有効であり、NASでも利用できる方法なので便利だ。

ただし、この方法はSSHFSが利用できるUnix系環境でないと難しい。Windowsだとそう簡単な話ではなくなってしまう。

しかし、NASを使うのであれば、WindowsではSMB/CIFSによってマウントするという方法をとれば、ローカルのディレクトリをクローンする感覚で扱うことができる。

注意点は、マスターリポジトリを含むファイルシステムのマウントポイントは固定しないとPush/Pullをしづらいことである。 このため、マウントポイントの固定には気を配ろう。

ホスティングする

マスターリポジトリをGitHub, GitLab, GitBucketなどにリポジトリを置く方法や、VPSなどに配置する方法ももちろんある。

便利な方法だが、プライベートなファイルを管理しづらいという問題があるほか、インターネット経由でなければならないというのは、稀ではあるが、場合によっては不便である。

ワーキングリポジトリのユーザーについて

「どのマシンで作業したか」が重要な情報であるならば、マシンごとにユーザーを変えるようにしたほうが良い。

ただし、GitHubなどで共同管理しているリポジトリへのコミットも複数マシンで行う場合は注意が必要だ。

作業する

作業を開始する

ひとり作業でない場合と同様に、ワーキングリポジトリでの作業開始時にはアップストリームを取り込む。

$ git pull

あるいは

$ hg pull
$ hg update

作業を完了する

ひとり作業である場合、コミットを練る必要はあまりない。 むしろ、競合を発生させるのが面倒なので、作業を終えるときは必ずコミットし、アップストリームに書くことを習慣づけよう。

$ git add -A
$ git commit -m "Laptop worked (halfway)."
$ git push
$ hg commit -A -m "Laptop worked (halfway)."
$ hg push

比較的大きな作業で、ちゃんとコミットログを残したい場合はブランチなどを使う。 しかし、普通、自分ひとりで扱う公開もしないリポジトリであればそのような必要はない。 巻き戻す可能性があるのなら別だが。

活用する

設定ファイル

もっとも典型的で基本的なのは、Unixシステムの設定ファイルである。

これは、共有するという意味もあるにはある。だが、それよりはスナップショットという意味があるだろう。 例えば以前はCinnamonやGoogle Chromeの設定ファイルはよく壊れていたが、このようなケースにおいて壊れる前の状態に巻き戻せるという意味がある。

ただし、バイナリファイルが多いと容量をとても取る場合があるので注意したい。

どんなことでも作業に

単純に継続的な作業において複数のマシンやラップトップでの持ち出し作業を行いたい場合にその同期に使うことができる。 単純なコピーでは、どの環境からどの環境に移すのかといった作業においてミスを発生するリスクが低くないことや、同じファイルに対して異なる環境で編集を加えたときが面倒なので、単純に複数マシンで作業したい場合において有効である。

もちろん、バージョン管理システムはバイナリファイルには向いてはいない。 だが、最近はGitがバイナリファイルを以前よりも上手く扱うようになったので、使えないというようなことはなくなった。

もしかしたらMicrosoft Officeのファイルは(XMLベースなので)テキストとして扱えるかもしれない。 (LibreofficeのファイルはXMLベースだが、残念ながらバイナリとして扱われる)

なお、バイナリファイルが多い場合や、ファイル数が膨大(万単位)である場合、GitよりもMercurialのほうが管理に適している。

知見

メインのワーキングリポジトリに直接pushしたらダメ?

おすすめはできない。

特にGitはデフォルトで禁止されており、なおかつpushした際にワーキングツリーを更新してしまうため、pushがしづらくなる。

Mercurialの場合はそれよりは容易だが、抽象化しづらく、ディレクトリを移動するのも難しくなってしまうためトータルで考えると不便だ。

マスターリポジトリはどこに置くべき?

GitHubに置く、という人が多いが、純粋にプライベートな内容をGitHubに上げるのは私は好ましくないと思う。

色々試したが、最も望ましいのは何らかのサーバー上に置くことである。 常時稼働しており、常時アクセス可能なサーバーはまさにこうした用途にぴったりである。

サーバーがあると何かと便利だ。できれば省電力のものを1台用意できると良い。

VPSを使うという方法もある。 ConoHa VPSなら512MBメモリ(30GBディスク)で620円/月、1GBメモリ(100GBディスク)で880円/月と安上がりだ。 これは、サーバー用に省電力PCを買い、電気代を払って動かすよりも低コストであり(電気代で150円くらいはかかる)、何より省電力なサーバーよりも圧倒的に速くて、なおかつ

VPSを難点は、ディスク容量が必要なケースにおいては難しいことだろうか。

だが、これはLinuxer的な考え方だ。 Chienomiの読者はLinuxerが多いだろうが、それでもなおWindowserのほうが多いだろう。 そこで、Windowsユーザーでも使いやすい方法を考えてみる。

例えば、Dropboxのようなクラウドストレージ上に配置するという方法もある。 EncFSと組み合わせれば機密性も保てる。

NAS上に置いてマウントするという方法も有力。もちろん、NASのSSHログインを有効にして普通にSSH URLを使ってアクセスするという方法もあるが、普通にマウントして使えば良いだろう。

Linux(Unix)側では次のようにする。

$ sshfs nas.local:/repos ~/mnt/repos
$ cd ~/Documents
$ git clone ~/mnt/repos/recipes.git

Windowsでは例えばZドライブにマウントすると固定して、Git Bashで

$ cd ~/Documents
$ git clone /z/receipes.git

のようにする。Mercurialでは特にMSYS2を前提としないため、次のようになるだろう。 (もちろん、MSYS2/minttyを入れてGit同様にやっても良い)

C:\cd %HOMEPATH%\Documents
C:\hg clone Z:\receipes