0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

適当にブランチを作成・マージした履歴を持つGitリポジトリを作成するシェルスクリプト

Last updated at Posted at 2020-03-07

Gitのブランチ操作に関して練習したり、その方法を記事に纏めたりしたい。そのためには多少複雑なコミット履歴が必要になるのだが、どう用意しようか困っていた。

  • 手動で作る
    • 10コミット作るのも大変
    • ランダム性が低く、あまり複雑な形にならない
  • 実際のOSSのリポジトリを使う
    • 手頃なものを見つける必要がある
    • 間違えても本家にpushしてはいけない
    • 練習とはいえ、意味の無いコミットをしづらい
  • 実業務のリポジトリを使う
    • 論外 最悪クビになる(だけでは済まないかもしれない…)

なので、シェルスクリプトで自動的に作ることにした。自動化するためには普段使わないようなgitコマンドやオプションなどが必要だが、一度書いてしまえば済むので案外問題にならなかった。

実行例

後に示す create_git_sample.sh で、20コミットのリポジトリを作ってみる。

$ mkdir -p ~/projects/git-test && cd ~/projects/git-test

$ bash ~/create_git_sample.sh 20
#1: grow branch_1
#2: grow branch_2
#3: grow branch_3
#4: grow branch_1
#5: grow branch_5
#6: merge branch_5
#7: grow branch_2
#8: grow branch_8
#9: grow branch_3
#10: grow branch_10
#11: merge branch_1
#12: grow branch_3
#13: grow branch_2
#14: merge branch_3
#15: grow branch_10
#16: grow branch_16
#17: merge branch_16
#18: grow branch_10
#19: grow branch_8
#20: grow branch_20

$ git branch
  branch_10
  branch_2
* branch_20
  branch_8
  master

$ git log --all --graph --pretty='format:%h  %s%d%n'  # 結果は以下

git-test-tree.png

rebaseなどの練習ができそうな、いい感じに複雑な履歴になっている。

リポジトリを消すときは次のコマンドを使う。(他のリポジトリのディレクトリで実行しないこと)

rm -rf * .gitignore .git/

スクリプト

動作は以下の通り。

  1. リポジトリを新規作成する
  2. 指定回数だけ以下のいずれかを実行する
    • ランダムに選んだブランチを伸ばす
      • masterや現在と同じブランチを選んだときは、ブランチを新規作成して伸ばす
      • ファイルに書き込むデータは何でもいいので、とりあえず git log --oneline の結果としている
    • ランダムに選んだブランチをmasterにマージして削除する
      • master自身を選んでしまったときは、上記のブランチを伸ばす操作に切り替える

Gitのバージョンは 2.7.4 。別のバージョンではオプションが使えなかったり、もっと良いオプションが使える可能性がある。

create_git_sample.sh
#!/bin/bash
set -eu

function setup_git_repository() {
	git init
	git config --local user.email "xxx@example.com"
	git config --local user.name  "xxx"

	cat << EOF > .gitignore
!*.txt
!.gitignore
EOF
	git add .
	git commit -m "commit #0"
}

function show_branch_name() {
	git symbolic-ref --short HEAD
}

function pick_branch_name() {
	git for-each-ref --format='%(refname:short)' 'refs/heads/*' | shuf -n1
}

function grow_branch() {
	current_branch="$(show_branch_name)"
	target_branch="$(pick_branch_name)"
	if [ -z "${target_branch}" \
	     -o "${target_branch}" = "master" \
	     -o "${target_branch}" = "${current_branch}" ]; then
		target_branch="branch_${i}"
		git branch "${target_branch}" "$(shuf -e -n1 -- 'HEAD' 'master')"
	fi
	git checkout "${target_branch}" 2> /dev/null

	git log --oneline > "${target_branch}.txt"
	git add .
	git commit -m "commit #${1}"

	echo "#${1}: grow ${target_branch}" 1>&2
}

function merge_branch() {
	target_branch="$(pick_branch_name)"
	if [ -z "${target_branch}" ]; then return 1; fi
	if [ "${target_branch}" = "master" ]; then return 2; fi

	git checkout master 2> /dev/null
	git merge --no-ff -X "theirs" -m "commit #${1}" -- "${target_branch}"
	git branch -d "${target_branch}"

	echo "#${1}: merge ${target_branch}" 1>&2
}

#--- main ---#

if [ -d ".git" ]; then
	echo "repository already exists." 2> /dev/null
	exit 1
fi

setup_git_repository > /dev/null

for i in $(seq "${1}"); do
	case "$(shuf -e -n1 -- 'grow' 'grow' 'merge')" in
		"grow"  ) grow_branch "${i}" ;;
		"merge" ) merge_branch "${i}" || grow_branch "${i}" ;;
	esac
done > /dev/null

コマンド等のメモ

  • シェルコマンド
    • set : シェルの動作を設定・確認する
      • -e : コマンドがエラーを返したら即座に終了する(if文などエラーを利用するものは除く)
      • -u : 未設定の変数を使ったらエラーとする
    • shuf : 入力の並びをランダムにする
      • -n : 出力個数を制限する → 1個にすると、ランダムに1個を選択してくれる
      • -e : コマンドライン引数を入力列とする
  • gitコマンド
    • symbolic-ref : 今回は現在のブランチ名を取得するのに使っている
    • for-each-ref : 今回はブランチ一覧を取得するのに使っている ※ git branch では出力を改めて整形する必要がある
    • merge : ブランチをマージする
      • --no-ff : fast-forwardを使わない → 「マージした」という履歴を必ず残せる
      • -X : マージ戦略を指定する → 今回はconflictで手動対処が必要になるのを防ぐために使っている
        • theirs : conflict時は相手の版を採用する

課題

  • ランダムなので、同じ形のリポジトリを再現できない
    • 生成手順を保存して流し込めればいい?(ただしコミットのハッシュ値は変わる)
  • いい具合に複雑な履歴とならないことがそこそこある
    • shuf -e -n1 -- 'grow' 'grow' 'merge' と同じ引数を入れて、確率を調整してみている
    • 新しいブランチを作る時も、 shuf -e -n1 -- 'HEAD' 'master' としてmasterから分岐する確率を上げている

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?