Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2811

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

$
0
0

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'# 結果は以下
commit-tree
* 31d637a  commit #20 (HEAD -> branch_20)
*   f2aa4aa  commit #17 (master)
|\
| * a657015  commit #16
|/
*   aba2761  commit #14
|\
| * 2ee59c2  commit #12
| * 41636ee  commit #9
| * 4331a92  commit #3
| | * 067ef23  commit #18 (branch_10)
| | * 6183b74  commit #15
| | * 7623eea  commit #10
| |/
|/|
* |   c571fd8  commit #6
|\ \
| |/
|/|
| * 410deba  commit #5
| * 85f8ad8  commit #4
| * aed22a4  commit #1
|/
| * f0b9948  commit #19 (branch_8)
| * ab171f9  commit #8
| | * 8eb7aa6  commit #13 (branch_2)
| |/
| * e4fdf2d  commit #7
| * 86f5b66  commit #2
|/
* e06942b  commit #0

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

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

rm-rf* .gitignore .git/

スクリプト

動作は以下の通り。

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

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

create_git_sample.sh
#!/bin/bashset-eufunction 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}";;esacdone> /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から分岐する確率を上げている

参考


Viewing all articles
Browse latest Browse all 2811

Trending Articles