※当サイトの記事には、広告・プロモーションが含まれます。

Gitのローカルのbare repositoryをgit diffし、変更の検知をシェルスクリプトで試す

gigazine.net

OpenAIのサム・アルトマンCEOが自身のXアカウントに「o2がGPQAで105%のスコアを達成したと聞いた」と2024年11月3日(日)に投稿しました。「o2」の正式名称は不明ですが、OpenAIが開発中の次世代AIモデルが驚異的な性能を備えている可能性が濃厚となっています。

OpenAIのCEOが「o2が博士号レベルのベンチマークで105%のスコアを達成」とSNSに投稿、次期AIモデルはGPT-4oでも53.6%しか記録できなかった高難度テストで約2倍のスコアを達成か - GIGAZINE

GPQAはAIの性能を測定するベンチマークの1種で、生物学・物理学・化学の専門家が作成した448問の選択問題で構成されています。GPQAの問題はかなりの高難度で、「専門家でない人間」がGoogle検索を駆使して挑んだ場合は34%、「博士号保持者または博士号の取得を目指す学生」の場合も65%のスコアしか獲得できません。

OpenAIのCEOが「o2が博士号レベルのベンチマークで105%のスコアを達成」とSNSに投稿、次期AIモデルはGPT-4oでも53.6%しか記録できなかった高難度テストで約2倍のスコアを達成か - GIGAZINE

⇧ う~ん...

目指して欲しい方向が異なる気がするんよね...

選択問題のような事前に回答が明確な問題に対してではなく、回答が分かっていないような問題に対して、

  1. 回答に至った根拠
  2. 回答に参考にした一次情報

を明確にしていないのであるなら、「幻覚(ハルシネーション)」による虚偽が行われている可能性があるのであって、そのあたりを解決して欲しいんよね...

実業務におけるAIの利用で求めらているのは、そういうことな気がしますけど...

学術研究の域から出ていないんよね...

所謂、「概念実証(PoC:Proof of Concept)」を永久に続けている感じで、リリースのレベルになってはいないけど、リリースしてしまっている感じかな...

結局のところ、妥協点を決めるしかないわけだとは思うのだけど...

Gitのローカルのbare repositoryをgit diffし、変更の検知をシェルスクリプトで試す

本ブログで何回か話に出てきている

github.com

⇧「Oxidized」というRuby製のライブラリに触れる機会があり、「Oxidized」の内部で「Rugged」というライブラリが利用されている関係上、「Output」で「Git」を選択している場合、「Git」のローカルの「bare repository」が作成されますと。

で、「Oxidized」が、

  1. 「対象機器」の「設定情報」の取得に成功
  2. 「対象機器」の「設定情報」の取得に失敗

どちらの状態になっているのかを確認したいとした場合に、本当であれば、

  • 最新のファイル
  • 1つ前のファイル

の比較のようなことをしたいのだけど、「Git」の「bare repository」はファイルシステム上にファイルという形でデータを保持せず、「Git」の「bare repository」上の「object」という形で保存してしまっているので、通常の「シェル」に用意されているコマンドでのファイルの比較ができませんと。

一応、

github.com

https://github.com/ytti/oxidized/blob/master/lib/oxidized/worker.rb

module Oxidized
  require 'oxidized/job'
  require 'oxidized/jobs'
  class Worker
    def initialize(nodes)
      @jobs_done  = 0
      @nodes      = nodes
      @jobs       = Jobs.new(Oxidized.config.threads, Oxidized.config.use_max_threads, Oxidized.config.interval, @nodes)
      @nodes.jobs = @jobs
      Thread.abort_on_exception = true
    end

    def work
      ended = []
      @jobs.delete_if { |job| ended << job unless job.alive? }
      ended.each      { |job| process job }
      @jobs.work

      while @jobs.size < @jobs.want
        Oxidized.logger.debug "lib/oxidized/worker.rb: Jobs running: #{@jobs.size} of #{@jobs.want} - ended: #{@jobs_done} of #{@nodes.size}"
        # ask for next node in queue non destructive way
        nextnode = @nodes.first
        unless nextnode.last.nil?
          # Set unobtainable value for 'last' if interval checking is disabled
          last = Oxidized.config.interval.zero? ? Time.now.utc + 10 : nextnode.last.end
          break if last + Oxidized.config.interval > Time.now.utc
        end
        # shift nodes and get the next node
        node = @nodes.get
        node.running? ? next : node.running = true

        @jobs.push Job.new node
        Oxidized.logger.debug "lib/oxidized/worker.rb: Added #{node.group}/#{node.name} to the job queue"
      end

      if cycle_finished?
        run_done_hook
        exit 0 if Oxidized.config.run_once
      end
      Oxidized.logger.debug("lib/oxidized/worker.rb: #{@jobs.size} jobs running in parallel") unless @jobs.empty?
    end

    def process(job)
      node = job.node
      node.last = job
      node.stats.add job
      @jobs.duration job.time
      node.running = false
      if job.status == :success
        process_success node, job
      else
        process_failure node, job
      end
    rescue NodeNotFound
      Oxidized.logger.warn "#{node.group}/#{node.name} not found, removed while collecting?"
    end

    def reload
      @nodes.load
    end

    private

    def process_success(node, job)
      @jobs_done += 1 # needed for :nodes_done hook
      Oxidized.hooks.handle :node_success, node: node,
                                           job:  job
      msg = "update #{node.group}/#{node.name}"
      msg += " from #{node.from}" if node.from
      msg += " with message '#{node.msg}'" if node.msg
      output = node.output.new
      if output.store node.name, job.config,
                      msg: msg, email: node.email, user: node.user, group: node.group
        node.modified
        Oxidized.logger.info "Configuration updated for #{node.group}/#{node.name}"
        Oxidized.hooks.handle :post_store, node:      node,
                                           job:       job,
                                           commitref: output.commitref
      end
      node.reset
    end

    def process_failure(node, job)
      msg = "#{node.group}/#{node.name} status #{job.status}"
      if node.retry < Oxidized.config.retries
        node.retry += 1
        msg += ", retry attempt #{node.retry}"
        @nodes.next node.name
      else
        # Only increment the @jobs_done when we give up retries for a node (or success).
        # As it would otherwise cause @jobs_done to be incremented with generic retries.
        # This would cause :nodes_done hook to desync from running at the end of the nodelist and
        # be fired when the @jobs_done > @nodes.count (could be mid-cycle on the next cycle).
        @jobs_done += 1
        msg += ", retries exhausted, giving up"
        node.retry = 0
        Oxidized.hooks.handle :node_fail, node: node,
                                          job:  job
      end
      Oxidized.logger.warn msg
    end

    def cycle_finished?
      if @jobs_done > @nodes.count
        true
      else
        @jobs_done.positive? && (@jobs_done % @nodes.count).zero?
      end
    end

    def run_done_hook
      Oxidized.logger.debug "lib/oxidized/worker.rb: Running :nodes_done hook"
      Oxidized.hooks.handle :nodes_done
    rescue StandardError => e
      # swallow the hook erros and continue as normal
      Oxidized.logger.error "lib/oxidized/worker.rb: #{e.message}"
    ensure
      @jobs_done = 0
    end
  end
end    

⇧ 成功した場合は、ログを出力してくれるようにはなっているのだけど、何をもって成功と判定されるのかが、jobのステータスで判断されるっぽいのだけど、jobのステータスがどういう条件で設定されるのかがハッキリしませんと。

失敗した場合も、ログ出力されるようなのだけど、jobのステータスがどういう条件で設定されるかは成功の時と同じく分からないんよね...

話が脱線しましたが、通常の「シェル」のコマンドでファイルの比較ができない話に戻ると、どういうことかというと、Wikipediaによりますと、

Data Structure

The object store contains five types of objects:

  • blob is the content of a file. Blobs have no proper file name, time stamps, or other metadata (a blob's name internally is a hash of its content). In Git, each blob is a version of a file, in which is the file's data.

https://en.wikipedia.org/wiki/Git

Some data flows and storage levels in the Git revision control system

https://en.wikipedia.org/wiki/Git

⇧ とありますと。

で、「Git」のリポジトリの構成については、

www.omnibuscode.com

⇧ 上記サイト様にありますように、何種類か用意されており、「git clone」の際のオプションによって異なりますと。

で、一般的に、「GitHub」のリモートリポジトリから「git clone」する時って、オプションとか何も付けずに行う感じになると思うので、上記サイト様の図で言うところの「normal」の構成になっているのが普通ですと。

対して、「bare repository」は「working tree」にあたる部分がないので、

No Gitのリポジトリのタイプ working tree GIT DIR
1 normal あり あり
2 bare なし あり

⇧ のような違いがありますと。

ちなみに、

git-scm.com

⇧「Git」には、環境変数「GIT_DIR」というものが存在するらしく、デフォルトだと「GIT_DIR」に何も設定されていないからなのか、「.git」ディレクトリとして作成される模様。

で、GitHubの公式のブログによると、

github.blog

In your local Git repositories, your data is stored in the .git directory. Inside, there is a .git/objects directory that contains your Git objects.

https://github.blog/open-source/git/gits-database-internals-i-packed-object-store/

⇧ とあり、「GIT DIR」に該当する「.git」ディレクトリ配下には「objects」ディレクトリがあり、そこに「object」という形でデータが保存されてますと。

つまり、「Git」で用意されているコマンドで操作する想定になっていますと。

で、一般的な「シェル」については、

developer.ibm.com

Basic shell architecture

Figure 2. Simple architecture of a hypothetical shell

In the Resources section, you can find links to learn about the architecture of the open source Bash shell.

https://developer.ibm.com/tutorials/l-linux-shells/

⇧ 上記のような感じで、デフォルトで「ls -la」とかのコマンドを利用できるのだが、こやつらは、通常の「ファイル」に対しての利用を想定していますと。

で、「Git」の「bare repository」は「workig tree」を持たないので、通常の「ファイル」の形でデータを保持せず、「GIT DIR」の「object」としてしかデータを保持していないと。

少なくとも、「Oxidized」の「Rugged」の利用の仕方では、「ファイル」の形ではデータを保持していない。

というのも、

github.com

⇧ issueで、議論が上がっていたので。

話の脱線が長くなりましたが、ということで、表題の件の話になりますと。

ポイントは、

stackoverflow.com

⇧ bare repositoryの場合「commit hash」でしか比較できないってことですかね。

あとは、

commis.hatenablog.com

git diffにquietオプションを指定すると、戻り値で判定できる。

差分がなければ0が返り、あれば1が返る。

Gitでリモートブランチの更新の有無を戻り値で判定する - 料理とソフトウェアは似ている

⇧ 変更があったかどうかだけであれば、上記サイト様にありますように、「git diff」のオプションで「--quiet」というものを付けてあげるということでしょうか。

公式のドキュメントを見てみたけども、

github.com

⇧「Git」で用意されている定数っぽいものが返却されるとしか記載がないのだが、

github.com

C言語が分からんので何とも言えんのだけど、

strcmpは2つの文字列を比較 (compare) するC言語関数である。 標準Cライブラリの文字列操作関数群が宣言されているヘッダーファイル string.h に含まれる。 ストリングコンペアストリングコンプなどと呼ばれることが多い。

strcmp - Wikipedia

⇧ とあるので、とりあえず、「diff.trustexitcode」の値と異なる場合に、「0」を返しているっぽいが、よく分からん...

環境変数の「GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE」の説明を見ると、

環境変数の「GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE」が「false」に設定されている場合、常に「0」を返すとなっている。

つまり、常に、差分なしと判定されてしまうと。

そして、環境変数の「GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE」の現状の設定を確認する術が分からんという...

結局、実際に、「git diff」コマンドをオプション「--quiet」付きで実施して検証するしか無いってことか。

では、シェルスクリプトを試す環境としては、

ts0818.hatenablog.com

⇧ 上記の記事の時に、導入していた「Oxidized」で生成された「Git」のローカルの「bare repository」を利用することにします。

以下のように、gitコマンドが利用できる環境であれば、何でも良いですが。

何はともあれ、シェルスクリプトのファイルを作成。

■viでシェルスクリプトのファイルを編集する(ファイルが無い場合は新規で作成される)

vi test-git-diff.sh    

で、

stackoverflow.com

bashシェルスクリプトは、

  1. 戻り値をechoで返す場合、関数内でechoした内容が全て戻り値になる
  2. 戻り値をreturnで返す場合、trapを利用していると、0以外がtrapで捕捉されてしまう

⇧ といった感じで、かなり残念な仕様になっている。

以下の内容で、保存する。

コミットが実施された日時のチェックとかは、今回の変更の検知には関係ないですが、コミットして1日経過しているかとかのチェックとかもしています。

■/opt/app/oxidized/.config/oxidized/test-git-diff.sh

#!/bin/bash

################################################################
#
#  関数定義など
#
################################################################
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  エラーをスローする
#■    params $1 エラーメッセージ
#■    exit 1 trapの実行トリガーとなるように0以外の数値
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function execption_throw() {

  # 標準出力を標準エラーにリダイレクト
  echo $1 1>&2

  # 戻り値
  exit 1

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  エラーハンドリングする
#■    params $1 エラー行
#■    params $2 実行コマンド
#■    params $3 シェルのステータス
#■    return 99 0と1以外の数値なら何でも
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function error_handler() {

  local line_no=$1
  local exe_cmd=$2
  local status=$3

  echo "□status□${status}" 1>&2

  # エラーが発生した場合のみ出力
  if [[ "${status}" -ne 0 ]]; then

    # 標準出力を標準エラーにリダイレクト
    echo -e "□行□${line_no}\n□実行コマンド□${exe_cmd}□ステータス□${status}" 1>&2

    # 戻り値
    return 99
  fi

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  ログ関数
#■    params $1 ログ出力先
#■    params $2 ログファイルに出力したいメッセージ
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function output_logger() {

  local LOG_LOCATION=$1
  local output_message=$2

  echo "${output_message}" >> "${LOG_LOCATION}"

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  コミットの日時を現在の日時と比較する関数
#■    params $1 現在の日時
#■    params $2 最新のコミットされた日時
#■    return 0 true:コミットして1日以上(変更あり)
#■           1 false:コミットして1日未満(変更なし)
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function compare_commit_time() {

  local current_time=$1
  local commit_time=$2

  # コミットの日時を秒に変換
  commit_epoch=$(date -d "${commit_time}" +%s)
  current_epoch=$(date -d "${current_time}" +%s)

  # 1日の秒数
  one_day_seconds=$((24 * 60 * 60))

  # 日時の差を計算
  time_difference=$((current_epoch - commit_epoch))

  # 1日以上経過しているかどうかをチェック
  if [[ "${time_difference}" -ge "${one_day_seconds}" ]]; then
    # 1日以上経過している
    return 0

  else
    # 1日未満
    return 1

  fi

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  2つのコミットハッシュの日時をチェックする関数
#■    params $1 最新のコミットされた時間
#■    params $2 1つ前のコミットされた時間
#■    return 0 true:異常なし
#■           1 false:異常あり
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function compare_latest_with_previous() {

  local latest_commit_time=$1
  local previous_commit_time=$2

  # 日時の比較
  if [[ "${latest_commit_time}" > "${previous_commit_time}" ]]; then
    # 戻り値
    return 0

  else
    # 戻り値
    return 1

  fi

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  コミットの日時を取得し、比較する関数
#■    params $1 最新のコミットハッシュ
#■    params $2 1つ前のコミットハッシュ
#■    params $3 ログ出力先
#■    return 0 内容に差分なし(変更なし)
#■           1 内容に差分あり(変更あり)
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
 
function check_commit_times() {

  local latest_commit_hash=$1
  local previous_commit_hash=$2
  local LOG_LOCATION=$3
  local is_all_green=0

  # 処理開始
  output_logger "${LOG_LOCATION}" "■■[start]check_commit_times■■"

  ### 現在の日時と最新のコミットの日時を比較する ###
  # 現在の日時を取得
  current_time=$(date +"%Y-%m-%d %H:%M:%S")
  
  # ログ出力
  #echo "■■Current DateTime: ${current_time}■■"
  output_logger "${LOG_LOCATION}" "■■Current DateTime: ${current_time}■■"

  # 最新のコミット日時を取得する
  latest_commit_time=$(git show -s --format=%ci "${latest_commit_hash}")
  
  # ログ出力
  #echo "■■Latest Commit: ${latest_commit_hash}, Time: ${latest_commit_time}■■"
  output_logger "${LOG_LOCATION}" "■■Latest Commit: ${latest_commit_hash}, Time: ${latest_commit_time}■■"

  # 現在の日時と最新のコミットの比較
  compare_commit_time "${current_time}" "${latest_commit_time}"
  RESULT_FUNC=$?

  # ログ出力
  #echo "■■RESULT_FUNC: ${RESULT_FUNC}■■"
  output_logger "${LOG_LOCATION}" "■■RESULT_FUNC: ${RESULT_FUNC}■■"

  if [[ "${RESULT_FUNC}" -ne 0 ]]; then
    # 0か1が加算
    is_all_green=$((is_all_green + RESULT_FUNC))

    # ログを出力
    #echo "Latest commit: ${latest_commit_hash} at ${latest_commit_time} is less than 1 day old."
    #echo "■■is_all_green: ${is_all_green}■■"
    output_logger "${LOG_LOCATION}" "■■Latest commit: ${latest_commit_hash} at ${latest_commit_time} is less than 1 day old.■■"
    output_logger "${LOG_LOCATION}" "■■is_all_green: ${is_all_green}■■"

  fi

  ### 最新のコミットの日時と1つ前のコミットの日時を比較する ###
  # 1つ前のコミット日時を取得する
  previous_commit_time=$(git show -s --format=%ci "${previous_commit_hash}")
  
  # ログ出力
  #echo "■■Previous Commit: ${previous_commit_hash}, Time: ${previous_commit_time}■■"
  output_logger "${LOG_LOCATION}" "■■Previous Commit: ${previous_commit_hash}, Time: ${previous_commit_time}■■"

  # 最新のコミットが1つ前のコミットより新しいかをチェック
  compare_latest_with_previous "${latest_commit_time}" "${previous_commit_time}"
  RESULT_FUNC=$?

  # ログ出力
  #echo "■■RESULT_FUNC: ${RESULT_FUNC}■■"
  output_logger "${LOG_LOCATION}" "■■RESULT_FUNC: ${RESULT_FUNC}■■"

  if [[ "${RESULT_FUNC}" -ne 0 ]]; then
    # 0か1が加算
    is_all_green=$((is_all_green + RESULT_FUNC))
    
    # ログを出力
    #echo "Latest commit ${latest_commit_hash} is older than previous commit ${previous_commit_hash}."
    #echo "■■is_all_green: ${is_all_green}■■"
    output_logger "${LOG_LOCATION}" "■■Latest commit ${latest_commit_hash} is older than previous commit ${previous_commit_hash}.■■"
    output_logger "${LOG_LOCATION}" "■■is_all_green: ${is_all_green}■■"

  fi

  # 処理終了
  output_logger "${LOG_LOCATION}" "■■[end]check_commit_times■■"  

  # 戻り値
  return "${is_all_green}"

}

#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
#■
#■  コミットを比較する関数
#■    params $1 Gitのローカルのベアリポジトリのパス
#■    params $2 ログ出力先
#■    return 0 内容に差分なし(変更なし)
#■           1 内容に差分あり(変更あり)
#■
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function compare_commits() {

  # Gitのローカルのベアリポジトリのパス
  local BARE_REPO_PATH=$1
  local LOG_LOCATION=$2

  # 処理開始
  output_logger "${LOG_LOCATION}" "■■[start]compare_commits■■"  

  # Gitのローカルのベアリポジトリのディレクトリに移動
  output_logger "${LOG_LOCATION}" "■■BARE_REPO_PATH: ${BARE_REPO_PATH}■■"
  cd "${BARE_REPO_PATH}"

  # コミットの件数を取得
  COMMIT_COUNT=$(git rev-list --count HEAD)

  # コミットが2件以上あるか確認
  output_logger "${LOG_LOCATION}" "■■COMMIT_COUNT: ${COMMIT_COUNT}■■"
  if [[ "${COMMIT_COUNT}" -lt 2 ]]; then
    execption_throw "Error: Not enough commits to compare. Current commits: ${COMMIT_COUNT}"

  fi

  # 最新の2件のコミットハッシュを取得
  COMMIT_HASHES=($(git rev-list --max-count=2 HEAD))

  # コミットハッシュを表示
  #echo "■■Comparing commits:■■" >&2
  #echo "■■Commit 1: ${COMMIT_HASHES[0]}■■" >&2
  #echo "■■Commit 2: ${COMMIT_HASHES[1]}■■" >&2
  output_logger "${LOG_LOCATION}" "■■Comparing commits:■■"
  output_logger "${LOG_LOCATION}" "■■Commit 1: ${COMMIT_HASHES[0]}■■"
  output_logger "${LOG_LOCATION}" "■■Commit 2: ${COMMIT_HASHES[1]}■■"

  # コミットの日時をチェック
  check_commit_times "${COMMIT_HASHES[0]}" "${COMMIT_HASHES[1]}" "${LOG_LOCATION}"
  IS_ALL_GREEN=$?
  
  #echo "■■IS_ALL_GREEN: ${IS_ALL_GREEN}■■" >&2
  output_logger "${LOG_LOCATION}" "■■IS_ALL_GREEN: ${IS_ALL_GREEN}■■"

  # 最新コミットから1日経過していない場合
  if [[ "${IS_ALL_GREEN}" -ne 0 ]]; then

    # 戻り値
    # 最終コミットから1日経過していない場合(差分なしとする)
    echo 0

  # 最新のコミットから1日以上経過している場合
  else

    # git diffを実行
    # 最新のコミットと1つ前のコミットの内容を比較
    git diff --quiet "${COMMIT_HASHES[0]}" "${COMMIT_HASHES[1]}"
    DIFF_EXIT_CODE=$?

    #echo "■■DIFF_EXIT_CODE: ${DIFF_EXIT_CODE}■■" >&2
    output_logger "${LOG_LOCATION}" "■■DIFF_EXIT_CODE: ${DIFF_EXIT_CODE}■■"

    # 内容に差分なし(変更なし)
    if [[ "${DIFF_EXIT_CODE}" -eq 0 ]]; then
      # 戻り値
      echo 0

    # 内容に差分あり(変更あり)
    elif [[ "${DIFF_EXIT_CODE}" -eq 1 ]]; then
      # 戻り値
      echo 1

    else
      execption_throw "An error occurred during git diff."

    fi
  fi

  # 処理終了
  output_logger "${LOG_LOCATION}" "■■[end]compare_commits■■"  

}

################################################################
#
#  メイン処理
#
################################################################

# ログ出力先
CURRENT_DIR=$(cd $(dirname $0) && pwd)
LOG_LOCATION="${CURRENT_DIR}/logfile.log"

# 処理開始
output_logger "${LOG_LOCATION}" "■[start]メイン処理■"

# エラーハンドリング
trap 'error_handler ${LINENO} ${BASH_COMMAND} $?' ERR

# ログ出力
#output_logger
#CURRENT_DIR=$(cd $(dirname $0) && pwd)
#exec >> >(tee -a "${CURRENT_DIR}/logfile.log" 2>&1)

# ベアリポジトリのパス
BARE_REPO_PATH="/opt/app/oxidized/.config/oxidized/test-personal-github-app.git"

# 関数を呼び出す
RESULT_COMPARE_COMMITS=$(compare_commits "${BARE_REPO_PATH}" "${LOG_LOCATION}")

echo "■RESULT_COMPARE_COMMITS: ${RESULT_COMPARE_COMMITS}■"
output_logger "${LOG_LOCATION}" "■RESULT_COMPARE_COMMITS: ${RESULT_COMPARE_COMMITS}■"

# 処理終了
output_logger "${LOG_LOCATION}" "■[end]メイン処理■"

シェルスクリプトを実行します。

シェルスクリプトを実行

bash test-git-diff.sh

⇧ ログが分かり辛いが、git diffの比較はできてはいそう。

あくまで、シェルスクリプト以外で、リモートのGitリポジトリにgit pushされないという前提の形になってはいますが。

bashは、関数で戻り値を返すことに難があったり、いろいろと欠陥が多いので利用を回避できるなら回避したいのが正直なところですかね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。