Git と Mercurial

サマリー

  • コンセプト
  • Git と Mercurial
  • Gitについて
  • Mercurialについて
  • Assignments

コンセプト

ソフトウェアのバージョンコントロールの歴史はそれなりに長く、ソフトの開発や本の執筆やウェブサイト管理などで重要な役割を担ってきました。 以下は、バージョンコントロールの基本的なコンセプトです。

  • ファイル群のversion history(バージョン履歴)を記憶し、必要な時にその履歴に戻ることができます
  • diff(差分)を記録し、どのファイルのどの行が変更されたのか知ることができること
  • 異なるバージョンのファイルをmarge(マージ)によって新しいバージョンに統合することができます
  • branch(ブランチ)によってワーキングコピーを作り、ブランチ下でファイル編集し、編集結果をマージしたり、させなかったりすることができます
  • commit(コミット)によって新しいバージョンのスナップショットを記録することができます
  • ローカルコンピュータやリモートサーバー上のバージョン履歴群のことをrepository(リポジトリ)と呼びます
  • リポジトリからファイルをpull(プル)することができます
  • push(プッシュ)によってリポジトリを変更できます
  • 複数のユーザーが同じファイルの同じ行で編集をするとmarge conflict(マージコンフリクト)が起きます
  • コンフリクトの解消、resolveは以下の方法で実施します。
    • a) 一人のユーザーから変更を加えて残りを破棄する
    • b) ファイルを手動で編集してコミットする

Git と Mercurial

バージョン管理のソフトはたくさんありますが、一番有名なものはSubversion, MercurialGitです。 それぞれ強みと弱みがありますが、世界中でもっとも使われているのはGitでしょう。 Fab AcademyではMercurialも使われており、両方とも覚えておきたいです。

Git と Mercurial の違い

GitはマクガイバーでMercurialはジェームスボンド

Git は分散管理型のVCS(バージョン管理システム),全てのユーザーはプライベートのローカルリポジトリを持っており、それぞれのユーザーが差分を通常はプルリクエスト経由でメインのリポジトリへマージする。

Mercurial は集中管理型, 全てのユーザーはリポジトリのコピーをローカルコンピュータへpullし、差分を中央リポジトリへpushs changesする。 もしその間に誰かがファイルを編集してしまったら、conflictを解消する必要がある。

![](git_mercurial/version-control-fig2.png)
![](git_mercurial/version-control-fig3.png)

どちらがよいでしょう?

参考(English):

Gitについて

ソフトのインストール

Gitのダウンロード OSX, Windows, Linux

ローカルリポジトリの作成

ローカルコンピュータ上でフォルダを作成し、 そのフォルダ内でgit initを実行します。

mkdir testing-git
cd testing-git
git init

このように表示されます。

Initialized empty Git repository in /private/tmp/repo/.git/

ファイルの追加

次にファイルを追加し、コミットする方法です。 READMEファイルを作成し、先ほどのリポジトリフォルダへ入れてから以下のコマンドを実行します。

git add README
git commit -m 'Initial import'

このように表示されます。

[master (root-commit) 1bcaa4d] initial import
 1 file changed, 1 insertion(+)
 create mode 100644 README

NOTE ローカルリポジトリにコミットされたことによってスナップショットが作られました。

それではREADEMEファイルをまた編集してみて以下のコマンドを実行してみてください。

git status

このように表示されます。

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README

最後にコミットした時からの差分がわかります。 さらにどこが編集されたのか細かく見ることができます。

git diff

差分の詳細です。

diff --git a/README b/README
index 9daeafb..2219bed 100644
--- a/README
+++ b/README
@@ -1 +1,2 @@
-test
+test is a test
+test2

先ほどやったようにgit addgit commitすることで履歴(リポジトリ)に反映させることもできますし、編集を破棄することもできます。破棄するには

git checkout -- README

とすると、最後にコミットしたバージョンにロールバックすることができます。

ブランチ

何かの編集(開発)に長い間取り組む必要があって、その編集履歴をメインのリポジトリに反映させるべきか決めかねていたり、何かの機能を開発中のソフトウェアに追加したいけれどもその機能に確信がない時のことなどを考えてみてください。

こんな時はbranch(ブランチ)を使います。 新しくブランチを追加した時、今まで作業していた元のリポジトリはmasterブランチと呼ばれます。

new_featureというブランチを作成したい時はこのようにします

git branch new_feature

今作業しているブランチを確認したい時は

git branch

このようになります。

git branch
* master
  new_feature

masterで作業中なのがわかります。 new_featureに移動します。

git checkout new_feature

こう表示されます。

Switched to branch 'new_feature'

これで、新しいブランチで編集作業ができるようになりました。マスターブランチのファイルに影響がなくコミットができます。 最初に作成したREADMEを編集してコミットしたい場合は、またマスターブランチに戻ります。 ブランチで作業した履歴は、マージコマンドで簡単に取り込むことができます。

git merge new_feature

このように見えます。

Updating 1bcaa4d..27efb70
Fast-forward
 README | 3 +++
 1 file changed, 3 insertions(+)

これで他のブランチで作業した結果が全てマスターブランチに反映されます。

リモートリポジトリ

Gitの素晴らしいところは、ローカルだけではなくインターネット経由でも管理ができることです。サーバーなしでその機能を使うことができます。 そしてremote repositoriesを使って他のユーザーと共同作業をするときなどに安全にデータを保存することができます。

Gitはどのサーバーにもインストールできますし、多くのユーザーはGitHub を使ってオープンソースのプロジェクトを管理しています。

GitHubでアカウントとリポジトリを作成してみましょう。 ローカルのgitプロジェクトをリポートリポジトリに追加することができます。 リポジトリの名前はいろいろなものがありますが、今回はoriginを使います。

git remote add origin https://github.com/(your account)/repo.git

HTTP, SSH, などを使ってリポジトリを追加することもできます。詳しくはGitHubのヘルプを見てください。GitHub help.

このリモートリポジトリにローカルのプロジェクトブランチをpushします。

git push origin master

ブランチがpushされたあとは、他のユーザーや自分でも、リモートリポジトリからローカルにコピーすることができます。これを**cloning(クローンする)と言います。 自分のコンピュータの違う場所のフォルダの中でクローンしてみましょう。

git clone https://github.com/fibasile/repo.git

ローカルコピーが作成され、編集やコミットなどができるようになります。結果はpushしてリモートリポジトリに反映することもできます。 クローンしたローカルリポジトリの編集をpushしたあと、元のオリジナルのローカルファイルに戻ってpullしてみましょう。

git pull origin master

これでコンピュータ上の2つのローカルリポジトリが同期されました。 同じ方法で違うコンピュータでもローカルリポジトリの同期ができます。

参考(English):

Mercurialについて

ソフトのインストール

Mercurial のダウンロード Windows, OSX, Linux.

設定

Gitではgitコマンドでローカルフォルダ上でファイル操作をしたように、Mercurialではhgコマンド使います。水銀(mercury)の元素記号です。 hgとタイプするとコマンドの一覧を示してくれます。

hg
Mercurial Distributed SCM

basic commands:

 add           add the specified files on the next commit
 annotate      show changeset information by line for each file
 clone         make a copy of an existing repository
 commit        commit the specified files or all outstanding changes
 diff          diff repository (or selected files)
 export        dump the header and diffs for one or more changesets
 forget        forget the specified files on the next commit
 init          create a new repository in the given directory
 log           show revision history of entire repository or files
 merge         merge working directory with another revision
 pull          pull changes from the specified source
 push          push changes to the specified destination
 remove        remove the specified files on the next commit
 serve         start stand-alone webserver
 status        show changed files in the working directory
 summary       summarize working directory state
 update        update working directory (or switch revisions)

use "hg help" for the full list of commands or "hg -v" for details

Mercurialリポジトリを作成して初期化してみましょう。

hg init

Gitでやった時と同じようにREADMEファイルを作成して何かテキストを入力します。 ファイルをaddし、commitするのも同じ手順です。

hg add README
hg commit -m 'Initial import' -u fiore

commitにはコメントだけでなくてユーザー名も追加します。デフォルトの設定は hg config –editで行います。

mercurialのログをチェックします。

hg log

このように表示されます。

changeset:   0:a2f0ef1e4c12
tag:         tip
user:        fiore
date:        Wed Jan 14 13:52:23 2015 +0100
summary:     Initial import

READMEに何かテキストを追加してみましょう。そしてコミットしてください。 Gitと異なるのは、ここでコミット前にaddする必要がないことです。Mercurialは最後のコミットからの差分を把握しています。

hg commit -m 'Another edit'

ログを再度確認してみましょう:

changeset:   1:6d8acdcc1429
tag:         tip
user:        fiore
date:        Wed Jan 14 13:57:20 2015 +0100
summary:     Some text added

changeset:   0:a2f0ef1e4c12
user:        fiore
date:        Wed Jan 14 13:52:23 2015 +0100
summary:     Initial import

では新しいファイルをリポジトリに追加してみましょう。LICENSEファイルを作成します。そしてステータスを確認します。

hg status
? LICENSE

このままの状態でコミットしても何も起きません。

hg commit -m 'another commit'
nothing changed

新しいファイルはバージョン管理下に追加する必要があります。1度追加したあとは、ずっとトラッキングされます。

hg addremove
adding LICENSE
hg commit -m 'another commit'

このコマンドは新しいファイルが追加された場合と、削除された場合のどちらのケースもバージョン管理に反映されます。例えば、最初に作成したREADMEファイルを削除した場合も同じコマンド手順(addremoveとcommit)でリポジトリに反映できます。

rm README
     hg addremove
removing README

Mercurialの素晴らしいところは、バージョン履歴に自由に戻ることができるところです。例えば、この状態から最初のコミット時の履歴に戻ってみましょう。

hg update -r0
1 files updated, 0 files merged, 1 files removed, 0 files unresolved

0というのはhg logで確認した最初のchangesetの番号です。 updateにバージョンを指定しない場合は、最新のものに更新されます。

リモートリポジトリ

Gitと同じようにMercurialでもリモートリポジトリを使って他のユーザーと共同作業ができます。

よく使われているオンラインサービスは BitBucketです。アカウントを作ってMercurialのリポジトリを作成できます。リポジトリタイプにMercurialをチェックしてください。

ローカルのリポジトリをリモートリポジトリにpushします。

hg push https://(your account)/(repo name)

これでbitbucket上のリポジトリにローカルプロジェクトが読み込まれましたが、Mercurialはリモートリポジトリのurlを記憶しないため、pushのたびにurlを入力する必要があります。 そこで.hg/hgrcを設定します。

[paths]
default = https://(your account)/(repo name)

hgrcには様々な設定をすることができます。英語 日本語

Gitと同じようにローカルの別フォルダにcloneすることができます。

  cd new_folder
  hg clone https://(your account)/(repo name)

LICENSEファイルを編集し、READMEファイルを新しく作成して hg addremovehg commitを実行しましょう。そしてリモートリポジトリにpushします。

hg addremove
hg commit -m 'Added new README and updated LICENSE'
hg push

今回のローカルリポジトリはhgrcが設定されたリモートリポジトリからのクローンなので、新たに設定する必要はありません。

コンフリクトの解消

これで最初のフォルダにpullすればリポジトリが反映されますが、その前にコンフリクトが起きた時にどうなるか見てみます。 LICENSEファイルを編集してpushしてみます。

hg addremove
hg commit -m 'Removed LICENSE text'
hg push

このような表示になります

pushing to https://fibasile@bitbucket.org/fibasile/testrepo
warning: bitbucket.org certificate with fingerprint 45:ad:ae:1a:cf:0e:73:47:06:07:e0:88:f5:cc:10:e5:fa:1c:f7:99 not verified (check hostfingerprints or web.cacerts config setting)
searching for changes
remote has heads on branch 'default' that are not known locally: 4c3851b23038
abort: push creates new remote head 7f93695a6e1f!
(pull and merge or see "hg help push" for details about pushing new heads)

このような表示が出た場合、MERCURIALが何を言っているのか、どんなトラブルが発生しているのか注意して確認してください.

特に

abort: push creates new remote head 7f93695a6e1f!

というのは新しいブランチheadを作ることを意味しています。 このような他のユーザーが今の変更を全て無視するような結果になりそうなことはやりたくありません。 幸いMercurialがどうやって進めたらいいかヒントをくれています。

(pull and merge or see "hg help push" for details about pushing new heads)

言われた通り実行します:

hg pull

このように表示されます

pulling from https://fibasile@bitbucket.org/fibasile/testrepo
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

これでマージとコミットができるようになります。 ここで注意しなければならいのは、コミット後もう一度リモートリポジトリに自分がマージしたバージョンをプッシュする必要があることです。

hg merge
hg commit -m 'Merged my changes'
hg push

ほとんどの場合、この方法でファイルを編集した時のコンフリクトは解消できますが、それでもトラブルが発生する場合はツールなどを使って手動でマージする必要があります。 最後にログをチェックします。

changeset:   6:61f4b120ec71
tag:         tip
parent:      4:7f93695a6e1f
parent:      5:4c3851b23038
user:        fiore
date:        Wed Jan 14 14:57:11 2015 +0100
summary:     merging my changes

最新のchangesetには2回のpushによって2つのparentsがあることがわかります。

教訓: エラーメッセージには必ず目を通し、mercurialの助言を受けましょう

参考(英語)

課題(Assignments)

  • GitHubBitBucketに登録しましょう
  • エキサイティングなプロジェクトのリポジトリをつくりましょう
  • リモートリポジトリににアップロードしましょう
  • 自宅のコンピュータと職場のコンピュータなどの別環境で、常に同期を保ちながら開発しましょう
  • オープンソースのプロジェクトを、Zipのダウンロードではなくリポジトリのクローンをしてみましょう