デモなどで使えるGitコミットを簡単にresetし切替えるツールを作りました
私は仕事がら、人前でコード作成のデモを行う事がよくあります。その場でバリバリとライブ・コーデイング出来るとカッコ良いですが、間違えたり、コードを書くことに気を取られ説明がおろそかになったりすることも起こりがちです。
そこで説明のストーリに沿ってコード作成の過程をgitにコミットしておき、コマンドで簡単に git reset を行い、その時点でのコードを説明したり、動かしたりできるツールを作りました。
上の画像のように、このコマンドを起動するとgit logが表示され、現在のコミットが赤い色で表示されます、ここで n キーを押すと次のコミットに git reset できます。また p キーで前のコミットに git reset したり、カーソル上下キーでコミットを移動して RETURNキーでそこにgit reset できます。
このコマンドを実行すると git reset されてしまうので、 -c オプション指定で 予めファイルに全git logを書いておきます。
rubyで作ってあります、 gem 等のインストールは不要です。
#!/usr/bin/env ruby require 'io/console' GIT_LIST_PATH = "#{ENV['HOME']}/tmp/git-demo.lst" RED = "\e[31m" YELLOW = "\e[33m" BLACK = "\e[30m" FIN = "\e[0m" UP = "\e[A" DOWN = "\e[B" RETURN = "\r" def show_log_item(item, current) if current print "#{RED}#{item[0]} #{BLACK}#{item[1]}#{FIN}#{RETURN}" else print "#{YELLOW}#{item[0]} #{BLACK}#{item[1]}#{FIN}#{RETURN}" end end def show_git_log(log, current_index) log.each_with_index do |item, ix| show_log_item(item, ix == current_index) puts end end def get_current_hash IO.read("|git log --pretty=format:'%h' -1") end def find_current_hash(log, current_hash) log.find_index {|item| item[0] == current_hash} end def wait_key key = STDIN.getch if key == "\e" && STDIN.getch == "[" case STDIN.getch when "A" then "↑" when "B" then "↓" else "" end else key end end def cursor_up print UP STDOUT.flush end def cursor_down print DOWN STDOUT.flush end def set_cursor(log, current_index) (log.size - current_index).times { cursor_up } end def reset_cursor(log, current_index) (log.size - current_index).times { cursor_down } end def move_current_postion(log, index, delta) show_log_item(log[index], false) if delta > 0 if index < log.size - 1 cursor_down index += 1 end else if index > 0 cursor_up index -= 1 end end show_log_item(log[index], true) index end def get_git_log IO.readlines(GIT_LIST_PATH).map {|s| s.scan(/^(\w+) (.*)\n?/)[0]} end def put_git_log system "git log --pretty=format:'%h %s' > #{GIT_LIST_PATH}" end def git_reset_hard(log, index) system "git reset --hard #{log[index][0]}" end def main log = get_git_log current_index = find_current_hash(log, get_current_hash) show_git_log(log, current_index) set_cursor(log, current_index) do_reset = false while true case wait_key when 'n' current_index = move_current_postion(log, current_index, - 1) do_reset = true break when 'p' current_index = move_current_postion(log, current_index, + 1) do_reset = true break when "\r", "\n" do_reset = true break when "\C-c", "q" break when "↑" current_index = move_current_postion(log, current_index, - 1) when "↓" current_index = move_current_postion(log, current_index, + 1) end end reset_cursor(log, current_index) git_reset_hard(log, current_index) if do_reset end if ARGV.size > 0 if ARGV[0] == "-c" put_git_log puts "#{GIT_LIST_PATH} created." else puts "#{$0} -c" puts " or " puts "#{$0} " puts " n: git reset --hard Next commit" puts " p: git reset --hard Pervious commit" puts " ↑ ↓: seek commit" puts " RETURN: git reset --hard Current commit" puts " q: quit" end else main end