20201011のGitに関する記事は10件です。

Gitログを整形してファイル名をcsv形式で取得する

目的

gitのコミット情報をcsv形式で取得したかった。
git logの--pretty=formatのオプションでは、私が欲しかったフォーマットで取得できなかったため、 一度ログを出力した上でログの整形を行うようにした。

環境

OS Mac Catalina
Pycharm CE
python 3.7

準備

gitログの取得

GitBashなどのコンソールで叩くとログファイルが出力されます.
git --no-pager log --name-status --no-merges --all \
--date-order --date=format:'%Y/%m/%d %H:%M:%S' > git.log

取り込む想定のgitログ
git.log
commit f36da445d06d2db7b4f08a508be835f5464ded06
Author: nomori<hoge@example.com>
Date:   2020/10/10 23:50:29
    first commit.
A   .gitignore
A   perse_git_log.py

環境設定ファイル

ConfigParserを使用している。
一旦、デフォルトの区切り文字のみ設定しておく。

settings.ini
[DEFAULT]
COMMIT_ID = commit
STATUS_ADD = A
STATUS_MOD = M
STATUS_DEL = D
GIT_AUTHOR = Author:
GIT_DATE = Date:

実装

perse_git_log.py
import re
import csv
import os
import configparser

# 環境ファイルの読み込み.
ini_file = configparser.ConfigParser()
ini_file.read('./config/settings.ini', 'UTF-8')

env = 'DEFAULT'
COMMIT_ID = ini_file.get(env, 'COMMIT_ID')
STATUS_ADD = ini_file.get(env, 'STATUS_ADD')
STATUS_MOD = ini_file.get(env, 'STATUS_MOD')
STATUS_DEL = ini_file.get(env, 'STATUS_DEL')
GIT_AUTHOR = ini_file.get(env, 'GIT_AUTHOR')
GIT_DATE = ini_file.get(env, 'GIT_DATE')

# 処理対象のログファイルのパス.
path = './input/git.log'

# gitのlogファイルを読み込む.
array_commit_info = []
with open(path) as git_log_file:
    data = git_log_file.readlines()

for item in data:
    # 末尾の改行コードを削除.
    item = item.replace('\n', '')

    if COMMIT_ID in item:
        # コミットのハッシュIDを取得.
        commit_id = re.sub('.*: ', '', item)

    elif GIT_AUTHOR in item:
        # コミットしたユーザー情報を取得.
        author_tmp = item.replace(GIT_AUTHOR, '')
        # メールアドレス部分を削除.
        author = re.sub(' +<.*>', '', author_tmp)

    elif GIT_DATE in item:
        # コミット日時を取得.
        date = re.sub('.*: ', '', item)

    else:
        # ファイルの変更履歴を取得.
        if STATUS_ADD in item or STATUS_MOD in item or STATUS_DEL in item:
            # Gitのステータスを除いたファイル名の取得.
            file_name = re.sub('.*: ', '', item)
            # 出力用の配列に情報を保持.
            array_commit_info.append([commit_id, author, date, file_name])

# 出力先が存在しない場合は作成する.
file_path = './output/'
if not os.path.exists(file_path):
    os.mkdir(file_path)

# CSV形式で出力.
output_filename = file_path + 'git_output.csv'
with open(output_filename, 'w') as f:
    writer = csv.writer(f)

    # ヘッダ情報を出力.
    writer.writerow(['COMMIT_ID', 'AUTHOR', 'DATE', 'COMMIT_FILE_NAME'])
    for line_data in array_commit_info:
        # コミット情報を出力.
        writer.writerow(line_data)

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gitログを整形して、コミットしたファイル名をcsv形式で取得する

目的

gitのコミット情報をcsv形式で取得したかったが
git logの--pretty=formatのオプションでは、私が欲しかったフォーマットで取得できなかったため、 一度ログを出力した上でログの整形を行うようにした。

環境

OS Mac Catalina
Pycharm CE
python 3.7

準備

gitログの取得

GitBashなどのコンソールで叩くとログファイルが出力される。
git --no-pager log --name-status --no-merges --all \
--date-order --date=format:'%Y/%m/%d %H:%M:%S' > git.log

取り込む想定のgitログ
git.log
commit f36da445d06d2db7b4f08a508be835f5464ded
Author: nomori<hoge@example.com>
Date:   2020/10/10 23:50:29
    first commit.
A   .gitignore
A   perse_git_log.py

実装

perse_git_log.py
import re
import csv
import os

COMMIT_ID = 'commit '
STATUS_ADD = 'A '
STATUS_MOD = 'M '
STATUS_DEL = 'D '
GIT_AUTHOR = 'Author: '
GIT_DATE = 'Date:   '

path = './input/git.log'

# gitのlogファイルを読み込む.
array_commit_info = []
with open(path) as git_log_file:
    data = git_log_file.readlines()

for item in data:
    # 末尾の改行コードを削除.
    item = item.replace('\n', '')

    if COMMIT_ID in item:
        # コミットのハッシュIDを取得.
        commit_id = item.replace(COMMIT_ID, '')

    elif GIT_AUTHOR in item:
        # コミットしたユーザー情報を取得.
        author_tmp = item.replace(GIT_AUTHOR, '')
        # メールアドレス部分を削除.
        author = re.sub(' +<.*>', '', author_tmp)

    elif GIT_DATE in item:
        # コミット日時を取得.
        date = item.replace(GIT_DATE, '')

    else:
        # ファイルの変更履歴を取得.
        file_status = item[0:2]
        if file_status == STATUS_ADD or file_status == STATUS_MOD or file_status == STATUS_DEL:
            # Gitのステータスを除いたファイル名の取得.
            file_name = item[2:]
            # 出力用の配列に情報を保持.
            array_commit_info.append([commit_id, author, date, file_name])

print(array_commit_info)

# CSV形式で出力.
file_path = './output/'
if not os.path.exists(file_path):
    os.mkdir(file_path)

output_filename = file_path + 'git_output.csv'
with open(output_filename, 'w') as f:
    writer = csv.writer(f)

    # ヘッダ情報を出力.
    writer.writerow(['COMMIT_ID', 'AUTHOR', 'DATE', 'COMMIT_FILE_NAME'])
    for line_data in array_commit_info:
        # コミット情報を出力.
        writer.writerow(line_data)

出力例

git_output.csv
f36da445d06d2db7b4f08a508be835f5464ded,nomori,2020/10/10 23:50:29,.gitignore
f36da445d06d2db7b4f08a508be835f5464ded,nomori,2020/10/10 23:50:29,perse_git_log.py

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

git revert を git revertした

git revert とは

一言で言えば「既存のコミットを取り消す」コマンドです。

似たコマンドでgit resetがありますが、
・git reset: そのまま過去に戻す
・git revert: 「コミットを打ち消したよ」というコミットを新たに追加して、状況を戻す
という違いがあります。

両方とも、できればあまり使いたくないですね。

revertをrevertの経緯

では、なんでrevertをrevertしたのか、ですが、

最新コミットが不要だったので、revertした
やっぱりそのコミットは必要だった
revertしたことをrevertしたい

という経緯です。

一から書き直してもいいですが、
やっぱりまるまる一気に元に戻したい。。。

revertをrevertする

それでは実際にどんな感じだったか、可能な範囲で晒していきます。

※ ブランチ名を仮にfix_user_imagesとします。

1、最初のrevert

# "git revert [コミット番号]"で、そのコミットを無かったことにする
$ git revert fb286b771

[fix_user_images 2c93f2815] Revert "画像サイズ修正"
 3 files changed, 1 insertion(+), 8 deletions(-)
 create mode 100644 〜〜/〜〜

2、revertをrevert

1でなくなくrevertしたあとに、同じブランチで既に新たな開発を始めていたので、
その開発内容はサラにします(泣

# ログ確認
$ git log --oneline

2829851e0 (HEAD -> fix_user_images) Revert "画像サイズ修正"
2c93f2815 Revert "ユーザー画像追加"
7b1b3b230 (origin/fix_user_images) Merge branch 'develop' of gitlab.〜〜〜:〜〜〜 into fix_user_images
...


# 最新コミットに戻す
$ git reset --hard HEAD

HEAD is now at 2829851e0 Revert "画像サイズ修正"


# revertして作られたコミット「"Revert "画像サイズ修正"」をrevert
$ git revert 2c93f2815

Removing 〜〜/〜〜
[fix_user_images 619bf7743] Revert "Revert "画像サイズ修正""
 3 files changed, 8 insertions(+), 1 deletion(-)
 delete mode 100644 〜〜/〜〜

3、無事反映を確認

$ git log --oneline

619bf7743 (HEAD -> fix_user_images ) Revert "Revert "画像サイズ修正""
2c93f2815 Revert "画像サイズ修正"
7b1b3b230 (origin/fix_user_images) Merge branch 'develop' of gitlab.〜〜〜:〜〜〜 into fix_user_images
fb286b771 画像サイズ修正
...

終わりに

・git revert
・git reset
・git rebase
は「3大叩いてはいけないgitコマンド」としてインプットしていましたが、
実際はまだまだこんなもんじゃないんだろうなと思います。

今後頻繁に叩く必要が出ないことを祈ります。。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iterm を格好良くした

itermの画面

terminal.png

やったこと

  • itermのテーマをjapanesequeにした
  • 背景を半透明にした
  • 「コンピュータ名:」を緑色にした(詳細は後述)
    • 全部白いままだとコマンドをどこで打ったのかわかりづらいので。
    • 黒地に緑が個人的に格好良いと思うので
  • ステータスバーでgitとファイルパスをつけた。

「コンピュータ名:」を緑色にする方法

Preferences > Profile > Advanced > Triggers edit で以下のように設定する。
これで文頭からkubotaaで始まる場合のみ色がつく。
Macのシステムを操作して色をつける方法もあるみたいだが、これはitermの機能を使った。
iterm_color.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

peco を使ってブランチのチェックアウトを行う (リモートブランチ と ローカルブランチ)

peco を使ってブランチのチェックアウトを行う (リモートブランチ と ローカルブランチ)

https://qiita.com/m-tmatma/items/6bb6b7c8a515a5424843 の改良版。

gist

https://gist.github.com/m-tmatma/05b9573ad64ef67eb3662d62bb6d0a20

リモートブランチ

スクリプト

coremote () {
    remotename=`echo $1 | sed -r "s#([^/]+)/.*#\1#"`
    branchname=`echo $1 | sed -r "s#[^/]+/##"`

    git branch | grep "..$branchname$"
    if [ $? = 0 ]; then
         git checkout    $branchname
    else
         git checkout -b $branchname $remotename/$branchname
    fi
}
alias cor='export -f coremote; coremote $(git branch -r | grep -v "/HEAD" | peco)'

改善ポイント

  • リモートブランチに対応するローカルブランチが存在したら、新たにブランチは作らずに既存ブランチをチェックアウトする。
  • origin/HEAD の行を除外する。
  • xargs をやめて $(コマンド) にした

初版は以下のようにしていた。

alias cor='export -f coremote; git branch -r | grep -v "/HEAD" | peco | xargs -I{} bash -c "coremote {}"'

使い方

$ cor

上下キーあるいは検索文字列を入力してチェックアウトしたいリモートブランチを指定する。
もしローカルに同一名のブランチが存在したらそのローカルブランチをチェックアウトする。
もしローカルに同一名のブランチが存在しなかったリモートブランチを同一名のローカルブランチを作成してチェックアウトする。

ローカルブランチ

スクリプト

colocal () {
    branchname=`echo $1 | sed -r "s#^../##"`
    git checkout    $branchname
}
alias col='export -f colocal; colocal $(git branch | peco)'

改善ポイント

  • xargs をやめて $(コマンド) にした

初版は以下のようにしていた。

alias col='export -f colocal; git branch | peco | xargs -I{} bash -c "colocal {}"'

使い方

$ col

上下キーあるいは検索文字列を入力してチェックアウトしたいローカルブランチを指定する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[初心者向け]GitHubを使った個人的検索方法(サンプルコードを見つける場合)

はじめに

私は、文系未経験のプログラミング初心者です。5月後半に始めたので今で大体5ヶ月弱が経ちました。
今個人アプリを開発していますが、その際に使っている検索方法をご紹介したいと思います。なぜこれを紹介したいと思ったかというと、初心者とGitHubにはそれなりに敷居の高さがある一方で、GitHubはバージョン管理以外でも有用で初心者の助けになることも多いと感じたからです。
初心者の方々だと、私ほどではないと思いますが詰まることもそれなりにあると思いますので、その検索に少しでも役立てていただいたら幸いです。尚、エラー解決がメインの使い方というわけではなく、公式ドキュメント等を見て「これってどんな書き方をすればいいんだろう?」とか疑問が湧いた時に使える方法です。

検索方法

手順はざっくりいうとこんな感じです。

1. 調べたいことがあった際に、その調べたいもの関連の特有のコードを見つける
2. その調べたいコードをGitHubの検索ボックスに入れて入力する
3. 必要であれば、調べる際にその特有のコードに関連する使用言語、特有のファイル名を用いて検索をする
4. 見つかった検索結果から、自分の探したいものに近そうな物を発見したら、そのレポジトリを漁ってみる

順を追って説明していきます。

1.特有のコードを見つける

プログラミングでは、各言語・フレームワーク・モジュールによって特有のコードが存在します。特有のコードが故に検索で引っかかりやすいというのを今回は利用します。
何か調べ物をする際、通常行うことは公式ドキュメントを見て、当該記事の説明を読むことでしょう。しかし、時に、特に初心者の方にとって、ドキュメントを見てもいまいち具体的なコードの書き方が分からないという様な事例があるかと思います(これが私だけだったら焼き土下座でもなんでもします)。
実例を交えて説明してみます。私が、Djangodjango-allauthusernameのValidationをしたいとします。そこで、公式ドキュメントで以下の様な記述を見つけました。

ACCOUNT_USERNAME_VALIDATORS (=None)
A path ('some.module.validators.custom_username_validators') to a list of custom username validators. If left unset, the validators setup within the user model username field are used.
Example:

# In validators.py

from django.contrib.auth.validators import ASCIIUsernameValidator

custom_username_validators = [ASCIIUsernameValidator()]

# In settings.py

ACCOUNT_USERNAME_VALIDATORS = 'some.module.validators.custom_username_validators'

いまいち何を書けば想像がつかなかったとします。そこで、この説明の中の特有のコード使って調べ物をします。今回はACCOUNT_USERNAME_VALIDATORSをターゲットとして調べたいと思います。

2 GitHubで検索する

2は非常にシンプルです。
Screen Shot 2020-10-10 at 20.58.14.png
GitHubの左上の方に検索ボックスがあります。そこに先ほどターゲットにした特有のコードをコピペするだけです。一つ注意するとするなら、検索対象をAll GitHubにしておくということだけでしょうか。

3 言語、ファイル名を指定して検索する

検索結果が表示されたら、左のボックスのCodeという項目を選択してみてください(エラー修正の場合ここでIssuesの方をみてもいいかもしれません)。
Screen Shot 2020-10-10 at 21.27.01.png
この時点である程度は絞り込めているとは思いますが、まだ候補が多い場合も十二分にあります。そこでもう少し調べたいものに近づけるためにAdvanced Searchを使います(このボックスのあるページ左側の最下部にあります)。
オプションはいろいろありますが、今回は私がよく使っている(タイトル通りの)言語とファイル名を使った検索方法を紹介します。

言語でのフィルター

まず、言語でフィルターをかけていきます。
Screen Shot 2020-10-10 at 21.30.57.png
Advanced optionsの一番下のWritten in this languageを使います。ここで、特有のコードが書かれている言語を指定します。今回の私の事例ですと、Pythonを選択するといった感じです。

ファイル名でのフィルター

続いては特有のコードが書かれているであろうファイル名を使って検索を行います。プログラミングでは、慣例的なファイル名が使われる事例が多々あります。[1]の特有のコードの時点でも充分絞り込めているとは思いますが、特有のコードが慣例的名前のファイルに書き込まれている場合、検索の精度は上がると思われます。

Screen Shot 2020-10-10 at 21.31.12.png

Code optionsの一番下、With this file nameという項目を使います。私の例の場合、ACCOUNT_USERNAME_VALIDATORSが書かれているのは、settings.pyという名前を入力すればよいことになります。

以上言語とファイル名でフィルターをかけた上でもう一度検索をしてみます。

4.検索結果内のレポジトリを調べてみる

検索した結果、探したいものはある程度調べられました。[1]で選んだコードが調べたい部分の直接のコードではない場合も多々あるでしょう。私の例の場合だと、ACCOUNT_USERNAME_VALIDATORSは特有のコードではあるけど、実装したいものそのものを表現しているコードではないという様な感じです(私の例だとvalidators.pyにありそうですね)。

そんな時は、検索結果で表示されたレポジトリを漁ってみましょう。ここまで絞ってヒットしたものなので、その機能が実装されている可能性が高いでしょう。プラスの方法として、更新された順とかで順番を変更してみるのも場合によっては有効です。

まとめ

以上が、私が使っている検索法です。初心者のうちはドキュメントを見てもちんぷんかんぷんになる場合は往々にありますし、なかなかにそれはストレスがたまります。この記事がそのストレスを軽減したり、エンジニアに重要な検索力の向上に役立てば幸いです。
GitHubを使った他の検索法や、GitHub以外でもおすすめの検索方法があれば、コメントで教えていただきたいです。

拙い文章ではございますが、ご覧いただき誠にありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Git】logの見方

コミットの履歴を振り返ることは、Gitを使っていくうえで必要不可欠です。
今回は過去のコミット履歴を振り返られる、git log コマンドについて解説します。

基本の使い方

単純な使い方はこれだけ。

git log

コマンドを実行すると、このような表示になります。

commit a2bb8f80c3048714c677fe15d716bfa227b14a01 (HEAD -> master, origin/master)
Author: user <user@gmail.com>
Date:   Sat May 16 10:00:00 2020 +0900

    commit message

commit xxxx....

そのリポジトリの新しいコミットから順に、コミットのSHA値、コミット者、コミット日次、メッセージが表示されます。
そのコミットを指しているブランチがあれば、そのブランチ名も表示してくれます。

オプションまとめ

git log には多くのオプションがあります。欲しい情報に応じてオプションを使い分けられると、より一層便利に感じられます。

コミット時の変更内容を知りたい

git log -p
commit a2bb8f80c3048714c677fe15d716bfa227b14a01 (HEAD -> master, origin/master)
Author: user <user@gmail.com>
Date:   Sat May 16 10:00:00 2020 +0900

    commit message

diff --git a/change.txt b/change.txt
index 481ade4..d90ab66 100644
--- a/change.txt
+++ b/change.txt
@@ -0,0 +0,0 @@ 
-    消された文字
+    足された文字

そのコミットの変更内容をdiffのように出力してくれます。

変更があったファイルの一覧が見たい

git log --stat
commit a2bb8f80c3048714c677fe15d716bfa227b14a01 (HEAD -> master, origin/master)
Author: user <user@gmail.com>
Date:   Sat May 16 10:00:00 2020 +0900

    commit message

change.txt                                      |   2 +-
add.txt                                         |   3 ++
delete.txt                                      |   3 --
3 files changed, 4 insertions(+), 4 deletions(-)

そのコミットで変更のあったファイルとその行数を一覧表示します。
個人的によく使うオプションNo.1

ちなみに、shortstatというオプションを使うと、最後の集計の行(3 files changed,...)のみを出力してくれます。

git log --shortstat

またまたちなみに、下記のオプションを使うと、変更があったファイル名のみを一覧表示してくれます。

git log --name-only

上記の--statだと、表示のフォーマットが決まっている影響で、ファイルパスが長くなると先頭の方が省略されてしまうのです。
こちらのオプションだと、変更量は表示されない代わりに、必ずフルパスで表示してくれるので、用途によってはこちらのほうが便利な場合も。

表示フォーマットを変えたい

git log --pretty=<表示フォーマット>

表示フォーマットを自由に設定してログを表示させることができます。
表示フォーマットは、オプションを組み合わせて記載したり、すでに用意されているエイリアスを使用することもできます。
例えば、表示フォーマットにonelineを設定した場合は、

a2bb8f80c3048714c677fe15d716bfa227b14a01 (HEAD -> feature) update source
ab22eba9c7f7ce509295cd9eb53f6bc2e90fe5da add source
afdef3dcded8f4090cab13ee4c3f72b80db5a385 Initial commit

このように、1つのコミットを1行で表示することができます。

自由なフォーマットで表示させるのはこんな感じ。

git log --pretty=format:"%h [%an] %s"
a2bb8f8 [user] commit message

%hはコミットのハッシュ値(短縮版)、%anはコミットしたユーザの名前、%sはコミットメッセージを表します。
ほかにも使用できるオプションは多くあるので、お気に入りの表示になるようにいろいろ試してみてください!

樹形図を表示させたい

git log --oneline --graph
#   406045a Merge pull request #1 from feature
|\
| # 33ad750 (origin/feature, feature) update source
| # cb0e5e0 add source
|/
# 611aa41 Initial commit

コミット同士のつながりを示す樹形図をアスキーグラフで表現してくれます。
樹形図を表示させるのは--graphというオプションなのですが、--onelineと組み合わせて使ってあげないと、樹形図としてみるにはしんどいくらい縦長になってしまいます。

表示するログを絞り込みたい

条件によるログの絞り込みができます。
いろいろあるので、いくつか例をご紹介。

・表示件数を絞る

git log -3

この場合は3件だけ表示されます。

・期間で絞る

git log --since="2020/04/01" --until="2020/04/30"

・特定のファイルが更新されたログのみ

git log path/to/file.txt

・コミットしたユーザで絞る

git log --author="user"

・コミットメッセージからgrep

git log --grep="fix"

・マージコミットのみ表示

git log --merges

反対にマージコミットを非表示

git log --no-merges

様々なオプションを紹介しましたが、これらはすべて組み合わせて使えるものです。
組み合わせを試してみて、お気に入りのログ表示を見つけてみてください!





普通にログ見るだけならGitHubで十分だよな~。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

git のブランチ名を bash のコマンドプロンプトに表示する

git のブランチ名を bash のコマンドプロンプトに表示する

git のブランチ名を bash のコマンドプロンプトに表示する方法です。(Ubuntu 20.04.1 で確認しました)

設定方法

if [ -e /etc/bash_completion.d/git-prompt ]; then
    source /etc/bash_completion.d/git-prompt
    PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\] $(__git_ps1 " (%s)") \$ '
fi
  • /etc/bash_completion.d/git-promptsudo apt install -y git で git をインストールすると作成されます。
  • Ubuntu ではデフォルトで以下のように定義されているので、最後に $(__git_ps1 " (%s)") \$ を追加します。

変更前:
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$'

変更後:
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\] $(__git_ps1 " (%s)") \$

コメント

/etc/bash_completion.d/git-prompt の中身を確認すると以下のようになっています。

if [[ -e /usr/lib/git-core/git-sh-prompt ]]; then
    . /usr/lib/git-core/git-sh-prompt
fi

/usr/lib/git-core/git-sh-prompt の先頭にコメントがあります。
https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh でも参照できます。
(GPL のようです)

#    3a) Change your PS1 to call __git_ps1 as
#        command-substitution:
#        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#        ZSH:  setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
#        the optional argument will be used as format string.

https://github.com/git/git/blob/d4a392452e292ff924e79ec8458611c0f679d6d4/contrib/completion/git-prompt.sh#L13-L17

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Visual Studio CodeでGitを利用する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CI/CDをkatacodaで体験(初心者向け) - Part3

CI/CD入門

このぺーじでは、katacodaと呼ばれる「ブラウザから無料で勉強用のインスタンスを起動できるWebサービス」を利用してCI/CDを実践します
内容は上記リンクに沿うので、不明点があればそちらへどうぞ

Gitのバージョン管理について - scenario3

ここでは、CI/CDとして欠かせないGitによるバージョン管理について学習します
このシナリオで学習することをさっと確認する場合は概要を確認
理解に間違い等がございましたら、ぜひご指摘ください

概要

  • git remote <add/rm..etc>でリモートレジストリを登録、削除
  • git push <remote registry> <branch on remote registry>で現在のbranchをリモートレジストリのブランチに反映
  • git pullでローカルレジストリにリモートレジストリとの差分を反映。branchの指定可能
  • git pull=git fetch+git merge

Step 1 - Git Remote

git remote <add/rm..etc>で現在のローカルレジストリとリモートレジストリの関係を定義できる
まず、現在のローカルレジストリがリモートレジストリを定義していないことを確認

$ ls -a
.  ..  .git  staging.txt
$ cd .git/
$ ls -a
.   branches        config       HEAD   index  logs     refs
..  COMMIT_EDITMSG  description  hooks  info   objects
$ cat config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

続いて、リモートレジストリの登録

git remote add origin /s/remote-project/1   ///"s/remote-project/1"はGitHubのリモートレジストリ

このコマンドの実行前にいくつかの要件を満たす必要がある

  • GitHubにアカウントを持つ
  • リモートレジストリが存在している
  • リモートレジストリにアクセスできる
    • リモートレジストリの状態:public × https接続できるように設定されている
    • リモートレジストリの状態:private × ssh接続できるように設定されている
$ cd .git/
$ ls -a
.   branches        config       HEAD   index  logs     refs
..  COMMIT_EDITMSG  description  hooks  info   objects
$ cat config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = /s/remote-project/1
        fetch = +refs/heads/*:refs/remotes/origin/*

新しく[remote "origin"]という項目が作成されている
ちなみにリモートレポジトリは複数設定可能

$ git remote add testOrigin /test/test
$ cat config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = /s/remote-project/1
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "testOrigin"]
        url = /test/test
        fetch = +refs/heads/*:refs/remotes/testOrigin/*

Step 2 - Git Push

一般的な開発では、複数人がそれぞれの担当を持っており、担当箇所の作成および編集を行う。その後、全体のコードやファイルに変更を組み込みます。
そのため、個人が担当部分に修正を加えたファイルをローカルレポジトリに反映させた後、リモートレポジトリにも反映させる必要がある。
リモートレポジトリにローカルレポジトリの状態を反映させるコマンドは
git push <事前に設定したremoteレポジトリ> <branch>

補足 ~branchとは?~
Gitにはbranchと呼ばれる概念があります
branchには、主に、branchを「切る(追加する)」、「マージ」の操作があります
前者は、Gitのバージョン管理が行われているすべてのディレクトリに対して複製を作成
後者は、複製されたbranchの変更部分をmaster branchに反映させる
masterと呼ばれるbranchは自動生成され、今までの課題はこのmaster branch上で行っていた
使い方(メリット)

  • (ローカル)レポジトリを複数人で利用する場合、個々人の変更がお互いに作用しない
  • 編集内容に合わせて、branchを複製することでエラー処理の場合分けを容易にする
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 228 bytes | 228.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /s/remote-project/1
 * [new branch]      master -> master

Step 3 - Git Pull

Step 2では、ローカルレジストリの変更をリモートレジストリに反映させた
Step 3では、リモートレジストリの変更をローカルレジストリに反映させる
コマンドはこちらgit pull <remote registry> <branch>

$ git pull origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From /s/remote-project/1
 * branch            master     -> FETCH_HEAD
   cbc1f59..6d9ea7e  master     -> origin/master
Updating cbc1f59..6d9ea7e
Fast-forward
 new-file.txt | 1 +
 staging.txt  | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 new-file.txt

Step 4 - Git Log

Step 3にて、リモートレジストリの変更をローカルレジストリに反映させたので、変更箇所を確認
まずは、「誰が」、「いつ」、「どのような変更(コミット時のコメント)」を確認するため、git log

$ git log
ESC[33mcommit 6d9ea7e2001c3b962a947e7e7dfa6b3699766c09ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[
Author: Different User <DifferentUser@JoinScrapbook.com>   //「誰が」
Date:   Sat Oct 10 11:28:56 2020 +0000   //「いつ」

    Fix for Bug #1234   //「どのような変更(コミット時のコメント)」

ESC[33mcommit cbc1f598936938a50dd6d120c8271eaa707b3485ESC[m
Author: Katacoda Scenario <scenario@katacoda.com>   //私たちは、katacodaが用意したローカルレジストリにリモートでアクセスしている(なんだか不思議ですね(笑))
Date:   Sat Oct 10 11:28:38 2020 +0000

    Message

続いて、具体的にどのような変更が加えられたのかgit showで確認

$ git show
ESC[33mcommit 6d9ea7e2001c3b962a947e7e7dfa6b3699766c09ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[
Author: Different User <DifferentUser@JoinScrapbook.com>
Date:   Sat Oct 10 11:28:56 2020 +0000

    Fix for Bug #1234

ESC[1mdiff --git a/new-file.txt b/new-file.txtESC[m    //変更されたファイル
ESC[1mnew file mode 100644ESC[m
ESC[1mindex 0000000..96716fbESC[m
ESC[1m--- /dev/nullESC[m
ESC[1m+++ b/new-file.txtESC[m
ESC[36m@@ -0,0 +1 @@ESC[m
ESC[32m+ESC[mESC[32mNewESC[m   //変更されたコード
ESC[1mdiff --git a/staging.txt b/staging.txtESC[m   //変更されたファイル
ESC[1mindex c4eb839..b0f03f3 100644ESC[m
ESC[1m--- a/staging.txtESC[m
ESC[1m+++ b/staging.txtESC[m
ESC[36m@@ -1 +1,2 @@ESC[m
 Staging AreaESC[m
ESC[32m+ESC[mESC[32mSomething ChangedESC[m   //変更されたコード

git showの味方が分からないので、何が変わったのかこちらで確認

$ ls -a
.  ..  .git  staging.txt

~~~git pull~~~

$ ls -a
.  ..  .git  new-file.txt  staging.txt
$ cat staging.txt
Staging Area
Something Changed
$ cat new-file.txt
New

二つの結果から、以下の変更箇所がある
Newと記載されたnew-file.txtが新規作成
Something Changedstaging.txtに加筆

git showの結果の見方が分からん、、、、涙
誰か分かりやすく教えてください

Step 5 - Git Fetch

git pullに似ている機能としてgit fetchがあります
端的な違いはというと、git pull=git fetch+git mergeです

git pullの処理は、リモートレジストリとの差分をローカルレジストリの(master branchに)反映させる
git fetchの処理は、リモートレジストリとの差分をローカルレジストリの(origin/master branchに)反映させる
git mergeの処理は、ローカルレジストリのmaster branchorigin/master branch(※1)の差分を反映させる

※1
"remotes/origin/master"として説明されたりされなかったりする
違いをご存じの方、ご連絡を!!!

注意 ~git merge(pull)で頻発するエラー「コンフリクト」~
発生原因:元となる状態から分岐(ブランチの追加、リモートレポジトリからのpull等)で同一ファイルに対して、別々の変更を加える。その後、元となる状態にそれぞれが変更を反映させることで競合が発生

対応策:たくさんあるのでググりましょう(笑)

e.g.1)
1. 元となる状態を自分の状態に反映させる(リモートレジストリからpull、masterブランチからブランチ追加等)
2. 自分の変更箇所を追加する
3. 元となる状態にマージ(リモートレジストリにpush、masterブランチに追加したブランチをmerge)

こちらの方法は、自分で加えた変更を一度破棄する必要があるので、変更箇所が複雑な場合は、次の方法を試すといった方針が適当かと思われる

e.g.2)
1. 自分の状態をmasterブランチにマージ
2. 元となる状態をひとまずfetch
3. 自分の状態と元となる状態の比較
4. 自分の状態を残すために、ブランチ追加
5. (以下e.g.1と以下同じ流れ)

(remotes)/origin/master branchとは?
リモートレジストリとローカルレジストリの中間に存在するbranchのこと
リモートレジストリとローカルレジストリの差分を確認したいけど、反映はさせたくない時に利用
e.g) 同じファイルについて、異なる人が編集を加えている場合

$ git branch -a
* ESC[32mmasterESC[m
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 228 bytes | 228.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /s/remote-project/1
 * [new branch]      master -> master
$ git branch -a
* ESC[32mmasterESC[m
  ESC[31mremotes/origin/masterESC[m

上の結果から分かる通り、git push直後に(remotes)/origin/master branchが作成されている

$ git fetch origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From /s/remote-project/1
 * branch            master     -> FETCH_HEAD
   a5fb2d2..1f07849  master     -> origin/master
$ ls -a
.  ..  .git  staging.txt
$ git merge origin/master
Updating a5fb2d2..1f07849
Fast-forward
 new-file.txt | 1 +
 staging.txt  | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 new-file.txt
$ ls -a
.  ..  .git  new-file.txt  staging.txt
$ git branch -a
* ESC[32mmasterESC[m
  ESC[31mremotes/origin/masterESC[m

上の結果から分かる通り、git merge前後でnew-file.txtが同一ディレクトリに出現
この部分の操作では、同一branch上で操作しているので分かりにくいが、fetch直後にgit checkout (remotes)/origin/masterでbranchを変更するとnew-file.txtが存在していることが確認できる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む