21
14

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 5 years have passed since last update.

LivesenseAdvent Calendar 2014

Day 18

多すぎるブランチをまとめて削除するためにやったこと

Posted at

こんにちは。リブセンスのエンジニアのkurobaraです。

リブセンスでは、会社の口コミサイトである転職会議のメディアチームに所属しています。

一応、転職会議メディアを開発することもありますが、基本は以下のことをやっています。

  • 転職会議メディアに関係する業務システムの開発(一応メイン担当)
  • サーバ運用監視
  • サーバ構成検討
  • etc...

チーム内で転職会議メディア開発以外の雑多なこと全部やっているという感じでしょうか。

今回のお話の発端


転職会議のメディアチームでは毎週1度チーム内のエンジニアでミーティングを行っています。

その時に以下の内容が議題に出ました

「git branch --all が酷いのでMergedなブランチを一括削除したいと思います。」

というのが発端だったりします。

因みにミーティング中、この議題に対して以下の内容が出てました

というわけで軽い気持ちでブランチ数を数えてみる


( ^ω^) 今のブランチ数はっと

( ^ω^)つ ッターン

$git branch --remote | wc -l
289

(゜o゜;

( ^ω^;) 開発人数に対して289個って多すぎやしませんかね・・・

( ^ω^) ブランチ数多いし、これ手作業でやると大変だな

「40日で登録数2.23倍」の実施期間はどれくらいブランチ数増えてたの?


( ^ω^) 当該期間だけで、増えたブランチ数はっと・・・

開始前ブランチ数 終了後ブランチ数
94個 174個

(゜o゜; 期間中に80も増えてる・・・

( ^ω^) 登録数も2倍にしたけど、ブランチ数も2倍になってるwww

(´;ω;`)ブワッ < その前からブランチ運用がザルとか言わないで・・・

そして話し合う・・・


( ^ω^) 要件決まらないなぁ・・・

( ^ω^;) 数多いし、もはやどれが重要か把握出来ないんだろうなぁ

(`・ω・´) とりあえず、それっぽいの作り始めるか

最終的に決まった要件は以下の内容

  • 最終コミットが削除実行日よりも3ヶ月前のブランチは全て削除してもよい
  • masterなど、チーム内運用で使っている特別なブランチは削除してはいけない

ちょっと面倒臭そうなものを調べる


( ^ω^) 実現できそうかどうか確認しておくか

全ブランチを取得
$git branch --all
* master
  test
  hoge
  remotes/origin/hoge
  remotes/origin/fuga
hogeブランチで、最終コミットの日付だけを取得
$git log -n 1 --date=short --pretty=format:"%cd" hoge
2014-12-14
リモートにあるhogeブランチを削除
git push origin :hoge

( ^ω^) いけるな!!

つくった


色々雑だけど、5分かからず実装・・・

(`・v・´) ドヤッ!

require 'rubygems'
require 'chronic'

NOT_DELETE_BRANCHES = ["remotes/origin/HEAD", "remotes/origin/master", "remotes/origin/hoge", "remotes/origin/HEAD -> origin/master"]
BRANCH_PREFIX = 'remotes/origin/'
delete_limit = Chronic.parse('3 months ago')

branches = `git branch --all`.split("\n  ")
excluded_branches = (branches - NOT_DELETE_BRANCHES).map { |branch_name| branch_name if branch_name =~ /remotes\/origin\/*/ }.compact
excluded_branches.each do |branch_name|
  date = `git log -n 1 --date=short --pretty=format:"%cd" #{branch_name}`
  last_commit_date = Chronic.parse(date)

  if last_commit_date <= delete_limit
    delete_branch_name = branch_name.gsub(BRANCH_PREFIX, '')
    `git push origin :#{delete_branch_name}`
  end
end

文字列から日付処理は面倒だったので、chronicを使いました

# cronで回せば問答無用でブランチ削除できるな

一呼吸


( ^ω^) 作ったので実行してみるか〜

( ^ω^;) 待て、これそのまま使って事故起きたらやばいぞ・・・

((;゚Д゚)ガクガクブルブル

手元ならまだしも、リモートの作業をするわけなので確認無かったら怖いですよね

ブラッシュアップ


(`・ω・´) いきなり削除はヤバイから、削除するかのトリガーを引けるようにするか

というわけで、機能を追加

  • 最終コミット内容を表示
  • 削除対象ブランチ名を表示
  • Y/n/qのような感じで実行するかどうかトリガーを引けるようにする

色々と雑だけど、さらっとやるならこんな感じかな

loop do
  p "[Y/n/q]> "
  input = $stdin.gets.gsub(/\n/, '')
  next if input.nil? || input.empty?

  if %w{quit exit q}.include? input
    p 'exit'
    exit
  end

  if %w{no N n}.include? input
    break
  end

  if %w{yes Y y}.include? input
    delete_branch_name = branch_name.gsub(BRANCH_PREFIX, '')
    `git push origin :#{delete_branch_name}`
    break
  end
end

( ^ω^) これで安心して実行できるな

最終実行版


多分、もっと短くできそうだなぁと思いつつも使い捨てなのでこれでいいだろうという感じ

require 'rubygems'
require 'chronic'

SEPARATE_LINE = '##################################################'
NOT_DELETE_BRANCHES = ["remotes/origin/HEAD", "remotes/origin/master", "remotes/origin/hoge", "remotes/origin/HEAD -> origin/master"]
BRANCH_PREFIX = 'remotes/origin/'

delete_limit = Chronic.parse('3 months ago')

branches = `git branch --all`.split("\n  ")

excluded_branches = (branches - NOT_DELETE_BRANCHES).map { |branch_name| branch_name if branch_name =~ /remotes\/origin\/*/ }.compact

excluded_branches.each do |branch_name|
  date = `git log -n 1 --date=short --pretty=format:"%cd" #{branch_name}`
  last_commit_date = Chronic.parse(date)

  if last_commit_date <= delete_limit
    commit_log = `git log -n 1 --date=short #{branch_name}`

    puts SEPARATE_LINE
    puts "branch name : #{branch_name}"
    puts commit_log
    puts SEPARATE_LINE

    loop do
      p "[Y/n/q]> "
      input = $stdin.gets.gsub(/\n/, '')
      next if input.nil? || input.empty?

      if %w{quit exit q}.include? input
        p 'exit'
        exit
      end

      if %w{no N n}.include? input
        break
      end

      if %w{yes Y y}.include? input
        delete_branch_name = branch_name.gsub(BRANCH_PREFIX, '')
        `git push origin :#{delete_branch_name}`
        break
      end
    end
  end
end

( ^ω^) こんなもの作る時間が勿体無いような・・・

とりあえず言いたいこと


登録数2倍で、ブランチ数も2倍に増えるので開発やリリースサイクルがいい感じに回っていて嬉しいね

とはいえ・・・

マージ済み等で不要になったブランチは削除しましょう!!

明日は


ウィザードである@thermesさんです。

よろしくお願いしますm(_ _)m

21
14
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
21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?