Git はファイルのバージョン管理
Gitはファイルのバージョン管理を行いますが、画像のようなバイナリファイルは苦手なので、画像を管理するなら、Git LFS を使うことになるかもしれません。
Git LFS については別に改めてまとめますが、Gitでよく使われる言葉やその概念についてまとめておきます。
Git で使われる基本用語
リポジトリ(repository 貯蔵所、倉庫)
ファイル自体やファイルの変遷の記録(歴史)を蓄えておく場所
ローカル(自分のコンピュータの中)とリモート(Gitサーバの中)の両方にリポジトリがあります。
ブランチ(branch)
初めてローカルリポジトリを作成したときには、通常masterブランチだけがあります。通常はこのmasterが幹に当たります。
一つのブランチを枝分かれさせて2つのブランチに分けて、それぞれ独立したブランチにすることを「ブランチを切る」といいます。
イメージ的には、例えば、少し挑戦的な機能を入れたいが成功するかどうかわからないので、幹とは違う別の枝を作って試してみようという感じになります(あとから幹にその変更を適用する→マージする、ということも可能です)。
ブランチは名前をつけて区別します。
常に一つのブランチ上で作業を行い、そのブランチに変更を加えます。
チェックアウトする(check out)
CSVとかでは違う意味で使っていましたので注意が必要。
作業フォルダを現在のブランチからチェックアウトして、異なるブランチへ移ること。
あるいは、同じブランチに登録されている過去の状態(歴史の1ページ)へ移ること。
コミットする(commit)
- ローカルのファイルを変更した後で、そのブランチの変更の記録(歴史)をローカルリポジトリに(歴史の1ページとして)登録すること。登録された歴史の1ページをコミットと呼ぶこともあります。
アッドする、ステージング(add)
コミットしたいファイルを追跡対象に加えること。アッドされたファイル(群)がコミットの対象となる。よくある事故として、アッドし忘れによりファイルがコミットされていなかった(つまり変更の歴史が残っていなかった)ということがあるので注意が必要。
逆に言えば、アッドしていないファイルはGitの管理下にないので、テンポラリなファイルはアッドすべきじゃないとも言えます。
プッシュ(push 押す)する
ローカルブランチの変更をリモートブランチへ反映させ同期を取ること。
他の人とファイル共有をしない場合等の理由で、リモートが必要がない場合もありえます。
プル(pull)する
- リモートブランチをローカルブランチへ反映させ同期を取ること。
マージ(merge)する
ローカルリポジトリに異なる2つのブランチがあるとき、一方のブランチの変更を他方のブランチに反映させること。
マージは、マージ対象のブランチを現在自分のいるブランチに反映させる。相手のブランチは変更されない。
また、例えば同一のファイルに対してリモートで変更され、ローカルでも変更を行った場合、プルすると衝突(conflict)することがある。その時に両者の変更をローカルで解決することもマージするという。
クローン(clone)する
リモートレポジトリにある指定したブランチ(デフォルトはorigin/masterブランチ)と同じ状態(環境)を、新規にローカルに作成する。
通常、ローカルレポジトリを作成するときにはorigin/masterブランチをクローンする。
origin : リモートリポジトリのURLの別名
Git 基本作業手順
リモートレポジトリからブランチをクローンする。
※リモートがなく、ローカルにリポジトリを作成する→作成したいディレクトリにcdして、git init
- git clone コマンド
更新されたリモートリポジトリをローカルの複製に反映させる。
- git pull コマンド
コンフリクトが発生したら、マージして解決する。その時には変更履歴を記録する。
- git add -> git commit コマンド
必要ならブランチを切りそのブランチへ移って。
- git branch -> git checkout コマンド
以下の作業を行う
ローカルでコンテンツの修正・追加・削除を行い、ローカルリポジトリに変更履歴を記録する。
- git add -> git commit コマンド
必要ならこの作業を繰り返す
ローカルの変更内容(歴史)をリモートに反映させる。
- git push コマンド
必要なら、5. へ戻って作業を繰り返す。
- 変更作業 -> git add -> git commit (-> git push) の繰り返し
ブランチでの作業が完了したら、変更をそのブランチを作った元のブランチへマージし、役割を終えたブランチを削除する。元のブランチの変更をリモートへ反映させる。
必要なら、4. へ戻る
Git の概念
分散型バージョン管理システム
複数の作業者が一つのリモートレポジトリの完全な複製を各人のローカルに持ち、また、各人はローカルにリポジトリを持っています(これらの特徴からから分散型バージョン管理システムと呼ばれています)。
その状態を維持するために、各作業者はローカルでの作業を行う前に、プルを行う必要があります。これは別の誰かが、ファイル等を更新している可能性があるからです。
ローカルで作業している間に他の作業者がプッシュしていた場合、自身がプッシュしようとするとGitからプルするよう促されます。プルした結果コンフリクトしたら、それを解決するマージ作業を行うことになります(マージさえ済ませたら、コミット・プッシュができるようになります)。
修正・追加・削除はローカルでの作業です。
変更を共同作業者に反映させても良い状態になったら、プッシュを行います。その際、例えば、テストが通らない状態でプッシュすると他の作業者に迷惑がかかることになるので、注意が必要です。
Working Directory(作業ディレクトリ)、index(インデックス)、repository(レポジトリ)、そしてHEAD
ここではローカルでの作業について、Gitがどのようにファイルの履歴(歴史)を管理するのかを概観してみます。
Working Directory(作業ディレクトリ)
レポジトリがあるディレクトリで、作成するサブディレクトリやその内のファイルも含まれる。実際にファイルを作成したり編集したりする場所。
index(インデックス)
ステージング環境ということもありますが、レポジトリに登録したいファイルを選択しインデックスに追加する(ステージングといいます)ことで、それらファイル群の変更・追加・削除の状態を一時的に保存しておく場所のことです。
インデックスに加えられたファイルは追跡対象となります(つまりaddした)。すなわち、作業フォルダのファイルと比較され変更があるかがチェックされる(インデックスに加えられたファイルが比較元であるので、addされなければ変更は反映されません)。
repository(レポジトリ)
Gitが変更の歴史を蓄えておく場所。コミットすることで、インデックスの状態をレポジトリにコピーして新しい歴史として加えられる。
ただし、歴史は上書きされるのではなく、過去の歴史はそのまま残されています。それら歴史はコミットIDで区別されコミットIDを指定することでいつでも復元可能です(その時の状態に戻ることができる)。
それら歴史の中で現在の位置をHEADというポインタで表しています(通常は最新の状態を表している)。言い換えれば、HEADはそのブランチの先頭を表します。そして、もちろんブランチごとにHEADがあります。
基本作業手順、ファイルを新規に2つ作成してコミットする
まずは、いくつかの基本コマンドを試しながら、何が起こっているのかを(できれば実際やっtみて)確認します。
また、世の中にはGitを扱った便利なGUIツールがありますが、基本がわかっていないと危険なので、まずはCUI、つまりコマンドラインで確認していきます。
- 作業ホルダーを作成し、
git init
を実行します。1 2
$ mkdir git_test $ git init
- ※
- まだgit config --global user.name "chikun"とgit config --global user.email chikkun@hogehoge.comを実行して、ユーザとメールアドレスを登録していない場合は登録してください。
この状態で
git status
を実行すると次のような、文字列が出力されます。このコマンドはインデックス内のファイルと現在のHEADとの間に差分があるパス、作業ツリーとインデックスファイルとの間に差分があるパス、そして作業ツリーの中で Git に追跡されていないパスを表示します。1 2 3 4 5 6
$ git status On branch master No commits yet nothing to commit (create/copy files and use "git add" to track)
- ※
- ちなみに、次の図は上はHEADが何を指しているのかを図示したものですが、まだ何もないので「?」が書いてあります。最初のコミットでデフォルトのmasterというブランチが作成され、 HEADはこのMasterを指すことになります。さらに、下の図はWorking Directory、Index、HEADの中身がない状態を表しています。
作業フォルダで、ファイル(file1.txt)を作成します(内容は任意)。この時点ではリボリトリもインデックスもなく、これから生成される予定のブランチを指すことになります。ちょっと下にある図にはmasterというbranchが描かれていますが、実際にはまだ存在していません。
つまり、現状、Working Directory、Index、HEADがどんな状態か表示するので、色々と確認していきます。
1 2 3 4 5 6 7 8 9 10 11
$ git status On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) file1.txt nothing added to commit but untracked files present (use "git add" to track)
` Untracked files:`とは、ステージングされていないファイルがあるということで、もちろん、リポジトリもなく、Git管理下にあるファイルは何もない状態ということになります。現状はまっさらな状態です。
- ※
- ちなみに、次の図は上はHEADが何を指しているのかを図示したものですが、まだ何もないので「?」が書いてあります。最初のコミットでデフォルトのmasterというブランチが作成され、 HEADはこのMasterを指すことになります。さらに、下の図はWorking DirectoryにVersionが1のfile1.txtだけがあり、残りのIndex、HEADの中身がない状態を表しています。
そのファイルをレポジトリに登録する前段階として、ファイルをインデックスに加えます(ステージングに上げるとか、UPするとか言う場合も)。これはファイルを指定する場合と、ステージングにUPされていない全てのファイルを対象にするドット「.」が指定できます。
・git add file1.txt
・git add . ←コンマだと、ステージングされていないファイルすべてが対象になります。
まだコミットはしていませんが、addしたので、Indexにファイルが現れます。
1 2 3 4 5 6 7 8 9 10
$ git add file1.txt $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt
- ※
- まだコミットされていないので、ブランチはありません。ただ、ファイルはWorking Directory、Index、HEADにそれぞれ存在するファイルを表しています。まだピンとこないと思いますが、これを理解するのがここでの大きな目標になります。
さて、最後にレポジトリにコミットします。これにより、ようやくレポジトリに登録されます。
・git commit
viが立ち上がりコメントを記述するよう促される -> コメントを記述し保存して終了
・git commit -m "コメントを記述" ←(viは立ち上がらない)
1 2 3 4
$ git commit -m "コメントを記述" [master (root-commit) 1916ea2] コメントを記述 1 file changed, 2 insertions(+) create mode 100644 file1.txt
これで、はじめてmasterが生成され、上記の図のように、Working Directory、Index、HEADが揃いました。
※ちなみに1916ea2はコミットのHash値で(commit idとも言われ、実際には40文字あるらしいが、通常7文字で十分大抵は区別できるので、7文字で表すことが多い)、何度も繰り返されるコミットをこれで区別します。
さて、この状態を簡単に確認します。
- 1つのコミットが「1916ea2」があります。
- 今回のこのコミットがこのリポジトリの最初のコミットで、上記の
git status
の出力にroot-commitがあります。 - 現在、HEADはmasterブランチの「1916ea2」を指しています。
- Working Directory、Index、HEADがそろっています。
- ブランチはmasterの1つしかない。
次に2つ目のファイル(file2.txt)を新規に作成します。まだaddもしていないので、IndexやHEADはそのままです。
file2.txtをaddします。
1 2 3 4 5 6 7
$ git add file2.txt $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: file2.txt
同様にcommitします。
1 2 3 4 5 6 7
$ git commit -m "コメントを記述2" [master c37cd18] コメントを記述2 1 file changed, 2 insertions(+) create mode 100644 file2.txt $ git status On branch master nothing to commit, working tree clean
さて、この状態を簡単に確認します。
- 2つのコミットがあり、それらは「1916ea2」、「c37cd18」の2つです。
- 現在、HEADはmasterブランチの最新のコミットである「c37cd18」を指しています。
- Working Directory、Index、HEADがそろっています。
- ブランチはmasterの1つしかない。
- 「1916ea2」というコミットのした時の状態は、消えてなくなっていません(つまり、いつでもその状態に戻すことも可能です→後述)。
基本作業手順、ファイルを1つ修正し、コミットする
次にfile2.txtに修正を修正します(修正は任意)。図のfile1.txtのVersionが2(v2)となっています。
git statusを実行すると、以下のように表示されて、addしていないファイルがあることがわかります。
1 2 3 4 5 6 7 8 9
$ 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: file1.txt no changes added to commit (use "git add" and/or "git commit -a")
下の図では、Working Directoryのfile1.txtがピンクになっています。
file1をステージングします(addします)。
Indexのfile1.txtのVersionもv2になっています。git statusは次のよう。
1 2 3 4 5 6 7
$ git add file1.txt $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: file1.txt
- ※
- git statusの出力された文字で、addする前の「modified: file1.txt」は赤色で、add後は緑色になっています。
それで、最後にコミットします。
これで最初に変更したfile1.txtがHEADにも反映されます。git statusは次のよう。
1 2 3 4 5 6
$ git commit -m "file1を修正した" [master 7fed657] file1を修正した 1 file changed, 1 insertion(+), 1 deletion(-) $ git status On branch master nothing to commit, working tree clean
現在のこの状態を簡単に確認します。
- 3つのコミットがあり、それらは「1916ea2」、「c37cd18」の2つです。
- 今最新のHEADはmasterブランチの上記の「c37cd18」を指しています。
- Working Directory、Index、HEADがそろっています。
- ブランチはmasterの1つしかない。
- 「1916ea2」というコミットのした時の状態は、消えてなくなっていません(つまり、いつでもその状態に戻すことも可能です→後述)。
インデックス(ステージング環境)が存在する理由
現在作業中のファイルをインデックスに加えなければ(ステージングしなければ)作業中のファイルはコミットされないので、一部まだ変更中のファイルがあってもそれはそのままで、他のものはステージングしてコミットできるので、コミットのために作業を中断(作業ファイルを作業前に戻したり)する必要がありません。
ファイル個別に過去のコミット(特にHEAD)とインデックス(これからコミットしたい内容)を比較したり、後述するように過去のものを参照したり、過去のものに戻したりできると同時に、ファイル群全体をあるコミットの時点に戻すことも可能で、これらがGitの便利なところとなっています。
インデックスに関わる操作
今回のポイント
- resetの使い方
- git reset –soft commitID
- git reset –mixed commitID
- git reset –hard commitID
- git reset HEAD ファイル名 ←HEADは省略可
- git reflog
今回のイント
- resetの使い方
- git reset –soft commitID
- git reset –mixed commitID
- git reset –hard commitID
- git reset HEAD ファイル名 ←HEADは省略可
- git reflog
ここで述べるコマンドには、コミットする前に実行するとコミットされていない変更が(歴史に登録されていないため)失われるものがあるので注意が必要です。
インデックスの修正(コミットする前)
誤ってインデックスに登録されたファイルをインデックスから外したい。
git reset HEAD ファイル名
指定ファイルのインデックスだけをHEADの状態(レポジトリの最新の状態)に戻す
追跡したくないファイルを誤ってアッドしてしまった(ステージングしてしまった)とき、まだコミットしていない状態でインデックスを修正し、アッドしたファイルをインデックスから取り除く(アンステージングする)ときに実行します。
※ただし、コミット前なので、ローカルリポジトリには反映されていません。
これを実行しても、もちろん、作業フォルダ上のファイルは変更されません。
それぞれの環境の状態の変化
リポジトリ | インデックス | 作業ホルダ |
---|---|---|
*不要ファイルがないコミット | 不要ファイル.txt | 不要ファイル.txt |
必要ファイル.txt | 必要ファイル.txt |
git reset HEAD 実行前後の状態の変化
もしも、すでに追跡対象となっているファイルに対してこのコマンドを当てると、インデックスに加えた変更が破棄されHEADの状態に戻される(リセットされる)ことを意味している。HEADの箇所を異なるコミットIDで実行すると指定ファイルのインデックスがそのコミットIDの状態へリセットされる(ただし作業フォルダのファイルは変更されない)。
または、インデックスをリセットするのではなく、ファイルを過去から復元したい(インデックスと作業フォルダのファイルを変更する)ならば次のコマンドにする。
git checkout HEAD ファイル名
指定ファイルを過去の歴史(ここではHEAD)から復元する。
git checkout HEAD 実行前後の状態の変化
この場合は、checkout で指定されたファイル以外は(インデックスも作業フォルダも)変更されない。
作業フォルダもインデックスもすべての変更を破棄してレポジトリの最新の状態、HEADに戻したい
- git reset –hard HEAD
オプションをつけるとファイルの指定はできず、インデックスのすべてがHEADの状態にリセットされる。–hard オプションの場合インデックスだけでなく作業フォルダもリセットされる(デフォルトは –mixed でインデックスだけ戻される)。
個々のファイルごとにではなく、すべて変更前の状態に戻したいときに実行する。
git reset –hard HEAD 実行前後の状態の変化
hituyo.txt へ加えていた変更も破棄される。
異なるコミットIDを指定するとインデックスと作業フォルダはそのコミットIDの状態へ戻され、その状態をHEADにリセットする(すなわち、指定したコミットID以降現在までのコミットはすべて破棄される)。
コミット後の修正
コミットメッセージの修正(コミットを増やさない)
git commit –amend
–amend オプションは、現在のHEAD(最新のコミット)を上書きする
インデックスを変更していない(アッドしていない)ときでも、HEAD(最新のコミット)のコミットメッセージを変更できる。
git commit –amend 実行前後の状態の変化
コミットは追加されずに変更された。
最新のコミットに変更を追加(コミットを増やさない)
git commit –amend
インデックスを変更(git add)してから実行する。
インデックスを変更した(アッドした)後でも、HEAD(最新のコミット)のコミットメッセージも変更してコミット自体を修正できる。
git commit –amend 実行前後の状態の変化
コミットは新たに追加されずに修正されて、「doc_2.txt」も反映されている。
作業フォルダからファイルを削除しても削除情報をインデックスに反映できない
- 不必要なファイルをコミットしてしまったら、作業フォルダのファイルを削除してもGit的にはそのファイルが存在し続けることになる。
rm ;git add 実行前後の状態の変化
インデックスと作業フォルダから指定ファイルを削除する
git rm ファイル名
インデックスと作業フォルダからファイルを削除する。
git rm ;git commit 実行前後の状態の変化
git rm した後、 git commit (–amend) を実行することで、最新のコミットには不要ファイルが含まれなくなる。ただし、この操作では作業フォルダの実ファイルごと削除されることに注意。
インデックスからは削除するが作業フォルダのファイルは削除しない
Gitには登録したくないが、ファイルは存在したままにしておきたいときの操作
git rm –cache ファイル名
インデックスからだけファイルを削除する。
git rm –cache ;git commit 実行前後の状態の変化
1
git rm --cache した後、 git commit (--amend) を実行する。
Git コマンド まとめその1
アッド(git add)に関わるコマンド
git add .
現在のディレクトリ「.」を指定することで、作業フォルダ以下のすべてのファイルをGitの対象とする。
インデックスにファイルを追加、変更を上書きする。削除することはできない。
git add -A
- 「-A」オプションは、作業フォルダ以下のファイルすべての追加・変更と削除も含めた変化をインデックスに登録する。
コミット(git commit)に関わるコマンド
git commit -m "メッセージ"
- コミットメッセージを続けて入力できる
git commit -a
現在インデックスにあるファイルを自動的に git add してからコミットする。
つまり、新規に作成されたファイルはアッドされない。
git commit -a -m "メッセージ"
- 上二つを合わせたコマンド
バックアップファイル「*~」など登録する必要のないファイルを git add . で登録してしまった時の対処
git rm –cache 消したいファイル名
コミット前ならインデックスから消すだけ。コミットした後なら、続けてコミットし直す。
git commit (-a) -m "メッセージ"
-a オプションをつけるかつけないかの判断は上の説明を参照。
\newpage (単独で)プロジェクト管理 {#sec:org30f4b93} ==========================
プロジェクトの安全性を考えた場合、プロジェクトをリリース環境と開発環境に分けて、開発作業自体は開発環境で行い、開発環境が安定した時点でリリース環境へ上げるという形が考えられる(リリース環境は本番環境と同じにしておく)。
この場合、リリース環境へ上げる時期に開発環境の作業を止めることになる可能性がある。つまり、開発環境を安定化させてからリリース環境へという流れには無駄がある。
そこで、開発環境は常に安定状態(エラーのない状態)にしておき、実際の開発はトピックごとに細かなバージョンに分けてそのバージョンが完了したら開発環境へ上げて開発環境が安定しているかのチェック、テストを行う、という形であれば、いつでも開発環境をリリース環境へ上げることが可能となる。そして、開発作業は継続して行うことができる。
その形を具体化したものがブランチとなる。
ローカルにGitプロジェクトを作る
新規プロジェクト作成例
ここでは、helloプロジェクトを作成するものとしてその手順をまとめていく。
- プロジェクトフォルダを作成する
1
2
$ mkdir hello
$ cd hello
Git の初期化を行う
$ git init
.gitignoreを用意する(後から加えていけるので基本設定だけで良い。記法は、 4.3{reference-type=”ref” reference=”sec:org6af39e1”} を参照)
$ echo ‘*.bak’ > .gitignore
ファイルを作成する
$ touch README.md
$ touch hello.txtコミットする
$ git add .
$ git commit -m "first commit"これで3つのファイルがインデックスに登録され、ローカルリポジトリのmasterブランチにコミットされた。
順序を変えて作成済みのフォルダとファイルを後からGitの管理を行うようにしても問題ない。ファイルを編集後アッドする。
ファイルを保存した状態では、作業フォルダとインデックスとに差異が生じている状態である。
$ git add .
これで、作業フォルダとインデックスとの差異がなくなる。続いてコミットすることですべてで同期が取れることになる。
自分一人での作業ならこのままでも十分バージョン管理ができる。
ブランチ(歴史の分岐)
プロジェクトの歴史を分岐させブランチを複数作ることで、他の作業に影響を与えることなく個々の修正作業を行うことができる。
例として、初めの方で図解したような
master ブランチでの開発作業は行わない
修正を加える / 新規に追加する ような作業は、新しいブランチを作成してそのブランチ上で作業を行う
作業が終了したらそのブランチでの変更をmasterブランチへ反映させる
作業用ブランチを削除する
という形がある。図を再掲載する。
この節では、図の上半分の解説となる。
現在のブランチを確認する
git branch
- 引数なしで実行すると現在存在するブランチがリストされ、作業しているブランチに「*」印がつく
新しいブランチを作り乗り換える
git branch topic
topic ブランチが作られる
ブランチはmasterとtopicの二つとなったが、現在内容はまったく同じである
git checkout topic
- 作業フォルダが topic ブランチになる
作業例
先のhelloプロジェクトで作業を行う。
topicブランチを作成し、チェックアウトする
$ git branch topic
$ git branch
* master
topic
$ git checkout topic
Switched to branch ‘topic’
$ git branch
master
* topichello.txt を編集しアッド・コミットする(下ではgit status で状態を表示させている)
$ git status
On branch topic
nothing to commit, working tree clean$ vi hello.txt // <- エディタで1行だけ編集
$ git status
On branch topic
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: hello.txt
no changes added to commit (use "git add" and/or "git commit -a")$ git add hello.txt
$ git status
On branch topic
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: hello.txt$ git commit -m "hello.txt 編集"
[topic eddda2f] hello.txt 編集
1 file changed, 1 insertion(+)
$ git status
On branch topic
nothing to commit, working tree cleancheckoutしてmasterブランチにマージする
$ git log –oneline
eddda2f (HEAD -> topic) hello.txt 編集
3e1afbf (master) first commit$ git checkout master
Switched to branch ‘master’
$ git log –oneline
3e1afbf (HEAD -> master) first commitマージ前にhello.txtを確認すれば空のファイルである。
$ git merge topic
Updating 3e1afbf..eddda2f
Fast-forward
hello.txt | 1 +
1 file changed, 1 insertion(+)$ git log –oneline
eddda2f (HEAD -> master, topic) hello.txt 編集
3e1afbf first commithello.txtを見れば編集内容が反映されていることが確認できる。
リモートに共有リポジトリを作成しプロジェクトを管理する
協同作業者がアクセスできる環境に共有レポジトリを作成する。リポジトリを置く環境は外部Linuxサーバでも良いし内部SMB、NFSサーバでも良い、いづれにせよ利用者がアクセスできる環境であれば良い。
ここでは一般的に外部にあるLinuxサーバ上にGitリポジトリを構築する作業例を示す。
Linux にリポジトリを作成する
ここは、リモートの Linux サーバ側の作業です。
Gitリポジトリにアクセスできるグループを作成し作業者のユーザをグループに加える。
$ sudo groupadd git
git グループを作成したのでプロジェクト参加者をグループに加える
$ sudo usermod -aG git [ユーザー名]
ここでは、/var/lib/ ディレクトリに git/ ディレクトリを作成しそこにリポジトリを作成する。
$ cd /var/lib
$ sudo mkdir git
$ cd git
$ sudo mkdir hello.githello.git ディレクトリのグループをgitに変更する
$ sudo chgrp git hello.git
$ cd hello.git
$ sudo git init –bare –shared
Initialized empty shared Git repository in /var/lib/git/hello.git/hello.git 内に作成されたファイルやディレクトリのグループをgitに変更する
$ sudo chgrp -R git ./*
ローカルで作成したプロジェクトをリモートに反映させる
ここは、ローカルのPC側の作業です。
ローカルのプロジェクト側からプッシュすることでリモートへ反映できる。
初めてのプッシュなのでローカルの情報全てをプッシュする。
$ git push –all ユーザ名@remote-host.jp:/var/lib/git/hello.git
以下は確認。
別のフォルダ(clone_hello)へリモートからクローンする
$ git clone ユーザ名@remote-host.jp:/var/lib/git/hello.git clone_hello
clone_hello にはmasterブランチがクローンされている。
$ cd clone_hello
$ git branch
* master別のフォルダ(topic_hello)へリモートからtopicブランチをクローンする
$ git clone -b topic ユーザ名@remote-host.jp:/var/lib/git/hello.git topic_hello
topic_hello にはtopicブランチがクローンされている。
$ cd topic_hello
$ git branch
* topic
Git コマンド まとめその2
初期化関連(git init)
git init
- Git 管理ディレクトリとして初期化を行う。
オプション
- –bare
作業ファイルのないGit管理のディレクトリとする。
- –shared
グループ権限で読み書き可能な状態にして、初期化を行う。
ブランチ関連(git branch)
git branch
- ローカルリポジトリのブランチの一覧を表示し、現在作業中のブランチには「*」がつく。
git branch <branchname>
- 現在のブランチから枝分かれする<branchname>のブランチを作成する。
オプション
- -r, –remotes
リモートリポジトリのブランチの一覧を表示する。
- git branch -r
- -a, –all
ローカルとリモートリポジトリ両方のブランチ一覧を表示する。
- git branch -a
- -d, –delete
<branchname>ブランチを削除する。
- git branch -d <branchname>
- -m, –move
現在のブランチを<branchname>にリネイムする。
- git branch -m <branchname>
- -c, –copy
現在のブランチを<branchname>で複製する。
- git branch -c <branchname>
チェックアウト関連(git checkout)
git checkout <branch>
- 作業フォルダ、インデックスそしてHEADを<branch>ブランチへ切り替える。作業フォルダでのファイルへの変更は保持される。
git checkout <commit>
- 作業フォルダ、インデックスそしてHEADを<commit>へ切り替える。作業フォルダでのファイルへの変更は保持される。
オプション
- -b <new_branch>
新規に<new_branch>ブランチを現在のブランチから作成し、そのブランチにチェックアウトする。
- git checkout -b new_topic
クローン関連(git clone)
git clone URI [ディレクトリ名]
masterブランチをクローンする。クローンを作成するディレクトリが指定できる。ディレクトリ名が省略されるとサーバ側のディレクトリ名(.gitは名前から除かれる)と同じ名前のディレクトリが作成されクローンされる。
Gitで管理されたプロジェクトのパスを指定する。 自マシンにマウントされているのならそのパスを指定する。
path/to/repo.git
<file:///path/to/repo.git/>
LANあるいはインターネット経由でアクセスするのなら、ユーザ名@ホスト名:パス
host.xz:/~[user]/path/to/repo.git/
ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
git://host.xz[:port]/~[user]/path/to/repo.git/
オプション
- –branch <name>, -b <name>
<name>ブランチをクローンする。
複数人でプロジェクト管理
ここでは、二人のユーザhanakoとtaroが各人のPC上で、共通のhelloプロジェクトの開発を行うという設定で具体例を挙げていく。
登場人物は以下の3者である。なお、前述までの内容がすでにリモートに反映されており、二人のユーザはどちらもその状態をクローン済みである。
リモートレポジトリ remote-host.jp:/var/lib/git/hello.git
hanakoと彼女のローカルリポジトリ ~/project/hello_A/
taroと彼のローカルリポジトリ ~/work/hello_B/\
以下のようなストーリでGit操作の手順をまとめる。
hanako : welcome.txtを作成し、プッシュする
taro : welcome.txtを編集し、プッシュする
hanako : welcome.txtを編集し、プッシュする
hanako : 衝突したwelcome.txtをマージし、プッシュする
hanako : welcome.txtを作成し、プッシュする
ここでhanakoが行う操作は次のものである。
作業開始前のプルを行う
新規ブランチを作成しそこで作業を行う
インデックスに加え、コミットする
リモートリポジトリへプッシュする
master へマージしプッシュする
確認も含めて作業する。
作業開始前のプルを行う
$ git pull
hanako@remote-host.jp’s password:
Already up to date.新規ブランチを作成しそこで作業を行う
$ git checkout -b make_welcome
Switched to a new branch ‘make_welcome’確認する
$ git branch
* make_welcome
master$ touch welcome.txt
インデックスに加え(新規ファイルなので明示的にアッドする)、コミットする
$ git add welcome.txt
$ git commit -m "add welcome.txt"
[make_welcome e4ff3c1] add welcome.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 welcome.txtリモートリポジトリへプッシュする
$ git push –set-upstream origin make_welcome
......
* [new branch] make_welcome -> make_welcome
Branch ‘make_welcome’ set up to track remote branch ‘make_welcome’ from ‘origin’.ブランチを確認する
$ git branch -a
* make_welcome
master
remotes/origin/HEAD -> origin/master
remotes/origin/make_welcome
remotes/origin/master
remotes/origin/topicローカルレポジトリでは、make_welcome がHEADになっている
リモートでは、origin/master がHEADになっている
リモートに、make_welcomeブランチができている\
まだ、make_welcomeブランチはmasterにマージされていない。
$ git log –oneline –graph –decorate –all
* 68bcc9e (HEAD -> make_welcome, origin/make_welcome) add welcome.txt
* eddda2f (origin/topic, origin/master, origin/HEAD, master) hello.txt 編集
* 3e1afbf first commitmaster へマージしプッシュする
$ git checkout master
Switched to branch ‘master’
Your branch is up to date with ‘origin/master’.\$ git merge make_welcome
Updating eddda2f..68bcc9e
Fast-forward
welcome.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 welcome.txt$ git push
hanako@remote-host.jp’s password:
Total 0 (delta 0), reused 0 (delta 0)
To remote-host.jp:/var/lib/git/hello.git
eddda2f..68bcc9e master -> master4つのブランチ master, make_welcome, origin/master, origin/make_welcome が全て同期されている。
$ git log –oneline –graph –decorate –all
* 68bcc9e (HEAD -> master, origin/master, origin/make_welcome, origin/HEAD, make_welcome) add welcome.txt
* eddda2f (origin/topic) hello.txt 編集
* 3e1afbf first commit
taro : welcome.txtを編集し、プッシュする
\% TODO 何か変だぞ もう一度やり直す
ここでtaroが行う操作は次のものである。
作業開始前のプルを行う
新規ブランチを作成しそこで作業を行う
インデックスに加え、コミットする
リモートリポジトリへプッシュする
master へマージしプッシュする
先のhanakoの作業を引き継ぐように作業を行うが、のちにコンフリクトが生じhanakoがマージ作業を行うことになる。
作業開始前のプルを行う
$ git pull
...確認
$ git log –oneline –graph –decorate –all
* 68bcc9e (HEAD -> master) add welcome.txt
* eddda2f (topic) hello.txt 編集
* 3e1afbf first commit新規ブランチを作成しそこで作業を行う
$ git checkout -b change_welcome
Switched to a new branch ‘change_welcome’$ vi welcome_txt <- 2行加えた。うち1行がコンフリクトする。
インデックスに加え(インデックスにすでにファイルはあるので -a で)コミットする
$ git commit -a -m "changed welcome.txt"
[change_welcome f2e139d] changed welcome.txt
1 file changed, 2 insertions(+)リモートリポジトリへプッシュする
$ git push –set-upstream origin change_welcome ......
* [new branch] change_welcome -> change_welcome
Branch ‘change_welcome’ set up to track remote branch ‘change_welcome’ from ‘origin’.\確認
$ git log –oneline –graph –decorate –all
* 68bcc9e (HEAD -> change_welcome, origin/master, origin/make_welcome, origin/change_welcome, origin/HEAD, master) add welcome.txt
* eddda2f (origin/topic) hello.txt 編集
* 3e1afbf firsr commitmaster へマージしプッシュする
$ git checkout master
.….
$ git merge change_welcome
.….
$ git push
.….
Git その他
Git の状態を表示
現在の状態を調べる
git status
コミットする変更があるか(インデックスがリポジトリと異なるか)
ステージングされていない(アッドされていない)ファイルがあるか
などの情報を表示する。
- オプションなど詳しくは「git help status」で調べられる
git log
今まで記録された歴史を一覧する
オプションなど詳しくは「git help log」で調べられる
二つのコミット間の差異を表示する
git diff <コミットID> <コミットID>
最新のコミットを確認する
git show (HEAD)
HEAD は省略できる
HEAD とその前回のコミットとの差分を表示する
コミットIDを指定すれば、その前回のコミットとの差分を表示する
git log -p
- 前回のコミットとの差分を表示しつつ歴史を一覧する
Git コマンドのマニュアル
git help
コマンドの一覧とその説明が表示される
git help <コマンド>
コマンドのオプションや説明が表示される
ファイルを含まないディレクトリだけ登録したい
- ディレクトリは必要だが中身のファイルは(作業人ごとに異なる内容であったり、テスト時に作られ頻繁に変更されるため)登録したくない
しかし
- Gitは中身のない空のディレクトリを無視する
ファイルをディレクトリに入れなければGitにディレクトリを登録できないので、プロジェクトルールとしてファイル名を決めて、ディレクトリに格納し登録する。
よく使われるファイルは以下のもの
.gitkeep <- 空ファイルで良い
.gitignore <- 次節で扱う無視するファイルを設定するファイル
empty (と名付けた)ファイルなど
Git に登録したくないファイルの設定
エディタなどによって自動で作られるバックアップファイルや「.DS_Store」ディレクトリなど、Git に登録する必要のないファイルをあらかじめ設定し、Git に無視するように伝える。
無視するファイルの登録方法
プロジェクト/.gitignore に登録
プロジェクト/.git/info/exclude に登録
git config –global core.excludesfile $HOME/.gitexclude と設定して、$HOME/.gitexclude に登録
先の二つは、プロジェクトごとの設定となり、最後の一つはユーザのGit管理に適応される。
通常は、.gitignore に無視するファイルを登録することでプロジェクト共同メンバすべてで共有する。
無視するファイルの設定
設定ファイルの書き方。記述する内容はGitが無視するファイル名やフォルダ名。
- abc
名称を記述
ファイル名、フォルダ名に適応される。\
- !abc
abc というファイルやフォルダは無視しない
! は、否定、無視しない意味となる。\
- *.abc
.abc で終わるファイル・フォルダは無視する\
- *.[abc]
.a または .b または .c で終わるファイル・フォルダは無視する\
- abc/
abc というフォルダは無視する
末尾の / は、フォルダであることを表す。\
- /abc
ルートフォルダ直下の abc というファイル・フォルダを無視する
先頭の / は、.gitignore が置かれているフォルダを表す。
.gitignore 以外の設定では、プロジェクトのルートフォルダを表す。\
設定例 .gitignore
aaa