ア | イ | ウ | エ | オ |
カ | キ | ク | ケ | コ |
サ | シ | ス | セ | ソ |
タ | チ | ツ | テ | ト |
ナ | ニ | ヌ | ネ | ノ |
ハ | ヒ | フ | ヘ | ホ |
マ | ミ | ム | メ | モ |
ヤ | ユ | ヨ | ||
ラ | リ | ル | レ | ロ |
ワ | ヰ | ヴ | ヱ | ヲ |
ン |
A | B | C | D | E |
F | G | H | I | J |
K | L | M | N | O |
P | Q | R | S | T |
U | V | W | X | Y |
Z | 数字 | 記号 |
Linuxカーネルの開発用に開発された分散型バージョン管理システム。Linus Torvaldsが開発し、濱野純にメンテナンスが引き継がれた。
Git最大の特徴は、分散型という点である。リポジトリが利用者それぞれに「分散」され、中央サーバーを必要としないことを特徴としており、これがSubversionやCVSなど従来のものに対するアドバンテージとなっている。
Gitは、「マスターリポジトリ」から各ユーザーの環境にリポジトリの複製を持たせるような構造となっている。このため、インターネットに繋がっていなくても、ローカルにあるリポジトリにコミットできる。つまり、電波が届かない地下鉄や飛行機の中、あるいは山奥にいても、必要に応じて変更をコミットできる。そして、マスターリポジトリへの反映は、ネットワーク接続が可能になってから可能で、それは「マージ」という。
さらに利点として、単にコミットしただけでは手元のリポジトリのみに反映されるため、マスターリポジトリに影響しない、という点がある。リポジトリへの変更が適切であればマスターリポジトリに対して変更をマージできるが、必要がなければマージしなくても良い。一度複製されたリポジトリは、マージさえしなければ手元で好き放題できるということである。
ただし、実際の運用ではマージは必須であること、マスターリポジトリが落ちている間はマージも何もできないことから、分散化自体が大きなアドバンテージと言えるかどうかは定かでは無い。実際、GitHubを用いた中央集権型のソース管理というのはありがちで、2016(平成28)年1月28日午前(日本時間)にGitHubが陥落したさい「仕事にならない」「帰りたい」などのツイートがTwitterに散乱していた。
Gitでは、あらゆるものをブランチとして扱う。
ブランチは枝分かれしたものという意味で、本流から枝分かれしたものがブランチであり、通常はこのブランチに対してアクセスすることになる。
デフォルトのブランチは「master」という名前のブランチである。
Gitにはタグ機能があり、歴史上の重要なポイントに印をつけることが可能。
何らかのコミットにタグを付けて目印にしたい場合は、まずコミットを実施し、その次にタグ追加の作業をする。
現在のコミットにタグを付ける場合は、次のいずれかをする。
$ git tag <tag-name>
$ git tag -a <tag-name> -m 'comment'
$ git tag -s <tag-name> -m 'comment'
-aも-sもないと軽量版のtagで、単なる目印のポインターでしかない。-aを付けると、commitの時と同様に注釈を付け、誰がtagを付けたかを記録できる。-sは更に厳密で、秘密鍵を持っていればtagに署名をすることができる。
また-mは省略可能で、略せば指定されたエディターが起動する。これもcommitの時と同様である。
存在するタグを確認する場合は、次のようにする。
$ git tag
git logにタグを表示するには、次のようにする。
$ git log --decorate=full
tagをキーとして見ることもでき、ハッシュの代わりにタグ名を書くだけである。注釈や署名があれば、それが最初に表示される。
$ git show <tag-name>
tagを削除するには、次のようにする。
$ git tag -d <tag-name>
このtagからbranchを作る場合は、次のようにする。
$ git chekout -b <branch name> <tag-name>
また、このchekout -bオプションは、次と同じ動作であり、次の二つの操作を実施しても同じ結果となる。
$ git branch <branch name> <tag-name>
$ git checkout <branch name>
Gitの標準では、ハッシュの頭7文字が短縮表示される。
仕様として、8000コミット以上になると頭7文字では一意に指定できない恐れが高まるとされている。実際、Linuxの開発ではGitを用いているが、既に頭7文字では被る事例が相次いでいるとのことである。
被って何が問題なのかということだが、つまり、表示される7文字でgit showしようとしても、
short SHA1 XXXXXXX is ambiguous
となってしまい、そのコミット内容をどうやっても表示することができないということである。
2n個のハッシュキーに対し、衝突確率を1/(2m)程度に抑えるためには、2(n+m)ビットのハッシュ値が必要である。
Linuxのコミット数は2012(平成24)年頃で約22万回に達したとされる。これを収める最小のビット数は218(=262144)なので18ビット。衝突確率を1/2つまり1/(21)にするためには、2×(18+1)=38ビットが必要なことがわかる。1文字で4ビットなので10文字(40ビット)が最低必要となる。Linuxの場合、10文字でも衝突は生じているが、11文字まで増やせば劇的に衝突率は減るだろうことが予想される。
では逆に、いまの7文字で可能な範囲はどの程度かを求めてみる。
4ビット/文字×7文字=28ビットなので、このビット数で衝突確率が1/2になる数を求めると、(28ビット/2)−1=13ビット、213=8192となる。
つまり、Gitの仕様として、7文字では約8000コミットを超えると半分の確率でハッシュキーが衝突し、使い物にならなくなる。
Gitには、上位から順に次の三つの階層が存在する。
git add すると、ワークツリーにあるものがインデックスに入る。しかしインデックスではイメージが湧きにくいため、インデックスと呼ぶ代わりに「ステージングエリア」と呼ぶこともある。
そしてリポジトリは、前述の通り、手元と遠隔に存在しうる。手元のリポジトリをローカルリポジトリ、遠隔にあるリポジトリをリモートリポジトリという。
実際に手元に存在し編集でき目に見えるファイルは、ワークツリーのファイルである。
リポジトリには、最古から最新まで歴史がある。そのうち、最新の状態を指し示すポインター(指標)を「HEAD」という。
後にも述べるが、HEADを指定してcheckoutすれば、ファイルをリポジトリの状態に戻すことができる。
HEADの移動には、後に詳細に述べるが「git reset」コマンドを使う。
HEADではなく、HEAD^もよく使われる。
ソースの修正→ビルド→動作確認、などを続けていると、いろいろなファイルに手が加わった結果、ブランチを切り替えたりする時に面倒なことになる。
そこで、ワークツリーの状況を綺麗な(リポジトリの)状態に戻したい時には、次のようにする。
$ git reset --hard HEAD
または
$ git checkout HEAD -- .
特定のファイルだけ、編集や削除を戻すときは、ファイル名が <ファイル名> だとすると、
$ git checkout HEAD -- <ファイル名>
でだいたい戻る。
一旦git add をしたが、やはり止めて別のコミットをしたい、と言った場合は次の方法でaddを取り消すことができる。
$ git restore --staged <ファイル名>
まず、変更中のファイルがあればcommitするか、別に避けておいてgit resetないしgit checkoutなどをして変更がない状態にしておく。
次にgit logで、どのくらい過去であるかをあらかじめ確認しておく。修正すべきコミットが過去5件以内であれば、例えば次のようにしてコミットの修正を開始する。
$ git rebase -i HEAD^^^^^
Vimなど設定したエディターが開き戻した分までのコミットが出てくるため、編集したいコミットの頭の pick を edit に書き換える。Vimなら書き換えたあと、:wq などで書き込めば、歴史改竄の作業が始まる。
ここで例えば、コミットをし忘れていた sample.txt を追加する場合を例とすると、次のようになる。
$ git add sample.txt
$ git commit --amend --no-edit
これで当該のコミットに、sample.txtが追加される。
あとは次をして、rebaseを継続させる。
$ git rebase --continue
先にeditに書き換えた全てのコミットの書き換えが終わると、修正の作業は終了となる。
pushについては後述するが、具体的には次のようにする。pushしたい現在のブランチ名を nowbranch であるとする。
$ git push --set-upstream origin nowbranch
この方法でpush後は、特に何も指定しなくても、pushだけでnowbranchの内容がpushできるようになる。
ワークツリーの内容をインデックスに登録するには、次のようにする。
$ git add <ファイル名>
実際には様々なオプションがあり、無視ファイルの設定などもあるが、もっとも単純な方法はこの通りである。
インデックスの内容をリポジトリに登録するには、次のようにする。
$ git commit
Gitにおけるコミットは、手元にあるリポジトリのみに反映される。
コミットする際にコメントを残すことができる。通常はvi相当のエディタが起動するが、次の方法で、コマンドラインからコメントを指定することでエディタの起動を抑止できる。
$ git commit -m "commit message"
Gitにおける復活の呪文はcheckoutである。
作業ファイルを、リポジトリの内容ではなくインデックスの状態に戻すには、次のようにする。
$ git checkout <ファイル名 または ブランチ名>
checkoutは、指定されたファイルをインデックスに記録されている状態に復帰させる。
ファイル名(パス付きももちろん可)を書けばそのファイルを、ブランチ名を書けば全ファイルを、インデックスの状態に戻す。
$ git checkout hoge.c
インデックスを飛び越え、リポジトリの内容をワークツリーに復帰するには、次のようにする。
$ git checkout HEAD <ファイル名 または ブランチ名>
Gitでは、「現時点での最新のコミット」をHEADという。
HEADを指定してcheckoutすると、最新のコミットされた内容(最新のリポジトリ)にワークツリーを復帰させる。
ほかのリポジトリ、つまりリモートリポジトリの変更点をマージするには、次のようにする。
$ git pull <repository name>
逆に、リモートリポジトリに自分のリポジトリの内容を送信するするには、次のようにする。
$ git push <repository name> <branch name>
多くの人が利用するリモートリポジトリに対してpull/pushする場合、手元でコミットを続けたものを満を持してpush、といった場合に確実にコンフリクト(衝突)を起こす。
この解決方法は様々あるが、面倒なことが多い。
一番手っ取り早いのは、適当なブランチを一つ作ってそこに対してコミットしておき、いざpushする時には、そのブランチをpush先のリポジトリへrebaseし、その後mergeしてからpushする、という手法である。
使用中のリポジトリをrepo、元のブランチをhoge、仮に作る手元のブランチをtempとすると、次のようになる。
手元のtempに対してコミットする。次に、元のブランチを更新する。
ここで、手元のブランチhogeのリポジトリは最新である。
ここで、ローカルブランチtempのコミット内容は最新のリポジトリに対するものに置き換わった。ここでコンフリクト(衝突)が生じた場合は訂正が必要だが、訂正後、または運良くコンフリクトしなかった場合は、早速、マージの作業に取りかかる。
ここで、元々使っていたブランチhogeに、今回コミットに使った仮のブランチtempの内容が反映された。「git log」で履歴を確認することができる。
そこで、早速リモートリポジトリに対してpushする。
これで、無事にpushできる率が高まる。
rabaseとpushの間に割り込まれた場合は面倒が起こることになるが、何もしないよりは面倒が少ない。
Gitの設定は、次のファイルに保存される。
直接書き換えなくても良いように、gitには設定のための機能が用意されている。
インストールしたら、まず名前とメールアドレスを書き込んでおくとよい。
repoなどを実行して新しいプロジェクトを取得する度に名前とメールアドレスを入力することになるが、登録してあれがEnterするだけで済む。
$ git config --global user.name "Null Potter"
$ git config --global user.email null.potter@example.com
エディターなら何でも使えるわけではない。一見動いているように見えても、正常に動作しないこともある。
例えばvimを使いたい場合は、次のように設定したりする。
$ git config --global core.editor 'vim -c "set fenc=utf-8"'
Gitには色々な欠点があるが、一番最初のコミットの修正が面倒であることもその一つである。git reabse -i で戻れるのは2番目のコミットまでで、最初のコミットには戻れない。
まだ2番目のコミットをしていないのであれば、git commit --amendで書き換えができるが、そうでない場合、次のいずれかの方法を取る。
別の考え方で、最初のコミットは空にしておく、という方法もある。
# リポジトリの作成
$ git init
# 最初のコミット
$ git commit --allow-empty -m "最初のコミット"
完全な空が好みでない場合は、後々の編集は別途コミットで実施する方が望ましいと誰もが思うような、ほぼ空のreadmeをコミットするというのも定番である。
$ echo "# xxx" >> README.md
$ git init
$ git add README.md
$ git commit -m "最初のコミット"
コメントなどを投稿するフォームは、日本語対応時のみ表示されます