flog (4117B) - raw


      1 #!/usr/bin/env zsh
      2 
      3 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
      4 0="${${(M)0:#/*}:-$PWD/$0}"
      5 
      6 # Desc: git log interactive viewer
      7 #
      8 # @params
      9 # Globals:
     10 #   ${mydir}: current dir of the script
     11 #   ${selected_action}: action to take on the selected commit
     12 #   ${selected_commit}: user selected commit
     13 #   ${confirm}: confirm status of user
     14 # Arguments:
     15 #   -h|--help: display help message
     16 #   -r|--revert: revert the selected commit
     17 #   -R|--reset: reset HEAD back to the selected commit
     18 #   -e|--edit: edit commmit (interactive rebase)
     19 #   -c|--checkout: checkout selected commmit
     20 #   -y|--yes: confirm action by default and skip confirmation
     21 
     22 emulate -LR zsh
     23 setopt warncreateglobal noshortloops
     24 
     25 local mydir; mydir=${0:h:A}
     26 builtin source ${mydir}/fgit_helper
     27 
     28 function usage() {
     29   builtin print -P -- "\
     30 %F{1}%BUsage%b%f:
     31   %F{2}flog%f [%F{13}-h%f] [%F{13}-r%f] [%F{13}-R%f] [%F{13}-e%f] [%F{13}-c%f] [%F{13}-y%f] ...
     32 
     33 Interactive log viewer with action menu.
     34 Action menu contains options including revert|reset|edit|checkout|exit.
     35 
     36 %F{4}Default%f: list all commits and prompt a menu to select action to perform.
     37 
     38 %F{1}%BOptions%f%b:
     39   %F{13}-h%f, %F{13}--help%f     Show this help message and exit
     40   %F{13}-r%f, %F{13}--revert%f   Revert the selected commit and skip action menu
     41   %F{13}-R%f, %F{13}--reset%f    Reset HEAD back to selected commit and skip action menu
     42   %F{13}-e%f, %F{13}--edit%f     Edit selected commit through interactive rebase and skip action menu
     43   %F{13}-c%f, %F{13}--checkout%f Checkout selected commit and skip action menu
     44   %F{13}-y%f, %F{13}--yes%f      Acknowledge all actions that will be taken and skip confirmation"
     45 }
     46 
     47 #######################################
     48 # draw action menu for selected commit
     49 # Arguments:
     50 #   $1: selected commit hash, used to display commit message in fzf header
     51 #   $2: selected action, if selected, skip menu, return action
     52 # Outputs:
     53 #   ${selected_action}: user selected action
     54 #######################################
     55 function draw_menu() {
     56   local selected_commit="$1"
     57   local selected_action="$2"
     58   local menu header message
     59   [[ -n "$selected_action" ]] && {
     60     builtin print -r -- "$selected_action"
     61   } || {
     62     menu="revert: revert the selected commit\n"
     63     menu="${menu}reset: reset HEAD to the selected commit using --mixed flag\n"
     64     menu="${menu}edit: edit selected commit through interactive rebase\n"
     65     menu="${menu}checkout: checkout the selected commit\n"
     66     menu="${menu}exit: quit flog"
     67     message=$(
     68       command git log \
     69         --format=%B -n 1 "$selected_commit"
     70     )
     71     header="commit $selected_commit: $message"
     72     selected_action=$(print -- "$menu" \
     73       | fzf --no-multi --header="$header" \
     74       | command awk -F ":" '{
     75           print $1
     76         }'
     77     )
     78     builtin print -r -- "$selected_action"
     79   }
     80 }
     81 
     82 while (( $# )) {
     83   case "$1" in
     84     (-r|--revert)   selected_action="revert";   shift ;;
     85     (-R|--reset)    selected_action="reset";    shift ;;
     86     (-e|--edit)     selected_action="edit";     shift ;;
     87     (-c|--checkout) selected_action="checkout"; shift ;;
     88     (-y|--yes)      confirm='y';                shift ;;
     89     (-h|--help)     usage && exit 0 ;;
     90     (*)             print::error "Invalid option: $1" &&   { usage; exit 1 } ;;
     91   esac
     92 }
     93 
     94 while :; do
     95   selected_commit=$(get_commit)
     96   [[ -z "$selected_commit" ]] && exit 1
     97   selected_action=$(draw_menu "${selected_commit}" "${selected_action}")
     98   [[ -n "$selected_action" ]] && break
     99 done
    100 
    101 if [[ "${selected_action}" != 'exit' ]]; then
    102   if [[ "${selected_action}" == "reset" ]] && [[ -z "${confirm}" ]]; then
    103     print -P -- "(%F{3}dryrun%f) reset HEAD to $selected_commit"
    104   elif [[ -z "$confirm" ]]; then
    105     print -P -- "(%F{3}dryrun%f) ${selected_action} ${selected_commit}"
    106   fi
    107 
    108   [[ -z "$confirm" ]] && confirm=$(get_confirmation)
    109   [[ "$confirm" != y ]] && exit 1
    110   notify-send 'past'
    111 fi
    112 
    113 case "$selected_action" {
    114   (revert) git revert "${selected_commit}" ;;
    115   (reset) git reset "${selected_commit}" ;;
    116   (edit) git rebase -i "${selected_commit}"~ ;;
    117   (checkout) git checkout "${selected_commit}" ;;
    118   (exit) exit 0 ;;
    119   (*) exit 1 ;;
    120 }