newbie hhyuga

情報系の学生です。プログラミング、情報セキュリティに興味があります。

Gitの基本的な使い方

Gitとは

Gitの公式サイトhttps://git-scm.comによれば、

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

直訳すると、

Gitは、無料でオープンソースの分散型バージョン管理システムで、小さなプロジェクトから大きなプロジェクトまで、高速かつ効率的に扱えるように設計されています。

だそうだ。
もともとは、Linuxカーネルの開発を効率よく行うためにリーナス・トーバルズらによって開発されたものらしい(参考:https://ja.wikipedia.org/wiki/Git)。

インストール

下記URLより、GitのCUIクライアントをDLしインストールする。
https://git-scm.com/downloads

インストールウィザードでは、以下の選択肢に注意する。

  • 環境変数の調整
    f:id:hhyuga201515:20180830152555p:plain
    真ん中の選択肢を推奨する。
    一番上は、環境変数を変えずに済むが、「Git Bash」という付属のシェルでしかGitが使えなくなってしまう。
    一番下は、UNIX関連のコマンドがPowerShell上で使えるようになる。

ローカルリポジトリを作る

リポジトリとは

リポジトリ(repository)とは、「貯蔵所」、「倉庫」という意味を持つ英単語で、Gitでは、バージョン管理の対象となるデータの保存場所のことである。
リポジトリには、ローカルリポジトリとリモートリポジトリの2種類があり、ローカルリポジトリは、自分の端末内で管理し、リモートリポジトリは、Gitのホスティングサービス上で管理する(Github、Bitbucket等)。
ソースコード等を編集する際、ローカルリポジトリ上で変更内容を保存し、それをリモートリポジトリにアップロード(Gitではプッシュという)することで、変更を他のユーザと共有できる。

ローカルリポジトリの作り方

  1. 任意の場所に、空の作業ディレクトリを作る。
  2. 作業ディレクトリ直下で、コマンドgit initを実行する。
  3. 「.git」というディレクトリが作られていることを確認する。

この「.git」ディレクトリがある場所が、ローカルリポジトリである。

コミットする

コミットとは

コミット(commit)とは、「委託する」、「引き渡す」という意味を持つ英単語で、Gitでは、変更内容をリポジトリに保存することである。
リポジトリ内にあるファイルをバージョン管理するためには、まずそのファイルをバージョン管理の対象として追加するコマンドを実行し、そのあとコミットすることで、その時のファイルを保存することができる。
コミットを取り消すコマンドを実行すると、そのコミットでのファイルの変更内容が取り消される。

バージョン管理対象のファイルを作る

今回は、Pythonスクリプトバージョン管理を行う。
「hello.py」という名前のファイルを作成し、以下の内容を書き込む。

def main():
    print("Hello Git.")

main()

次に、以下のコマンドを実行する。

> git add hello.py    # hello.pyをバージョン管理の対象にする
> git commit -m "[Add] hello.py"    # コミットする
[master (root-commit) c46e5a6] [Add] hello.py
 1 file changed, 4 insertions(+)
 create mode 100644 hello.py

git addコマンドでは複数のファイルをバージョン管理の対象にすることもできる。
コミットする際は、必ずメッセージ付与し、そのコミットでどんな変更を行ったかを、記述する。

[参考]コミットするタイミング

コミットを行うタイミングについては、きりがいい時にすればよい。
例えば、1つの関数や機能を実装するたびにコミットするなど。
そのプロジェクトに対するタスク管理もしているなら、タスク単位でコミットをするとよい。

[参考]コミットメッセージの書き方

コミットに付与するメッセージは、できるだけ短く、何を変更したがわかる内容にするとよい。
以下のようなプレフィックス(prefix)をつけてメッセージを書くと、よりわかりやすくなる。

  • Add: 機能を追加したとき。
  • Update: 機能を変更したとき。
  • Fix: 機能を修正したとき。
  • Remove: 機能を削除したとき。

変更履歴を確認する

ファイルに変更を加える

先ほどのhello.pyを以下のように変更する。

def main():
    print("Hello Git.")
    print("I'm studying Git.")

main()

以前との差分を見る

ファイルを変更した際、前回のコミットとどこが変わったのかを調べたいときは、以下のコマンドを実行する。

> git diff
--- a/hello.py
+++ b/hello.py
@@ -1,4 +1,5 @@
 def main():
        print("Hello Git.")
+       print("I'm studying Git.")

 main()
\ No newline at end of file

前回のコミットとの差分が出力される。
変更内容をコミットしておく。

> git add hello.py
> git commit -m "[Update] 表示内容の変更"

変更履歴を確認する

> git log
commit 93ae93f9ecca88f4c439aec6f28b41a4829446c8 (HEAD -> master)
Author: hhyuga
Date:   Thu Aug 30 17:25:39 2018 +0900

    [Update] 表示内容の変更

commit c46e5a6c070a00b5aca7a9d410adf9d372b24db4
Author: hhyuga
Date:   Thu Aug 30 17:03:36 2018 +0900

    [Add] hello.py
> git reflog
93ae93f (HEAD -> master) HEAD@{0}: commit: [update] 表示内容の変更
c46e5a6 HEAD@{1}: commit (initial): [add] hello.py

ファイルの変更を戻す

先ほど変更したファイルを1つ前のコミットの状態に戻すコマンドはrevertresetの2つある。

  • revert: 指定したコミットの変更を打ち消すような変更をして、それを新たなコミットとする。
  • reset: 指定したコミットまでのすべての変更を取り消す。

「変更を元に戻した」という履歴が残るのは、revertの方なので、通常時はこちらを使う。
resetは誤ってコミットを発行してしまった場合などに使うとよい。

revertする

コマンドはgit revert <commit_id>だが、commit_idは先ほどのgit reflogで確認する。
ここでは、print("I'm studying Git.")を追加した変更を打ち消す。

> git revert 93ae93f
(エディタが開いてコミットメッセージを編集するよう促される。そのままでよければ「:q」と入力しエディタを閉じる)

ソースコードを確認すれば、先ほどの変更が元に戻っていることがわかる。

resetする

先ほどrevertしたコミットを取り消す。
revertの1つ前のコミットIDを指定すると、その状態までresetすることができる。

> git reset --hard 93ae93f
HEAD is now at e5b2b78 [update] 表示内容の変更
> git log

ファイルの内容がrevert前に戻り、変更履歴にはrevertしたコミットも残っていないのがわかる。

リモートリポジトリへプッシュする

リモートリポジトリの作成

Gitホスティングサービスで最も有名なのは、Githubであるが、非公開リポジトリの作成は有料なので、今回はBitbucketを使ってリモートリポジトリを作成する(公開してもよいのならGithubでもよい)。

Bitbucketにログインし、サイドメニューの「+」ボタンをクリックして、
f:id:hhyuga201515:20180830184207p:plain:w300

リポジトリを選択。
f:id:hhyuga201515:20180830184136p:plain:w300

リポジトリ名は、ここでは「HelloGit」としておく。他はデフォルトのまま、「リポジトリの作成」を選択。
f:id:hhyuga201515:20180830185030p:plain:w500

以下の画面が出てくるので、コマンドをコピペして実行。
f:id:hhyuga201515:20180830184914p:plain

git remote add origin https://<user_name>@bitbucket.org/<user_name>/hellogit.git    # リモートリポジトリを追加する
git push -u origin master    # 現在の変更をリモートリポジトリにプッシュ

リモートリポジトリを確認すると、変更内容が正しく反映されていることがわかる。 f:id:hhyuga201515:20180830185926p:plain

[参考]originとは

git remote add origin <url>コマンドでは、リモートリポジトリのURLのエイリアスとして、「origin」という名前を付けている。一般的にリモートリポジトリのエイリアスには「origin」が使われれるが、別の名前にしても問題はない。

GitのGUIクライアント(GitKraken)を使う

ここまでGitの操作はすべてコマンドで行っていたが、これをGUIで行うためのアプリケーションがいくつかある。
https://git-scm.com/download/gui/windows ここにいくつか紹介されているが、個人的には、GitKrakenが一番使いやすかった。ただし、少し重たい。
ここからDLできる。 www.gitkraken.com

GitKrakenでローカルリポジトリを開くと以下のように表示される。
f:id:hhyuga201515:20180830212706p:plain:w700

コミットの履歴やメッセージ等が表示される。
もちろん、コミットやリバート、プッシュ等の操作もできる。

ブランチで分ける

Gitにはブランチという概念がある。ブランチ(branch)は枝という意味の英単語で、Gitでは、ブランチを使うことによって、ソースコードの変更を切り分けることができる。
例えば、既に完成しているプログラムに新しく機能を追加する際、完成しているプログラムのブランチから新しくブランチを作成し、そこで機能の追加を行う。そうすることで、完成しているプログラムを書き変えることなく、機能の追加を行うことができる。

branch1の作成

GitKrakenのサイドメニューの「LOCAL」からmasterブランチを右クリックし、「Create branch here」を選択
masterブランチとは、最初のコミットの際にデフォルトで作成されるブランチです。
f:id:hhyuga201515:20180830222303p:plain

ブランチ名を「branch1」とする。
f:id:hhyuga201515:20180830222430p:plain

hello.pyを以下のように書き換え、コミットする。

def main():
    print("Hello Git.")
    print("I'm studying Git.")
    branch1()

def branch1():
    print("This is branch1.")

main()

branch2の作成

再度masterブランチを右クリックし、同様にしてbranch2を作成する。 hello.pyを確認すると、branch1の変更前に戻っていることがわかる。 これは、masterブランチには、まだbranch1の変更を反映していない状態で、branch2を作成したからである。

hello.pyを以下のように書き換え、コミットする。

def main():
    print("Hello Git.")
    print("I'm studying Git.")
    branch2()

def branch2():
    print("This is branch2.")

main()

マージする

masterブランチにbranch1、branch2の変更を適用することを「マージ(merge)」という。mergeは、「併合する」、「溶け合わせる」という意味の英単語である。
まずは、「LOCAL」のmasterブランチをダブルクリックする。
ちなみに、このようにブランチを移動することを「チェットアウト」という。
これで、ソースコードを確認すると、ブランチ作成前の状態に戻っていることがわかる。

まず、branch1を右クリックし、「Merge branch1 into master」を選択する。
f:id:hhyuga201515:20180830230308p:plain

すると、branch1の変更が、masterブランチへ反映される。
マージした際には自動でコミットが発行される。

次に、同様にしてbranch2を右クリックし、「Merge branch2 into master」を選択する。
すると、右側に「Merge Failed」と表示される。
f:id:hhyuga201515:20180830230506p:plain
これは、変更が同じファイル内で重複することで起こる。これを「コンフリクト(conflict)」という。conflictは、「争い」、「衝突」という意味の英単語である。
ソースコードを見てみると、以下のようになっている。

def main():
    print("Hello Git.")
    print("I'm studying Git.")
<<<<<<< HEAD
    branch1()

def branch1():
    print("This is branch1.")
=======
    branch2()

def branch2():
    print("This is branch2.")
>>>>>>> branch2

main()

上の内容が現在の変更で、下の内容がマージしようとした変更である。この2つの変更が重複しているため、マージする際にエラーが出た。
そこで手動で変更内容を以下のように修正する。

def main():
    print("Hello Git.")
    print("I'm studying Git.")
    branch1()
    branch2()

def branch1():
    print("This is branch1.")

def branch2():
    print("This is branch2.")

main()

手動でマージできたら、その変更内容をコミットする。
これで、branch1とbranch2の変更を取り込むことができた。

[参考]GitFlow

ブランチの運用方法として、GitFlowというブランチモデルがある。
アプリケーション開発などにGitを利用する際、以下のような役割を持ったブランチを用意し、運用することで、開発の効率と、アプリケーションの動作の安定性を保つ。

  • develop
    開発用ブランチ。新たに機能を追加する際は、ここから新しいブランチを作る。

  • feature
    機能追加のためのブランチ。developをベースとしてブランチを作成し、機能を追加したら、ブランチをdevelopにマージして閉じる。

  • release
    リリース準備用のブランチ。リリースのための作業をするブランチ。
    developブランチをベースに作成し、作業が終わったら、masterブランチにマージして閉じる。

  • master
    リリースするためのブランチ。このブランチでは、必ずプログラムが正しく動作するようにしておく。

  • hotfix
    masterブランチにバグなどの、早急に対応が必要な場合にこのブランチを作成する。
    masterブランチをベースに作成し、作業が終わればmasterブランチと、developブランチにマージして閉じる。

GitKrakenには、GitFlowをでブランチを運用するための機能がある。
また、これの簡易版として、GithubFlowというモデルもある。

C/C++開発環境がWSL上にあり、エディットをGUI(VSCode)で行う方法

概要

WindowsユーザがLinux環境でC/C++開発したいとき、
以前は仮想マシンを立ち上げてそのうえでLinuxを動かすことが多かったが、
最近はWindows Subsystem for Linux(WSL)上にUbuntu等をインストールしてLinux環境を整えることができるようになった。
このとき、エディタはVim等のCUIではなく、VSCodeなどのGUIで開発したいときは、主に2通りの手段がある。

Windows上にX Serverを、WSLにはX Clientをインストールして、Windows上にVSCodeのウィンドウを表示させて開発。
Windows上からWSL上のファイルを直接エディットする。

本記事では②の方法のやり方を述べる。
もちろん、補完機能などもちゃんと動作するようにする。

実行環境

OS: Windows 10
VSCode Ver: 1.24.1
C/C++ for Visual Studio Code Ver: 0.17.5

必要なソフトウェアのインストール

VSCodeのインストール

C/C++拡張機能をインストール

ワーキングディレクトリを開く

エディットしたいファイルがWSL上にある場合

WSL上のファイルは、

C:\Users\%USERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs

の中にある。
もしかしたら「_79rhkp1fndgsc」の部分が環境によって異なるかもしれないが、読み替えてほしい。
エディットしたいファイルがあるディレクトリにたどり着いたら、そのフォルダをWindows上のVSCodeで開く。

エディットしたいファイルがWindows上にある場合

エディットしたいファイルがあるフォルダをそのままWindows上のVSCodeで開く。

C/C++拡張機能の設定を変更

ここを参考に設定ファイルを書き換える。
設定ファイルは、Ctrl + Shift + Pでコマンドパレットを開き、「C/Cpp: Edit Configurations...」を選択することで編集できる。

{
    "configurations": [
        {
            "name": "WSL",
            "intelliSenseMode": "clang-x64",
            "compilerPath": "/usr/bin/gcc",
            "includePath": [
                "${workspaceFolder}",
                "/usr/local/include",
                "/usr/include"
            ],
            "defines": [],
            "browse": {
                "path": [
                    "${workspaceFolder}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            },
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ],
    "version": 4
}

右下にこのマークが出るはずなのでしばらく待つ。5分経っても変化がない場合は、VSCodeを再起動してみる。
f:id:hhyuga201515:20180630091105p:plain

確認

ちゃんとWSL上のインクルードファイルを参照していることがわかる。 f:id:hhyuga201515:20180630092957p:plain f:id:hhyuga201515:20180630092912p:plain

コンパイル

Windows上でターミナルを開いて、

$ bash
または
$ ubuntu -c bash

でWSLのコマンドラインを開き、gcc/g++等使ってWSL上でエディットしたファイルをコンパイルし、実行すればよい。

matplotlibのインストール時にエラーが出る

問題

pythonではパッケージ管理システムであるpipを使うことで、いろんなライブラリが使えるようになります。
matplotlibは、pythonを使ってグラフ描画ができるライブラリですが、自分の環境ではエラーでインストールができませんでした。

環境

OS: Windows 10
Python ver: Python 3.6.1

問題のコマンド

pip install matplotlib

実行結果
f:id:hhyuga201515:20180422084311p:plain

エラー内容

PermissionError: [WinError 5] アクセスが拒否されました。: 'c:\\program files\\python36\\Lib\\site-packages\\numpy'

ということで、numpyをインストールするときは管理者権限が必要なようです。

解決方法

PowerShellを管理者権限で起動して、再度同じコマンドを実行してみると、、、 f:id:hhyuga201515:20180422084316p:plain
無事にインストールできました。