gitで特定ディレクトリで特定のタグ/ブランチをディスク容量ケチって追う
gitで以下のようなことをやりたい。試しにスクリプト書いてみたんだが、どうもダサい感じがする。
入力値: リポジトリURL と タグ/ブランチ
指定のリポジトリURLから、特定のタグ/ブランチをcloneしてくる。すでにclone済みであって、clone済みのものが最新であればcloneしてこない。タグ・ブランチ名がバージョン番号っぽいものであれば、–depth 1を使って容量を削減する。
用途としては、モジュールを特定バージョンやブランチに固定したいが、ブランチ名の場合には履歴もちゃんととってそのモジュールの開発もできるようにしたい、というもの。
試しに書いたもの
#!/bin/bash
BASE_URL="git@xxxx:user"
# $1 = repository_name, $2 = tag or branch
if [[ "$1" =~ / ]]; then
echo "abune-" # For avoiding 'rm -rf /'
exit 1
fi
git_dir="./$1/.git"
if [ -d "$git_dir" ]; then
local_hash=$(GIT_DIR=$git_dir git rev-parse HEAD)
fi
remote_hash=$(git ls-remote $BASE_URL/$1.git $2^{} | cut -f1)
if [ -z "$remote_hash" ]; then
remote_hash=$(git ls-remote $BASE_URL/$1.git $2 | cut -f1)
if [ -z "$remote_hash "]; then
echo "naiyo-"
exit 2
fi
fi
if [ "$local_hash" != "$remote_hash" ]; then
if [[ $2 =~ ^v[0-9.]+$ ]]; then
clone_flag="--depth 1"
else
current_branch=$(GIT_DIR=$git_dir git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" = "$2" ]; then
# just pull
pushd $1
git pull origin $2
popd
exit 0
fi
clone_flag=""
fi
rm -rf $1
git clone $clone_flag --branch $2 $BASE_URL/$1.git
if [ $? -ne 0 ]; then
echo "yabainjan"
fi
else
echo "nanmosen"
fi
ダサいところ
指定されたtagがannotated tagの場合にはコミットそのもののhash値を取るために、一回^{}を付けて聞いているのがイケてない。annotated tagでない場合は2回聞いちゃうので遅くなる。
git ls-remote git@xxx:user/rep v0.0.1^{commit}
でうまくいくかと思ったけどダメだった。
git ls-remote git@xxx:user/rep v0.0.1*
というのも考えたが、v0.0.1^{}と同時にv0.0.13などもひっかかってしまうのでダメ。
こっちのほうがいい?
ローカルのほうですでにclone済みの場合には、
git describe --tag
した結果現在指しているタグを取得する。次に、取得したタグを用いて、そのタグがannonated tagだった場合annotated tagのhash値を取る。具体的には、
git show-ref --tag -d $fetched_tag
をして、一番下の1行を取得する。
これとリモートの指定されたhash値を比較する。これでリモートに対するコマンド発行数が1回に減らせそう。
ただ、もっとスマートに書けそうな気がするんだよなー。タグとブランチをちゃんと峻別したり、.gitディレクトリの中のファイルを見たりするとよさげか。というわけでブログで投げっぱなしジャーマン。ツッコミは@gunyarakunまで。