GitとGitHubの設定

Ubuntu Desktop環境構築 Part 13

公開日: 2020-12-28
更新日: 2023-10-01

  Table of Contents

Requirements

  • GitHubの個人アカウント作成済み
  • Visual Studio Codeインストール済み

What is Git?

Gitとは, ファイルやソースコードの変更を分散型でトラッキングする仕組みです. ファイルやソースコードの変更をトラッキングする仕組みのことをバージョン管理システムと呼んだりします.

Def: Version Control System

変更履歴を管理することを通じて,

  • 前回差分箇所をハイライト
  • ファイルの特定の段階に戻る
  • ファイルを復活

などを実現する仕組みがVersion Control System(VCS)です.

VCSを活用するメリットの具体例として,

  • あのとき動いたが,今は動かない… もう一回動いていた状態に戻したい
  • このコードを加えた人とタイミングを知りたい
  • 前回消してしまったコードを復活させたい
  • 同じテーマで2つファイルが発生してしまったから差分を確認したい

つまるところ,「VCSを活用することで, 一回とんでもない変更をしたとしても, すぐプロジェクト全体の状態を戻したり修正することができる」ということです.

Local VCS vs Distributed VCS

Version管理システムは分散型と集中型の2つに大別することができます.

  • 集中型: 変更履歴などのデータを一つの中央サーバーに集めて管理する種類のこと
  • 分散型: 各クライアントがリポジトリをミラーし終わったあとは, 変更履歴の参照などのVersion管理アクションは各々のクライアント内部で閉じている種類のこと

分散型は,最新のソースコードの管理が難しいというデメリットがありますが(いわゆるコンフリクト), クライアントのローカル環境内部で変更履歴の確認等の作業が完結するので, 集中型Version管理システムで直面するnetwork latency overhead問題を余り気にせずに開発作業をすることができます.

Centralized Version ControlDistributed Version Control

集中型VCSでは, 1つのrepository(=データを保存する場所)に対して多くの開発者とコンテンツを共有しているため, 2人で同じファイルを同時に編集してしまうと, 先に編集した人の変更内容が消えてしまうリスクがありました. 一方, Gitではリモート側の内容をローカルへコピーした上で, 手元のVCS内部で編集作業を行い, remoteへ同期する際は, merge conflictという形でdiffが警告され強制的な上書きを防止くれるので, 分散型のメリットに基づく平行開発環境を提供してくれています.

また, merge conflictが発生してもそれを解消するコマンドを提供してくれているので, その便利さがGitが今日普及した理由と考えられます.

What is Git Repository?

repositoryとはデータを保存する場所のことです. Gitでは,このrepository単位でデータを管理しており,修正ログもrepository内に保存されています. Gitは分散型Version管理システムであるため,repositoryは各開発者側にlocal環境へミラーリングして利用します.

このとき, GitHub/GitLab上のリモートサーバーに置かれたrepositoryをremote repository, 開発者がlocalにおくrepositoryはlocal repositoryと呼ばれます.

GitによるVersion管理

Snapshots vs Differences

Version管理の方法として, Gitは差分(Differences)でなくSnapshotsでデータを管理しています. Git は基本的に,すべてのファイルが各時点でどのように見えるかをSnapshotで記録し,そのSnapshotへの参照を保存します. 効率化のため,ファイルが変更されていない場合は, Git はファイルを再び保存せず,すでに保存されている以前の同じファイルへのリンクだけを保存します.

Snapshots vs Differencesのイメージは以下のFiguresとなります.

commits are snapshots, not diffs

Gitのバージョン管理の仕組み

sequenceDiagram

  participant A as working directory<br>(working tree)
  participant B as staging area<br>(index)
  participant C as local repository<br>(local branch)
  participant D as local repository<br>(tracking branch)
  participant E as remote repository

  A->>B: git add
  B->>C: git commit
  C->>E: git push
  C->>A: git switch -c<br>(checkout)
  E->>D: git fetch
  D->>A: git merge
  E->>A: git pull (実質的には git fetch + git merge)

Gitはディレクトリ単位でVersion管理します. 管理されるディレクトリには3つのエリアが作られ,それぞれWorking Directory,Staging Area,Respositoryと呼びます.

  • Working Directory:
    • ドキュメントやプログラムファイルの作成などの作業を行う場所
    • 開発者が作業するためのディレクトリ領域
  • Staging Area:
    • 変更履歴として保存するファイルを選択し,置いておく場所
    • git addで指定したファイルが行き着くところ
  • Respository:
    • 変更履歴を記録しておく場所
    • Staging Areaに置かれているファイルを変更履歴をリポジトリに保存することを「Commit」といいます

Git管理されたファイルはmodified, staged, committedという状態が与えられ,それぞれの状態がファイルがどこのエリアにいるかを示しています.

状態 説明
modified ファイルの内容は変更されたがまだcommitされていない状態(データベースに記録されていない状態)
staged ファイルが次のcommitでデータベースに記録される準備ができたことを示します
committed ローカルレポジトリにファイル変更履歴が記録されていることを示します
sequenceDiagram
    participant wd as Working Directory
    participant sd as Staging Area
    participant cd as .git directory<br>(=Repository)
    cd->>wd: Checkout the project
    Note left of sd: git checkout<br>git restore
    wd->>sd: Stage Fixes
    Note left of sd: git add<br>git rm
    sd->>cd: Commit
    Note left of cd: git commit

git ls-fles: stagedにインデックスされているファイルの表示

git ls-filesコマンドでステージングエリアに存在するファイルを確認することができます. ただし,gitの監視対象にある,ディレクトリに存在するファイルのみをリスト化するということであって,ディレクトリは確認することができません.

1
2
3
4
5
6
7
8
9
 % git ls-files
.gitignore
404.html
Gemfile
Gemfile.lock
Gruntfile.js
LICENSE
README.md
...

また,オプションを組合せてgit ls-files -io --exclude-standardと入力するとgitignoreに記載されているファイル=stagedされないファイルのみを表示することもできます.

  • -iオプションで無視ファイル(ignore)のみを表示
  • -oオプションを渡すことで管理対象外のファイルを表示
  • --exclude-standard オプションは .gitignore 等で無視されているファイルを除外するオプション

Gitはどこにバージョン管理のDBをもっているのか?

git initによってGit管理に指定したディレクトリには.gitというディレクトリが作成されます.Git が保管したり操作したりする対象の,ほとんどすべてがここに格納されます. リポジトリのバックアップやクローンをしたい場合,このディレクトリをどこかへコピーするだけで,ほぼ事足ります.

.git ディレクトリの中は以下のようになっています.

HEAD
config*
description
hooks/
info/
objects/
refs/

重要なのは4項目です.具体的には, HEAD ファイル, index ファイル(まだ作成されていない), objects ディレクトリ, refs ディレクトリです. これらがGitの中核部分になります. objects ディレクトリにはデータベースのすべてのコンテンツが保管されます.refs ディレクトリには,それらコンテンツ内のコミットオブジェクトを指すポインタ(ブランチ)が保管されます.HEAD ファイルは,現在チェックアウトしているブランチを指します.index ファイルには,Git がステージングエリアの情報を保管します.

Gitはどのように履歴データを取り出しているのか?

Gitはシンプルなキー・バリュー型データストアです.どんな種類のコンテンツでも格納でき,それに対応するキーが返されます.キーを使えば格納したコンテンツをいつでも取り出せます.ここでのコンテンツのことを「コミットオブジェクト」といいます.「コミットオブジェクト」はコミットによって生成されたデータのことです.Gitはコミットオブジェクトに対して40文字のIDを発行します.これがコミットハッシュ値でキー・バリューのキーに相当します.

コミットオブジェクトの中身を確認したい場合は,git cat-file -pで任意のコミットのコミットオブジェクトを見ることができます.

1
2
3
4
5
6
% git cat-file -p 757cd618f38d574238bae4768ff1a1aedfafdb7a
tree 05520e3bd0354e823cacf96b244987f235b3c240
parent 2476c4c7bcbf98e444b6851d67036077334502d2
author DQNEO <dqneo@example.com> 1454588308 +0900
committer DQNEO <dqneo@example.com> 1454588308 +0900
second commit
  • treeというのはtreeオブジェクトのことで,これはディレクトリツリーに対して割り振られるIDです.(もうちょっと厳密に言うと,treeオブジェクトは1つ以上のtreeオブジェクトまたはblobオブジェクトを持つツリー構造のデータです)
  • parentというのは親コミットすなわち1個前のコミットのハッシュ値です.Gitのコミットオブジェクトは必ず1つ以上の親コミットを持っており,親を順番にたどっていくことで履歴をさかのぼることができます.
  • authorとcommiterは普通同じ人になるのですが,cherry-pickしたりrebaseしたりすると異なる名前になることがあります.
  • 1行空行をはさんでそこから下がコミットメッセージです.

なお,コミットオブジェクトに対応するハッシュ値の計算式は以下のようになります

hash = sha1("commit<半角スペース><コミットオブジェクトのバイト数>\0<コミットオブジェクトの中身>")

How to Install Git

Ubuntu 20.04 LTSにGitをインストールすのは簡単で以下のコマンドをターミナルで実行するだけです.

1
2
% sudo apt update && sudo apt upgrade -y
% sudo apt install git-all

Versionを確認しときます.

1
2
% git --version
git version 2.30.0

Setup

Git configファイルの置き場所は3パターンあります:

PATH 説明
/etc/gitconfig システム上のすべてのユーザーとそのすべてのリポジトリに適用される値を保持します.git config に --system オプションを指定すると,このファイルから読み書きします.これはシステム設定ファイルなので,これを変更するには管理者権限かスーパーユーザー権限が必要となります.
~/.gitconfig ユーザー自身に固有の値を指定します.--global オプションを指定することで,Git にこのファイルの読み書きをさせることができます.
config file in the Git directory その単一のリポジトリーに固有の値を指定します.このファイルの読み書きを強制的に行う場合,--local オプションを指定しますが,デフォルトで参照するようになっています.このオプションが正しく動作するには,Git リポジトリのどこかに位置している必要があります.

以下のコマンドでconfig一覧を確認することができます

1
% git config --list --show-origin

~/.gitconfigの設定

configファイルの設定をここから紹介します.Version管理を実現するためには誰がどのファイルをいつ変更したのかのデータが必要です.なのでまずユーザーがだれなのかをgitに教えるため,user nameとemail addressをconfigに設定します.

1
2
% git config --global user.name "John Doe"
% git config --global user.email johndoe@example.com

次にEditorの設定をします.commitメッセージを書くときなどに立ち上がるEditorの設定となります.

1
% git config --global core.editor nano

次に default branch nameを設定します.昔はmasterで最近はmainと変わってきたところですがこちらは好みなので設定は任意です.

1
% git config --global init.defaultBranch main

commit templateの作成

Commit messageのテンプレートを作成します.commit messageを作成する際に,適切なフォーマットやスタイルを自分(または他の人)にリマインドすることができるというメリットがあります.

まず,~/.gitmessage.txtというファイルを以下のように作成します.commit message conventionなるものを確認したい場合はこちらのサイトがおすすめです.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<type>[optional scope]: <description>

[optional body]

Reviewed-by: [reviewer]
Refs: [ticket]

# ==== Type ====
# Add      ADD new file, function, feature
# Update   UPDATE existing functions/features
# Clean    Refactoring
# Remove   REMOVE files
# Fix      FIX bugs
# Upgrade  Upgrading to a new version

# ==== Type ====
# [Refs]: #<number>: referring an issue on GitHub
# [close, closed, fixed, resolve, resolved] #<number>: closing issue

git commit を実行したときにDefaultのメッセージとして使うためには,commit.templateの設定値を設定する必要があります.

1
% git config --global commit.template ~/.gitmessage.txt

GPGキーの登録

Gitは, メールアドレスを使って誰がAuthorなのか,Committerであるかを判別するしています. しかし, メールアドレスは各自がlocalの git config で設定できる属性のため, 簡単になりすましができてしまうという 問題があります.

このようななりすましの対策として, GPGキーを用いたgit commitへのデジタル署名がGitHub公式ページでは推奨されています. GPG公開鍵をGitHubに登録とすると, commitとtagが正常に検証されたGPGキーで署名されている場合,「Verified」としてマークがつくようになります.

GPGキーの生成とGitHubへの登録

GitHubでサポートされていないアルゴリズムを用いてキーを生成 & 追加しようとすると, エラーが生じることがあるので, サポートされているアルゴリズムをまず確認します:

1
RSA,ElGamal,DSA,ECDH,ECDSA,EdDSA

GPGキー生成

1
% gpg --full-generate-key
  • キーは少なくとも 4096 ビットである必要があり
  • キー有効期間は, 無期限を示すデフォルトの選択を指定(公式の推奨)
  • ユーザID情報時に求められるメールアドレスは, GitHub アカウント用の検証済みメールアドレスを入力
  • GPGキーはホームディレクトリ以下の.gnupg/openpgp-revocs.dに生成されます

生成されたGPGキーの確認

生成されたGPGキーの確認は以下のコマンドでできます. GitHubでは秘密鍵のGPGキーIDの長い形式の登録が必要なので, ` –keyid-format=long` オプションをつけて表示します.

1
2
% gpg --list-secret-keys --keyid-format=long  
% gpg --list-public-keys --keyid-format=long  

なおそれぞれ2つのIDがでてきますが, それらの意味は以下です:

sec SECret key
ssb Secret SuBkey
pub PUBlic key
sub public SUBkey

GitHubに登録するGPGキーの確認

まず秘密鍵のGPGキーを確認します. この例では, GPG キー ID は 3AA5C34371567BD2 です

1
2
3
4
5
6
% gpg --list-secret-keys --keyid-format=long
/Users/hubot/.gnupg/secring.gpg
------------------------------------
sec   4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]
uid                          Hubot 
ssb   4096R/42B317FD4BA89E7A 2016-03-10

次に, 秘密鍵情報をASCII形式(テキスト形式)で出力します

1
% gpg --armor --export 3AA5C34371567BD2

—–BEGIN PGP PUBLIC KEY BLOCK—– で始まり、—–END PGP PUBLIC KEY BLOCK—– で終わる GPG キーをコピーし, それを登録します.

Git へ GPG キーを伝える

GitHubへのGPGキー登録後, GitでGPG署名キーを設定する必要があります.

GPG キー ID は 3AA5C34371567BD2の場合,

1
% git config --global user.signingkey 3AA5C34371567BD2

きちんと登録されているかどうかの確認するため, .gitconfigを開きます(場所は個人次第)

1
% cat ~/.gitconfig

.zshrcへの登録

1
% [[ -f ~/.zshrc ]] && echo 'export GPG_TTY=$(tty)' >> ~/.bashrc

[[ -f ~/.zshrc ]]は条件式で -f 後のファイルパスが存在するならば 1 else 0を返します.

コミットに署名する

-S フラグをgit commitコマンドに追加し, pushするだけで完了です.

1
2
3
4
% git commit -S -m "your commit message"
# Creates a signed commit
% git push -u origin main
# ローカルコミットをリモートリポジトリにプッシュする

タグに署名する

  1. タグに署名するには, git tag コマンドに -s を追加します.
  2. タグをgit tag -v [tag-name] コマンドで検証(verify)します
1
2
3
4
% git tag -s mytag
# 署名済みのタグを作成する
% git tag -v mytag
# 署名済みのタグを検証する

Appendix: BFG Repo-Cleanerのインストール

BFG Repo-Cleanerとは?

BFGは, git-filter-branchと同様にGit Repository Historyから機密データ(例:パスワードや認証情報、その他のプライベートなデータ)をクレンジングしてくれるツールです.オープンソースコミュニティによって構築およびメンテナンスされています.

誤って個人情報を含んだファイルをrepositoryに上げてしまい情報流出が発生してしまう恐れは多々あります. その際,ファイルの削除だけでなくhistoryの削除も実施する必要があり,そのようなときにBFGが役に立ちます.

BFGのインストール

1
2
% cd ./tools/bfg
% wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar
  • ./tools/bfgは自分がapt以外の経由でパッケージをインストールする際に使っているディレクトリなので,任意の場所でも構いません

つぎにCLIから簡単に呼び出すことができるようにaliasを指定します. 自分はzshを使っているので.zshrcに以下のラインを追記します.

1
alias bfg='java -jar ~/tools/bfg/bfg-1.14.0.jar'
  • javaコマンドが必要なのでsudo apt install -y default-jdkとかでOpenJDKをインストールすることが必要です

利用方法

Delete all files named ‘id_rsa’ or ‘id_dsa’ :

1
% bfg --delete-files id_{dsa,rsa}  my-repo.git

Replace all passwords listed in a file (prefix lines ‘regex:’ or ‘glob:’ if required) with REMOVED wherever they occur in your repository :

1
% bfg --replace-text passwords.txt  my-repo.git

References



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)