1.6. gitの操作方法/using git

1.6.1. github/gitlabとの接続設定/configure for communication with github/gitlab

gitは、 分散型バージョン管理システム のひとつです。

開発チームの各メンバーの計算機上の 共有リポジトリ とリンクされた ローカルリポジトリ を作業者ごとのディレクトリに作成し、普段はローカル リポジトリにアクセスしてソースの変更を記録します。

他のプロジェクトメンバーの 変更内容と合流(マージ)させたいときにローカルリポジトリと共有リポジトリ との間で変更差分の受け渡し(pushpull)をします。

別々の人が同じファイルを同時期に編集して、編集箇所が衝突することがあります。 その場合にはユーザが衝突箇所を見て判断し、合流後の内容として妥当に なるように手作業で編集します。

1.6.2. 初期設定/initial configuration

共有リポジトリは多くの場合、ソースを格納できるサービスを提供する ソースホスティングサイト を利用します。ソースホスティングサイトと 通信が可能となるように ssh公開鍵 を登録しておき、 ホスティングサイト上の 共有リポジトリクローン する ことで、ローカルリポジトリを作成します。

1.6.2.1. ソースホスティングサイトとの通信の準備/prepare to communicate with the source hosting site

gitコマンドで ソースホスティングサイト にアクセスする通信方法としては、 httpsとsshから選べるようになっていることが一般的です。 httpsを選ぶと操作の度にパスワードの入力を求められることがあるので、 sshを使えるのであればsshを選ぶのがお薦めです。

すでに作成済みのssh公開鍵があれば、それをソースホスティングサイトに登録します。 なければ 鍵ペアの生成/generating a key-pair を見てください。 sshの公開鍵はユーザごとの情報なので、ユーザプロファイルの設定画面内に、sshの鍵の 登録のためのインタフェースがありますので、そこから登録します。

1.6.2.2. リポジトリのクローン/cloning a repository

ローカルリポジトリをゼロから作成すると、他のリポジトリとリンクされていない 孤立したリポジトリができあがります。ソースホスティングサイトを利用する場合には ホスティングサイトにある共有リポジトリと、はじめからリンクされたローカルリポジトリを 作るために、クローン操作によってローカルリポジトリを作成するのが便利です。

(架空の)ホスティングサイト brilliant-sources.com 上の team-tokyo/FastSolver.git というパス名のリポジトリをクローンする:

Clone a repository named team-tokyo/FastSolver.git from a (fictional) source hosting site brilliant-sources.com:

$ git clone ssh://git@brilliant-sources.com/team-tokyo/FastSolver.git

Note

ローカルリポジトリを作成する方法としては、この他に、全く空のディレクトリ からスタートする方法や、先に初期バージョンとしてある程度ファイルを作成 してしまってからリポジトリを作成して、共有リポジトリに push する 方法などがあります。

1.6.2.3. 自分の名前とメールアドレスの登録/Register your name and mail address

gitでは、ファイルをいくつか編集したのちに、それらをアトミックな単位である コミット としてローカルリポジトリに登録します。 コミットのデータの中には作成者のアカウント情報が登録されます。 これはgitに予め自己申告しておく必要があります。 gitはホームディレクトリの中の設定ファイルにその値を記録しておきます。

ユーザ名とメールアドレスをgitに記録させる:

Let git record your name and mail address:

$ git config --global user.name "Ken Abe"
$ git config --gloabl user.email "ken.abe@somewhere.com"

1.6.3. ローカルリポジトリへのファイルの登録/Adding files to the local repository

gitでは、直接編集が可能なワーキングツリーと、さまざまな過去のバージョンの 履歴を記録しているリポジトリとの間に、 ステージングエリア という 隠れたファイルのツリーがあります。ワーキングツリーで変更を加えたファイル から、リポジトリに記録したい内容だけを選んで、ステージングエリアに書き込んだ のちに、ステージングエリアの内容をアトミックな単位である コミット として登録します。

たくさんのファイルからなるプログラムを作成していると、一つの問題を解決するために さまざまなファイルを修正する必要が生じます。夢中になって作業をしていると、どの ファイルに修正を入れたのかを忘れてしまったりします。また、一つの問題を追っている うちに、別の問題が目に止まり、それもついでに修正したくなってしまうこともあります。

gitではこういう状況でも、自分が行った変更をしっかり確認して、正式に登録すべき ものだけを選択して登録できるようになっています。

ステージングエリアにファイルを登録するために、以下のコマンドを使います。

  • 変更が入ったファイルや選択されたファイルの一覧を見るには git status

  • 変更した前後の差分を確認するには git diff

  • 不要な変更を取り消すには git checkout

  • ファイルをコミットに含める対象として選択するには git add

  • ファイルの選択を解除するには git reset

ステージングエリアに登録したファイルをコミットするには、以下のコマンドを使います。

  • 現在の ブランチ に、選択したファイルをコミットとして登録するには git commit

  • 現在のブランチに対する、リモートリポジトリ側の最近のコミットを取り込むには git pull

  • 現在のブランチの最近のコミットをサーバに送るには git push

1.6.3.1. git status - 変更が入ったファイルや選択されたファイルの一覧を見る/see which files are changed or selected

git status は ワーキングツリー の中で、最後にコミットして以来、変更した ファイルや新規に追加したファイルの一覧を表示します。

ワーキングツリー内の変更点を表示する:

$ git status

出力は、一番多い場合で3つのセクションに別れます。

  • 最初は、ステージングエリアに選択済みのファイルの一覧です

  • 2番目は、変更がなされているが、ステージングエリアに含まれていないファイルです。

  • 3番目は、新規に追加されたが、ステージングエリアに含まれていないファイルです。

該当するファイルがなければ、そのセクションは空になります。

git statusで表示対象とする範囲を特定のディレクトリに絞りたければ、 ディレクトリのパス名を引数に指定します。

カレントディレクトリ以下に関して変更の状態を表示する:

$ git status .

1.6.3.2. git diff - 変更した前後の差分を確認する/compare the edited to the previous file

git diff は、ワーキングツリーの内容をステージングエリアの内容と比較し、 結果をdiffコマンド形式で表示します。

ワーキングツリー内の全ての変更箇所を差分表示する:

$ git diff

カレントディレクトリに絞って変更差分を表示する:

$ git diff .

ワーキングツリーと別の ブランチ “master” との差分を表示する:

$ git diff master

別のブランチ “master” との差分を、カレントディレクトリに限定して表示する:

$ git diff master .

1.6.3.3. git checkout - 不要な変更を取り消す/Revert unwanted changes

git checkout は、ローカルリポジトリの中から、指定したバージョンのファイルを ワーキングツリーに取り出すコマンドです。

一旦編集をし始めたものの、うまくいかず、コミット前の段階で、元に戻したい時に 使うことができます。(コミットした後では、この方法では元に戻せません。)

ワーキングツリー全体を、最後にコミットした時点の内容で上書きする:

$ git checkout

カレントディレクトリの headers/triangle.h というファイルだけ、最後にコミットした バージョンをワーキングツリーに取り出す:

$ git checkout headers/triangle.h

1.6.3.4. git add - ファイルをステージングエリアに選択する/add files to the staging area

git status や git add で変更内容を確認したら、コミットしたいファイルを git add コマンドでステージングエリアに選択します。

ファイル src/rectangle.cpp を選択する:

$ git add src/rectangle.cpp

ディレクトリ “include” の中の全てのファイルを選択する(変更点のないファイルは選択されない):

$ git add include

1.6.3.5. git reset - ファイルの選択を解除する/deselect a file

git reset は、ステージングエリアの内容をリポジトリの内容で上書きする コマンドです。一旦 git add でステージングエリアに、変更の入ったファイルを 登録したのちに、同じファイルに対して git reset を実行すれば、リポジトリに 入っているバージョンのファイルに、ステージングエリアの内容を戻すことができます。

結果として、 git add の作用を取り消すことができます。

ファイル block.h を git add したことを取り消す:

$ git add block.h
$ git reset HEAD block.h

HEADというのは、バージョンを指すキーワードで、現在操作しているブランチの 最新のコミット、つまり最新のバージョンを指します。最新バージョンのコミット における、block.h ファイルの内容を、ステージングエリアに書き込んでいます。

1.6.3.6. git commit - 選択したファイルを現在のブランチにコミットとして登録する/Record the selected files as a commit to the current branch

ステージングエリアに希望するファイルを過不足なく登録できたら、 git commit コマンドで リポジトリに登録します。

ステージングエリアの内容を現在のブランチの最新コミットとして登録する:

$ git commit

1.6.4. ローカルリポジトリとリモートリポジトリの間の送受信/exchange between local and remote repositories

1.6.4.1. git pull - 現在のブランチに対するリモートリポジトリ上の最近のコミットを取得する/Get the recent commits from the remote repository

開発チームの他のメンバーがリモートリポジトリに登録した最新の変更は、 git pull コマンドでローカルリポジトリに取得し、同時にワーキングツリーに 取り出すことができます。

現在のブランチの最近のコミットをリモートリポジトリから取得する:

$ git pull

このとき、ローカルリポジトリでも変更をコミットしていて、まだリモートリポジトリ に送っていない場合には、ローカルのコミットとリモートのコミットの内容を 統合するマージ処理が自動的に行われます。

双方で同じファイルの、オーバーラップする行に変更を加えている場合、自動の マージに失敗します。これがマージの衝突です。

1.6.4.2. マージの衝突の解決方法/resolving merge conflicts

マージの衝突が起きると、merge conflict が起きたことを伝えるエラーメッセージが 出ます。

マージの衝突が起きた箇所には目印がつけられます。まず、どのファイルでマージの 衝突がおきたのかは、git status で確認することができます。

git status で「双方に変更があった」と表示されるファイルが、マージの衝突が 起きたファイルです。そのようなファイルをエディタで開くと、衝突が起きた 箇所に目印の行が挿入されているのをみつけることができます。ローカルではこのような 変更があったが、リモートではこのような変更があった、というように表示されます。

両者の変更の内容を考え、エディタで目印を取り除き、統合後のファイル内容として 妥当なものになるように直します。その作業を終えたら git add します。

衝突のあったファイルを一通り処置して git add したら、git commit します。

衝突があったときに、一方の変更内容をまるっきり捨ててしまうコマンドもあります。

全く同じバグに対する対策を、連絡不足から二人の人が同時期にやってしまって、 一方の修正だけを残せばよいような場合に使うと良いでしょう。

1.6.4.3. git push - 現在のブランチに対する最近のコミットをサーバに送る/Send the recent local commits to the remote repository

git push で現在の ブランチ にある、まだ送信していないコミットをリモートリポジトリ に送ることができます。

現在のブランチの最近のコミットをリモートリポジトリに送る:

$ git push origin HEAD

origin というのはリモートのリポジトリにつけられるデフォルトの名前、 HEADというのは、「カレントブランチの先端のコミット」の意味です。

git push においても、ローカルとリモートで共に変更が加えられている可能性があります。 git pull においては、そういう場合に自動的にマージが行われましたが、git pushでは 自動のマージは行われずエラーになります。そのようなエラーが起きたら、一旦 git pull して、手元でマージ作業をしてください。マージが済んだバージョンをgit pushすると 成功します。

1.6.5. ローカルリポジトリからのファイルの取得/Getting files from the local repository

リポジトリからファイルを取り出したい状況には、いろいろなケースがあります。

主なものを挙げます

  • 開発チームの他のメンバがサーバにpushした最新版を取り出したい。

  • 今見ているブランチとは別のブランチの中身のソースをワーキングセットに 取り出したい。

  • 今見ているファイルの、以前の版を取り出したい。

  • 今編集中のファイルを、以前の版と比較したい。

それぞれの操作を説明します

1.6.5.1. 開発チームの他のメンバがサーバにpushした最新版を取り出したい。

git pull (説明はこのページの中程) すれば、 最新のコミットがリモートリポジトリからローカルリポジトリに取得 されるだけでなく、ワーキングセットに取り出されます。

1.6.5.2. 今見ているブランチとは別のブランチの中身のソースをワーキングセットに取り出したい。

git checkout でブランチ名だけを指定すると、ワーキングセットの内容がまるごと そのブランチの内容に切り替わります。カレントブランチも切り替わります。

ブランチ’experimental’の内容をワーキングセットに取り出し、カレントブランチを experimentalにする:

$ git checkout experimental

ブランチに加えて、ファイルやディレクトリのパス名を指定すると、指定したパス名 の範囲のファイルだけが取り出されます。カレントブランチは変わりません。

1.6.5.3. 今見ているファイルの、以前の版を取り出したい。

git checkout で、ブランチ名の代わりに、コミットを特定する情報を書けば、 指定したコミットの時点での、特定のファイルを取り出すことができます。

コミットを特定する情報の形式にはいろいろありますが、よく使うものを挙げます:

  • 「HEAD」「HEAD^」「HEAD^^」それぞれ、最後にコミットした時点、その一つ前のコミット、 さらに一つ前のコミット

  • 16進数のコミットIDの先頭6桁程度 - 全てのコミットには数値としてIDが振られます。 実際の桁数はかなり長いですが、gitコマンドに渡す際には、他のコミットと区別が つくだけの桁数を入力すれば受け付けてくれます

最後のコミットの一つ前野コミットの時点の src/triangle.cpp をワーキングエリアに 取り出す:

$ git checkout HEAD^ src/triangle.cpp

コミットID 4a1be32b… のコミットの時点での include/triangle.h をワーキングエリア に取り出す:

$ git checkout 4a1be32b include/triangle.h