自転車とプログラミング

自転車メーカーに勤める会社員がプログラミングを学ぶ中で感じたことを書きます。最近サービス作りました。

Gitちんぷんかんぷんな私がGitを学ぶ!そこから学習のコツを見つけるところまで

これは「フィヨルドブートキャンプ Part 2 Advent Calendar 2020」の21日目の記事です。

フィヨルドブートキャンプ Part 2 Advent Calendar 2020 - Adventar

昨日はchihasoさんのプログラマー一年目の最大の学びは「手順書を書くこと」でした。
業務を具体化する手順書を書くことで抜けもれなく仕事ができて、しかも自分で覚えておく必要がなくなり効率的に業務に取り組めるようになったことがまとめられています!業務の段階が変わる都度、手順を組み立てると非常に時間がかかるし、頭を使います。最初に時間がかかっても手順書でアウトプットしておくと、正確だし後の時間も大きく短縮できますね!

はじめに

今回の記事はGit超初心者の私が理解促進を兼ねて、「Gitとは?」からGitの導入と基本操作を記事化しました。

もともとはフィヨルドブートキャンプのカリキュラム内で「新しいLinuxの教科書」を読んでいて、Linuxの操作やシェルスクリプトについて勉強していたところ、突然Gitの紹介〜解説が始まり理解が追いつかなかったことがありました。

読んでいた際は「今までシェルスクリプトやってたのに突然バージョン管理ソフト?の解説が始まったぞ!???」とけっこう混乱。復習を兼ねて今回の記事を執筆します。

そもそもバージョン管理システムって?

バージョン管理システムとはいわばファイルの変更履歴を保存して管理するツールです。
修正を施すファイルに対して「誰がどういった修正を加えたか」確認でき、必要に応じてファイルを過去の状態に巻き戻すことがバージョン管理システムの大きな目的です。 自分ひとりでプログラミングをするのであれば、人力でもそれほど難しいことでは無いかもしれません。一方でチームでのソフトウェア開発となるとバージョン管理システムの恩恵は多大なものになる(と思われます)。

さらにそもそもバージョンって何???

バージョンとは版や型を意味する英単語。ver1.0.0みたいな形で表現してるのをよく見ます。
内容を改良し更新させることで現バージョンから異なるバージョンになります。
ちなみに改良を指すバージョンアップは和製英語なのでアップグレードもしくはアップデートが英語的には正しいそう。

バージョン管理システムってどう良いの?

まずバージョン管理という概念がないと単一のオリジナルファイルに修正を加え続けることになります。不可逆的な処置をした場合、もとに戻すことができず非常にリスキーです。
バージョン管理という思想があったとしても手入力では「201215〜.txt」のような管理方法が限界ですし、どこかで守られなくなることが多くあります。 また、もし複数人で手を加えていたら、片一方がファイルを作った直後にもう一方が同名で上書きしてしまうかもしれません。 まあ、どちらもド文系の私が文系な職場でやってしまっていたことですが😅…。
バージョン管理システムを用いることで上記のリスクを避けることができ、冒頭の目的を叶えることができる代物というわけですね。

バージョン管理システム Git

Gitってなに?

Gitとは分散型バージョン管理システムです。
分散型バージョン管理システムとは、そのプログラムに携わる各々のローカル環境に変更履歴を含むプログラムの情報が複製され、それをもって修正を行うことができるものです。後述の集中型に比べて修正作業が競合するリスクが低く、それでいてオフライン環境で作業ができることから利便性が高くなります。

GitはもともとLinuxの開発者がLinuxの開発用に作ったシステムが、世界中のエンジニアに広がっていったそうです。Linuxカーネルの開発に使われてることは新しいLinuxの教科書に書いてありましたが、開発者本人が作ったとは…!

Git以外のバージョン管理システム

バージョン管理システムはGitに限らず色々あって、例えば集中型バージョン管理システムsvnというのがあります。ですがエンジニア界隈では利便性の高いGitが人気を博していて、勉強するならまずはGitというのが鉄板のようです。
このあたりまでで「新しいLinuxの教科書」にGitが出てきた理由が見えてきましたね。

Gitの使い方

それではGitを使ってみます。

使い方の解説はこちらにまとめました

Gitを導入しよう

インストール

まずはインストールです…が予めインストールされてる場合があるので、それを確認しましよう。

$ git --version 

Gitがインストールされていればバージョンが表示されます。されてなければ↓↓。

# apt-get install git

初期設定

Gitを使うには、まず名前とメールアドレスを設定しなければなりません。Gitを使用しているユーザーがだれなのか、をGitに伝えるための設定です。

$ git config --global user.name '名前'
$ git config --global user.email 'メールアドレス'

使い方

初期設定を終わって、具体的な使い方に入ります。

リポジトリを作る

リポジトリとはGitがファイルの履歴を保存している場所のことです。

$ mkdir -p˜ /git/test
    #まず作業を行うディレクトリをつくります。
$ cd˜ /git/test
$ git init
    # git initでGit用に初期化します。

初期化すると.gitディレクトリが作成されます。これがリポジトリです。ファイルの変更履歴はすべてこのリポジトリに保存されています。 このリポジトリが作成されたディレクトリをワークツリーと呼び、リポジトリの内容を復元・展開する場所として使用されます。

リポジトリにファイルを追加

さてリポジトリにファイルを追加してみましょう。ここでは事前に作ったblogtest.shという$1をそのままechoで出力するだけのものを使用します。

$ git add blogtest.sh
    #blogtest.shを履歴として追加するよう指定
$ git commit -m 'コメント'
    #直前に指定したファイルをリポジトリに登録

コミットしたときに今回登録したファイルに対するメッセージも登録できます。

差分の表示と再コミット

さて、コミットしたファイルに修正を加えたとしましょう。 現ファイルと前回のファイルの差分を表示するコマンドがあります。

$ git diff

通常のdiffコマンドのように2つのファイルの差分を確認できます。 また、ファイルに修正が加わったかどうか知る方法もあります。

$ git status

git statusコマンドはワークツリーの状態とワークツリー内のファイルの状態を教えてくれます。修正が加わったファイルにはmodifiedの表示が入ります。

再コミットは初回のコミットと同じ手順でOKです。

履歴の確認

変更を重ねてきたときに変更の履歴を見たくなるかもしれません。変更の履歴はGitのリポジトリに保存されているので確認することができます。

$ git log

ワークツリーとインデックスとリポジトリ

ファイルをコミットするときにgit addをしてからgit commitと2段階になっていました。git addされたファイルは[インデックス]というコミット前のファイルを仮置する場所に登録されます。
なので、各々の場所にも意味合いがあって

  • 「ワークツリー:作業場所」
  • 「インデックス:コミットするファイルの仮置場」
  • リポジトリ(ローカル):リモートリポジトリに送るためのコミットを記録する場所」
  • リポジトリ(リモート):複数人で共有するリポジトリ

「一度にコミットできれば手間少なくていーじゃん」と思ったのですが、git addにはいくつか役割があるようです。

一つは誤コミットの回避です。初めてGitに触れる私と違って本職の方々はスケールがでかくて、一度にコミットするファイルの量も盛りだくさん(と思う)。そういったときに直にコミットできるとコミット漏れが生じやすくなってしまいます。しかもチームで稼働しているとコミット漏れの影響を他メンバーも受けてしまいます。
そこでコミット前のファイルを仮置する仕組みを設けて、ワークツリー↔インデックス↔リポジトリ間の差分を確認できるようにすることで、誤コミットを回避できるようにしています。

ここのあたりでようやくGitの開発思想が私にもわかりました。チームでプログラムを開発する際、円滑に物事が運ぶようするためのツール。それがGitです。

コミットの単位

一つのコミットには一事柄に関する修正のみが推奨されます。新機能の追加と不具合の解消は一度にコミットするのはNGとなります。

新しいLinuxの教科書には「新機能の追加」をインデックスに追加してから、ワークツリーで「不具合の解消」を修正するというようなやり方が書かれていました。ワークツリーとインデックスの内容がこんがらがっちゃいそうですがどうなんでしょうかね😅

ミスからの復旧

ファイルを誤って消去等してしまい復旧させたい、というときに過去の状態に戻すことができます。

$ git checkout HEAD .
    #ワークツリー最上位ディレクトリで実行
    #ワークツリーとインデックスがリポジトリと同じ状態になる

復旧方法はこれ以外にも色々あるようです。

ブランチを使う

チームでソフトウェア開発することを想像すると、新しい機能の開発や不具合の修正を順次進めるというのはあまりイメージできません。どちらかというと並列的に進行していくはずです。 このときに使われるのが、リビジョンからコミットを枝分かれ(派生)させるブランチ、枝分かれした修正を取り込むマージという機能です。

$ git branch ブランチ名
    #ブランチを作成する

$ git branch
    #ブランチ一覧を表示する

$ git checkout 移動先ブランチ名
    #指定したブランチに移動する

$ git marge マージするブランチ名
    #現在作業しているブランチにマージするブランチの情報を取り込む

イメージとしては別名保存したファイルで行った修正をもとのファイルにコピペするような感じでしょうか。

バックアップを作る→復旧する

ハードの故障等の理由からこれまで作業してきたリポジトリが消えてしまう場合があります。そういった自体に備えてバックアップを用意することができます。

    #バックアップ用ディレクトリを作る
$ git --bare init
    #--bareオプションを付けると作業を行わないバックアップ用リポジトリとされる
    
$ git push 送信先リポジトリ 送信元ブランチ:送信先ブランチ    
    #git pushで変更の履歴を送信して、バックアップを作る。
    #git pushは作業中のリポジトリから使う

バックアップ用のリポジトリには慣習的に.gitとつけるようです。 git pushで作ったバックアップは複製することができます。

$ git clone 複製元リポジトリ
    #複製を作るディレクトリで行う

ここまでで自分一人でGitを使ってバージョン管理をして、修正内容によってはブランチを使ったり、バックアップから復旧させたりできるようになりました。ファイル名で管理したりする、人力バージョン管理から卒業ができますね。

Gitのすごいところと学び方のコツ

記事執筆のためにGit調べてみれば、 活用するメリットはそこかしこに記載されていて枚挙に暇がありませんでした。

  • バージョン管理によるチームでの開発円滑化とリスク管理という利点
  • バージョン管理システムの中でも利便性と速度に優れるGitが選ばれていること
  • 大多数が使用するGitはノウハウが構築されていること

等々…Gitが如何に優れていて、学ぶべきかという理由がたくさん見つかりました。こりゃー本職の方々は右を向いても左を向いてもGitなんだろうなぁと想像がつきます。

ここまでGitを調べてみて、私がGitを最初に学んだ段階でスムーズに飲み込めなかった理由が見えてきたように思います。それは「なぜバージョン管理システムを、Gitを学ぶのか」という本質的な部分が見えてなかったことです。

バージョン管理がなぜ必要なのか、なぜ数あるバージョン管理システムのうちGitなのか。 そういった根幹となる思想・理念・理由を省いて操作方法を学ぼうとしたところで、枝葉を見ているだけになってしまって非常に理解度、理解速度が低くなってしまっていました。
ですので、本質的な部分(Gitが活躍するリアルな場面やGitが選ばれる理由、Gitの開発理念等)をGitが出てきたところで調べてみて、Gitを学ぶ理由をきちんと自分の中で見い出せばよかったんですね。今回の記事が私にとってのその機会だったように思います🤔

プログラミングという未知の領域を学んでいるのもあって、ついつい目の前の学習事項に因われてしまいがちです。ですが、なにを学ぶにしても「それをなぜ学ぶのか」というひとつ上の視点を常に持っておきたいですね。

ありがとうございました。

当記事は以下の書籍、WEBサイトを参考に執筆しました