ま、そんなところで。

ニッチな技術系メモとか、車輪を再発明してみたりとか.

Git LFS管理オブジェクトを圧縮状態で運用する

LFS管理のオブジェクトは非圧縮で管理されるため、git本体で管理するよりも容量が大きくなってしまいます.
しかし、LFS拡張を使用するとオブジェクトを圧縮管理させて運用できるかもしれません.

1. 前提

2. Git LFS Extensions

2-1. Git LFS Extensionsとは

LFSには、オブジェクトの取得時と登録時に任意のコマンドを実行できる機能があります.

github.com

以下の設定を config ファイルに記述して設定すると、登録時と取得時に自動でコマンドを実行してくれます.

[lfs "extension.<name>"]
    clean = <command>
    smudge = <command>
    priority = <priority>

cleanLFSオブジェクトの登録時(git addのタイミング)に実行されるコマンド、 smudgeLFSオブジェクトの取得時(git checkoutのタイミング)に実行されるコマンドです.
priority は、複数の extension がある場合に、実行される順序を指定します.
数値が小さいほど優先度が高くなります.

2-2. LFSオブジェクトの圧縮/展開拡張

Git LFS Extensions を使って、LFSオブジェクトの登録時に圧縮し/取得時に展開するコマンドを設定します.
以下のコマンドを実行して、Git LFS Extensions を登録します.

# LFSオブジェクトの登録(git add)時の圧縮/取得(git checkout)時の展開処理を登録
# ローカルの場合. 他のリポジトリと競合しないなら --global で登録してもよいかもしれません. 
git config --local lfs.extension.gzip.clean "gzip -c"
git config --local lfs.extension.gzip.smudge "gzip -d"
git config --local lfs.extension.gzip.priority 1

configファイルには以下のように登録されます.

[lfs "extension.gzip"]
    clean = "gzip -c"
    smudge = "gzip -d"
    priority = 1

これでLFSサーバ上ではファイルが圧縮された状態で管理されるようになります.
push/fetch時の通信量も減りますので、高速化が見込めますね.

下記と併用すると、色々と便利です.
zv-louis.hatenablog.com

2-3. 運用上の注意

2-3-1. 関連ツールの対応が期待できない

この機能は2025/07 の時点でまだ experimental な位置づけとのこと.
Git各種ツールでの対応状況はまちまちでした.

  • 公式git, git for windows, cygwin の git の対応は確認.
  • TortiseGit は対応を確認. diffもできるっぽい.
  • SourceTreeは、圧縮LFSオブジェクトのcheckoutは正常にできているが、diffができない.
    ※ 圧縮状態のバイナリファイルと認識されているっぽい

2-3-2. .lfsconfig で extensions の指定ができない

Git LFS Extensions は セキュリティ上の理由から .lfsconfig ファイルに記述することはできないようになっています.
※ 記述したとしても、LFSオブジェクトの登録/取得時には警告が出て無視されます.
このためGitの管理対象ファイルに含めて自動で読み込ませることができません.

git clone時には git clone -n を使い、cloneと同時にチェックアウトを行わないようにして、 最初にリポジトリを参照するユーザ各々が手動で設定をする必要があります.

3. (参考)

SSH接続だけで利用できる Git LFS 対応のリポジトリを作る方法

Git LFSを使うとき、GithubやGitLabなどのサービスを使えば容易なのですが、どうにもこうにもストレージやtransactionのコストが気になりますね.

そこで、LFSに対応したGitのbareリポジトリを自前で準備できないか調べてみたところ、
まだ experimental な機能ではありますが、 pure SSH プロトコルに対応した git-lfs-transfer コマンドをサーバに準備してやれば、 ssh接続での利用に限ってLFSに対応したbareリポジトリを作ることができるようになることがわかりました.

これでひとまずはコスト意識せずに Git-LFS を使えます.

1. 前提

bareリポジトリを置くサーバーにはSSHの公開鍵認証でログインできるようにしておきます.
また、git-lfsのバージョンはv3.0以降である必要があります.

Git-LFSの準備については下記参照.
zv-louis.hatenablog.com

2. サーバ側のセットアップ

pure SSHに対応した git-lfs-transfer の実装はいくつかあるようですが、 今回は bk2204/scutiger の実装を使うことにします.

Rust言語で書かれているので、ビルドするにはRustの環境が必要です.

2.1. Rustビルド環境の準備

2.1.1. 必要なパッケージ類の導入

ビルドに必要な開発パッケージをインストールしておきます.

sudo apt install -y git libssl-dev zlib1g-dev libpcre2-dev libgit2-dev build-essential

2.1.2. Rustのビルド環境(cargo/rustcなど)をインストールする

公式サイトのガイドに従い、サーバ側にRustのビルド環境をインストールします.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

インストール後、以下のコマンドで環境変数を設定します.

source $HOME/.cargo/env

Rustビルド環境のインストールが完了したら、以下のコマンドでcargoのバージョンを確認します.

cargo --version

正常にインストールされていれば、バージョン情報が表示されます.

2.2. scutigerのビルド&インストール

Rustの準備ができたらscutigerをビルドしてコマンドの実行ファイルを作ります.

2.2.1. リポジトリをcloneする

ビルド用のディレクトリを作成し、scutigerをcloneします

mkdir -p scutiger
cd scutiger
git clone https://github.com/bk2204/scutiger.git .

2.2.2. Makefileの修正

インストール時にエラーになるので、 ビルドを実行する前に Makefile の installターゲットを修正します.

--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ test:
 install: all
        for i in target/release/git-*; do \
                [ -x "$$i" ] || continue; \
-               install -m 755 "$$i" "$(DESTDIR)/bin/$$(basename "$$i")"; \
+               sudo install -m 755 "$$i" "$(DESTDIR)/bin/$$(basename "$$i")"; \
        done

2.2.3. scutigerをビルド&インストール

scutigerをビルドしてインストールします.

make install

正常にビルドされると、/usr/local/bin に以下のコマンドがインストールされます.

ls -l /usr/local/bin/
-rwxr-xr-x 1 root root 1832528  712 22:44 git-at
-rwxr-xr-x 1 root root 1824504  712 22:44 git-lfs-transfer
-rwxr-xr-x 1 root root 1832864  712 22:44 git-recent-refs

2.3. git-lfs-transfer コマンドの動作確認

① サーバー側の動作確認

動作確認のために、サーバ上で以下のコマンドを実行してみます.

git-lfs-transfer

正常に動作していれば、以下のようなメッセージが表示されるはず.

$ git-lfs-transfer
error: The following required arguments were not provided:
    <path>
    <operation>

USAGE:
    git-lfs-transfer <path> <operation>

For more information try --help

② クライアント側からの動作確認

クライアント側からssh接続経由で git-lfs-transfer が実行できるか確認します.

ssh user@server git-lfs-transfer

正常に動作していれば、サーバー上と同様のメッセージが表示されるはずです.

以上でサーバー側のセットアップは完了です.

3. 運用時の制限事項

3.1. リモートリポジトリはSCP/SSH形式での表記が必要

git-lfs-transfer を使う場合は、リモートリポジトリの設定をSCP/SSH形式で設定する必要があります.
HTTP/HTTPS形式では git-lfs-transfer が正しく動作しないようです.

git@server:repo.git      # OK
ssh://git@server/repo.git # NG!!  http/https形式での設定だと正しく動作しない.

3.2. clone時に環境変数の設定が必要(LFSのセキュリティ保護)

セキュリティ上の理由から、clone時に自動で checkout しないようになっています.
nオプションをつけて( git clone -n )cloneするようにします.

cloneと同時にcheckoutしたい場合は、 GIT_CLONE_PROTECTION_ACTIVE 環境変数を設定します.
この環境変数はコマンドの実行時のみ有効にするようにし、環境変数として常に設定しておくのは避けるべきとされています.

GIT_CLONE_PROTECTION_ACTIVE=false git clone git@server:repo.git .  

3.3. Pure SSHプロトコル対応のツールは少ない

SourceTreeTortoiseGit など、主だったGitのGUIツールではまだ pure SSH プロトコルLFSを扱うことができません.
公式のgit, git for windowsの git コマンド, cygwin の git など、公式のgitしか対応していないようです.

4. トラブルシューティング(ここでトラブった・・・)

4-1. 「git-lfs-authenticate が見つからない」というエラーになる

pure SSH は git-lfs の version 3.0.0 以降でサポートされていて、 pure SSH プロトコルが使われていれば、git-lfs-authenticate は必要ないはず.

① git-lfs のバージョンを確認

git lfs version

git-lfs のバージョンが 3.0.0 以降でない場合は、git-lfs をUpdateします.

② git-lfs-transfer が ssh経由で使用できるか確認.

push時に git-lfs-transfer が エラーになると、gitは git-lfs-authenticate を使ったプロトコルへフォールバックするっぽい.
ssh経由で git-lfs-transfer コマンドが エラーになっていないかを確認します.

ssh user@server git-lfs-transfer

sshで直接コマンド実行する場合、bashrcが読み込まれていなかったりしますので、 パスが通ってないとか、権限の問題でエラーになっている可能性があります.

4-2. push時にgit-lfs-transferがデッドロックする

sshマルチプレクシングが使われていると、push時に git-lfs-transferデッドロックを起こすことがあるようです.
sshマルチプレクシングを使用しないようにリポジトリに設定します.

# リポジトリに設定
git config lfs.ssh.automultiplex false
# ユーザレベルでもOK
git config --global lfs.ssh.automultiplex false

(参考サイト)

Gitリポジトリを履歴を保ちつつLFSに移行する

GitHubリポジトリを移行したい!
となったとき、ファイルサイズ制限(100MB)やリポジトリサイズの警告(1GB)ですんなり行かないことがあります.
移行にはLFSの導入が必須となるのでリポジトリの再作成が必須なのですが、過去の履歴もなんとか保持したい・・ですよね.

履歴をそのままにして、過去に遡って巨大なファイルをLFS管理としてリポジトリを再構築する手順です.

1. 動機

2. 移行手順

基本的に git lfs migrate コマンドを使用して、リポジトリ内の大きなファイルをLFSに移行するのですが、履歴上のどのファイルを移行するかは今後の運用を考える上で重要です.
そのため、以下の手順で移行を行います.

Step1. 対象のファイルを確認: git lfs migrate info コマンドを使用して、巨大なオブジェクトのファイルを確認します.
Step2. 対象のファイルを選択: 移行に必要なmigrate import対象のファイルを選択し、必要なフィルタ設定を検討します.
Step3. 対象のファイルを移行: git lfs migrate import コマンドを使用して、対象のファイルをLFSに移行します.

2-1. 対象のリポジトリをクローンする

まず、対象のリポジトリをミラークローンして作業リポジトリにします.

mkdir <repository-name>.git
cd <repository-name>.git
git clone --mirror <repository-url> .

2-2. 対象のファイルを確認

リポジトリへ移動します.

cd <repository-name>.git

git lfs migrate info コマンドを使用して、リポジトリ内の大きなファイルを確認します.
どのファイルがどれだけサイズに影響を与えているかを確認します.

git lfs migrate info --everything
# 出力例:
Sorting commits: ..., done.                                                                                                  
Examining commits: 100% (8421/8421), done.                                                                                   
*.csv       1.0 GB    13388/13388 files 100%
*.lib       899 MB       76/76 files 100%
*.def       517 MB       95/95 files 100%
*.cs        494 MB   8432/8432 files 100%
*.dic       484 MB         3/3 files 100%

リポジトリ内のどのファイルが大きいのかを確認するには以下のコマンドを利用します.
上位から指定した件数のファイルを表示します.

# リポジトリ内のオブジェクトサイズ表示
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sort -k3 -n -r | head -n ${件数}

# サイズを単位付き表示とする場合はこちら
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sort -k3 -n -r | head -n ${件数} | \
awk '{print $1, $2, $3, $4}' | \
numfmt --field=3 --to=iec
# 出力例
blob 1234567890abcdef1234567890abcdef12345678 1000000000 path/to/largefile.zip
blob 1234567890abcdef1234567890abcdef12345679 900000000 path/to/anotherlargefile.zip

ちなみに、現在チェックアウトされているファイルで大きいものを探す場合は下記のコマンド

# .git 以下は除外する.
find . -type d -name '.git' -prune -o -type f -print0 | xargs -0 du -h | sort -hr | head -n ${件数}

2-2. 対象のファイルを選択

git lfs migrate import の include フィルタに適用するパラメータを検討します.
項目が多くなりがちなので、patterns.txt ファイルを作成して、摘要パターンを記載していきます.

*.psd                    # 特定の拡張子のファイル
hoge/fuga/*              # 特定のディレクトリ内直下の全てのファイル
hoge/fuga/*.zip          # 特定のディレクトリ内のzipファイル
hoge/fuga/**             # 特定のディレクトリ以下(サブディレクトリ含む)全てのファイル
hoge/fuga/**/hoge-*.zip  # 特定のディレクトリ以下(サブディレクトリ含む)の全てのhoge-*.zipファイル
/hoge/fuga/xxxx.zip      # 特定のパスのファイル

※ 実際のファイルにはコメントを含めないこと

2-3. 対象のファイルを移行

2-3-1. LFS移行の実行

patterns.txt ファイルを作成したら、以下のコマンドで対象のファイルをLFSに移行します.

git lfs migrate import --include="$(paste -sd , patterns.txt)" --everything

2-3-2. リポジトリの確認

移行後、リポジトリの状態を確認します.
指定したファイルがLFSで管理されていることを確認します.

git lfs ls-files

また、リポジトリのオブジェクト一覧から対象のファイルがLFS管理となって列挙されないことを確認します.

git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sort -k3 -n -r | head -n ${件数}

2-4. リポジトリへpush

移行したリポジトリをリモートへpushします.
pushはmirrorを使用して、LFSオブジェクトも含めてpushします.

注意 : この操作はリモートリポジトリを上書きするため、慎重に行ってください.

git push --mirror origin

(参考)

Git LFSのセットアップ

1. クライアントのセットアップ

1-1.Windows

ここからダウンロードしてインストール.

1-2. macOS/Linux

git-lfsリポジトリからインストールする.

2. Git LFSを使う

2-1. Git LFSの初期化

Git LFSをインストールしたら、最初に初期化してフックスクリプトを登録必要がある.
ユーザごとに実施が必要.

git lfs install

2-2. LFSの対象ファイルの指定

Git LFSを使用するには、git add の前に、LFSで管理したいファイルの拡張子を指定しておきます.
ファイル名を指定することもできるが、拡張子を指定するのが一般的らしい.

# 特定の拡張子を指定する場合は以下のように指定する.
git lfs track "*.zip"

# path/to/folder以下のzipファイルをLFSで管理する場合は以下のように指定する.
git lfs track "path/to/folder/*.zip"

# path/to/folder以下の全てのファイルをLFSで管理する場合は以下のように指定する.
git lfs track "path/to/folder/*"

# path/to/folder以下を再帰的に全てのファイルをLFSで管理する場合は以下のように指定する.
git lfs track "path/to/folder/**"   

# 上記を組み合わせたパターンの例
# path/to/folder以下の全てのzipファイルを再帰的にLFSで管理する場合.
git lfs track "path/to/folder/**/hoge-*.zip"

このコマンドを実行すると、.gitattributes ファイルが作成され、以下のような内容が追加される.
このファイルもファイルと一緒にgitにコミットしておく.

*.psd filter=lfs diff=lfs merge=lfs -text

この設定により、指定した拡張子のファイルはGit LFSで管理されるようになる.

2-3. LFSで管理されているファイルの確認

LFSで管理されているファイルは、以下のコマンドで確認できる.

git lfs ls-files

2-4. LFSで管理されているファイルのコミット

LFSで管理されているファイルをコミットする際は、通常のGitの操作と同様に git add を行い、コミットする.

git add path/to/file.zip
git commit -m "Add file.zip to LFS"

2-5. LFSで管理されているファイルのプッシュ

LFSで管理されているファイルをリモートリポジトリにプッシュする際は、通常のGitの操作と同様に git push を行う.

git push origin main

2-6. LFSで管理されているファイルのクローン

LFSで管理されているリポジトリをクローンする際は、通常のGitの操作と同様に git clone を行う.

git clone

2-7. LFSで管理されているファイルの取得

LFSで管理されているファイルを取得する際は、通常のGitの操作と同様に git pull を行う.

git pull origin main

2-8. LFSで管理されているファイルの削除

LFSで管理されているファイルを削除する際は、通常のGitの操作と同様に git rm を行う.

git rm path/to/file.zip
git commit -m "Remove file.zip from LFS"

2-9. LFSで管理されているファイルのアンインストール

LFSをアンインストールする場合は、以下のコマンドを実行する.

git lfs uninstall

2-10. LFSのバージョン確認

LFSのバージョンを確認するには、以下のコマンドを実行する.

git lfs version

(参考)

git-lfs.com

sshで接続時にToo many authentication failuresになる

$ ssh -vv hoge
         :
Received disconnect from UNKNOWN port 65535:2: Too many authentication failures

<原因>

ssh-agentの試行回数は6回. 6回を超えるとToo many authentication failures.

対策は2つ

sshクライアント側

(a) 接続設定として に IdentityOnly yes を指定する.

(b) ssh-agent から鍵を削除

sshサーバ側

Server administrators can increase the limit by setting MaxAuthTries in the server's /etc/ssh/sshd_config

developer.1password.com

(Ubuntu24.04) pyenvでpython環境インストール時に発生したエラー対処メモ

Ubuntu 24.04 環境でpyenvを使用してpython環境をinstallするときのエラー対処一覧メモ.

1. インストール時にpythonのビルドスクリプトでエラー

ホスト環境に 'python3-venv' が必要なようです.

sudo apt install python3-venv

以下に情報がありました.
stackoverflow.com

2. python環境のビルドエラー/警告の対処

(1) ModuleNotFoundError: No module named '_ssl'

ModuleNotFoundError: No module named '_ssl'
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

'libssl-dev' をインストールします.
これが無いとビルドエラーでインストール失敗するみたいです

(2) ModuleNotFoundError: No module named '_bz2'

ModuleNotFoundError: No module named '_bz2'
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?

'libbz2-dev' をインストールします.

(3) ModuleNotFoundError: No module named '_curses'

ModuleNotFoundError: No module named '_curses'
WARNING: The Python curses extension was not compiled. Missing the ncurses lib?

'libncurses-dev' をインストールします.

(4) ModuleNotFoundError: No module named 'readline'

ModuleNotFoundError: No module named 'readline'
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?

libreadline-dev をインストールします.

(5) ModuleNotFoundError: No module named '_tkinter'

ModuleNotFoundError: No module named '_tkinter'
WARNING: The Python tkinter extension was not compiled and GUI subsystem has been detected. Missing the Tk toolkit?

tk-dev (tk8.6-dev) をインストールします.

(6) ModuleNotFoundError: No module named '_lzma'

ModuleNotFoundError: No module named '_lzma'
WARNING: The Python lzma extension was not compiled. Missing the lzma lib?

liblzma-dev をインストールします.

2. 今回エラーは出ていないけど、おそらく必要なライブラリ

今回エラーは出てませんでしたが、他のパッケージとともにインストール済みで必要と思われるものです.

(1) zlib

gzip圧縮のライブラリ.
おそらくdevパッケージがない場合エラーか警告となるはず・・。

zlib1g-dev をインストールします.

(2) sqlite3

軽量のファイルDBの開発パッケージ.
これも必須だった気がします.

libsqlite3-dev をインストールします.

(3) libffi

debugpy モジュールで、ブレークポイントを張るような環境の場合、ffiライブラリをリンクさせておきます.
このライブラリがリンクされていないと、_ctype のが参照できず、インストールしたpython環境でブレークポイントを張ったデバッグができません.

libffi-dev をインストールします.

詳しいことはこちらに・・ zv-louis.hatenablog.com

3 .まとめ

ということで、下記のコマンドで一括インストールすればすんなりといくはず.

sudo apt install python3-venv libssl-dev libncurses-dev libreadline-dev tk-dev libbz2-dev liblzma-dev libffi-dev zlib1g-dev libsqlite3-dev

VirtualBox上のLinuxOSの動作がとても遅い場合に試す設定のメモ

VirtualBox上でLinuxOSを動作させる場合、動作が非常に遅くなるケースがあります.
このような場合に行う設定のメモ.

1. VirtualBoxストレージのディスクコントローラの確認

VirtualBoxストレージのディスクコントローラ、「ホストのI/Oキャッシュを使う」オプションがOFFになっていないか確認.
OFFになっているようだったら、ONにする.

ホストのI/Oキャッシュを使う

2. I/O スケジューラの変更

仮想マシン側とホスト側でI/Oスケジューラが動いていると、仮想マシン側は2重にスケジューリングされるので、当然I/Oのパフォーマンスは落ちてしまいます.
仮想マシン側のI/OスケジューリングをOFFにしてホスト側のスケジューリングに便乗するようにすると、パフォーマンスの改善が見込めます.

① udevルールを作成

/etc/udev/rules.d/50-ioschedulers.rules を作成.
(※ ruleの優先度を決めるファイル先頭の数値は必要に応じて適当な値にすること)

② ruleの設定

ruleの内容は以下のように設定すると、起動時にスケジューラをnoneに設定してくれる.

# i/o schedulerを仮想マシン用に"none"にする.
# ※ KERNEL==は物理ディスクデバイス. 以下設定では /dev/sda〜/dev/sdz を指す.
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}="0", ATTR{queue/scheduler}="none"

**③ 確認

再起動後、none にカッコがついていれば設定できています.

# ASM_DISK = デバイス名. 確認したいディスクデバイス sda...sdz を指定.
# cat /sys/block/${ASM_DISK}/queue/scheduler
sudo -E cat /sys/block/sda/queue/scheduler
[none] mq-deadline 

3. VirtiaoBox Guest Additionsをインストール

Guest Additionsのインストールでも仮想マシンのパフォーマンスUpが見込めます.

3-1. 前準備

GuestOS側で必要なソフトをインストールする

sudo apt install build-essential
# ※ non-LTSの場合.
sudo apt install linux-headers-generic 
# ※ LTSの場合. xx-yyはubuntuのLTSバージョン 20.04, 22.04.. etc
sudo apt install linux-headers-generic-hwe-{xx-yy}

3-2. Guest Additionsのインストール

①メディアを挿入する

guest additions CD の挿入

仮想マシン側で挿入された仮想ディスクをマウントする

# /mnt直下にdvd用のマウントポイントとなるディレクトリ作成
sudo mkdir -p /mnt/dvd
# Guest Additionsのディスクを/mnt/dvdへマウント
sudo mount /dev/dvd /mnt/dvd
/mnt/dvd: WARNING: device write-protected, mounted read-only.d

※ /dev/dvd もしくは /dev/cdrom がない場合、/media/{UserName}/以下にディスクがマウントされていないか確認

③ディスク内のVBoxLinuxAdditions.runを実行する

sudo /mnt/dvd/VBoxLinuxAdditions.run

仮想マシンを再起動

仮想マシンを再起動します.

sudo shutdown -r now

参考サイト