├── LICENSE ├── Makefile ├── README.md ├── git-recall └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Berrahal Walid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | BINPREFIX ?= "$(PREFIX)/bin" 3 | 4 | LIB=git-recall 5 | 6 | .PHONY: all install uninstall 7 | 8 | all: 9 | @echo "usage: make install" 10 | @echo " make uninstall" 11 | 12 | install: 13 | mkdir -p $(BINPREFIX) 14 | install -m 0755 $(LIB) $(BINPREFIX) 15 | 16 | uninstall: 17 | test -d $(BINPREFIX) && \ 18 | cd $(BINPREFIX) && \ 19 | rm -f $(LIB) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # git-recall 2 | 3 | > Simple and handy tool to easily recall what you've done 4 | 5 | ![git recall](http://imgur.com/zuw2LqW.gif) 6 | 7 | ## Purpose 8 | 9 | `git-recall` is a simple tool that allows you to easily go through your commits and 10 | check what you or other contributors in your team did. It doesn't aim to be a replacement for the 11 | `git log` command, but just to be a convenient way to recall what you've done from your terminal. 12 | 13 | 14 | ## Usage 15 | 16 | ```sh 17 | $ git recall [-a ] 18 | [-d ] 19 | [-b ] 20 | [-p ] 21 | [-f] 22 | [-h] 23 | [-v] 24 | ``` 25 | 26 | ##### Options description: 27 | 28 | - `-a` - Restrict search for a specific user (use -a "all" for all users) 29 | - `-d` - Display commits for the last n days 30 | - `-b` - Specify branch to display commits from 31 | - `-p` - Specify path/s or file/s to display commits from 32 | - `-f` - Fetch the latest changes 33 | - `-h` - Show help screen 34 | - `-v` - Show version 35 | 36 | ##### How to use: 37 | 38 | Once the commits are displayed, you can use either the `arrow keys` or `j/k` to switch between commits, 39 | press `TAB` or `e` to `expand/reduce` the commit's diff or `q` to quit. 40 | 41 | ##### Limitations: 42 | 43 | when the number of lines between the commits list and a commit's diff is higher than the current terminal session's number of lines, 44 | the result will be displayed using the [`less`](http://www.tutorialspoint.com/unix_commands/less.htm) program which will open the diff in a separate screen. 45 | You can still use either `TAB` or `q` to return to the commits list. 46 | 47 | ## Examples 48 | 49 | ```sh 50 | $ git recall 51 | # By default (without options), the command will display commits from yesterday and 52 | # for the current user. 53 | ``` 54 | 55 | 56 | ```sh 57 | $ git recall -d 5 -a "Doge" 58 | # The command will show all Doge's commits from 5 days ago. 59 | 60 | $ git recall -d 5 -a "all" 61 | # The command will show commits of all contributors from 5 days ago. 62 | ``` 63 | 64 | 65 | ```sh 66 | $ git recall -f 67 | # Fetch commits beforehand. 68 | ``` 69 | 70 | ## Installation 71 | 72 | ##### Without using tools 73 | 74 | You can install it by simply copying the `git-recall` script into any existing path 75 | (e.g. `/usr/local/bin`) or create your own directory and add it to the `PATH` variable. 76 | 77 | Make sure to run `chmod +x /usr/local/bin/git-recall` or the directory in which you copied it to. 78 | 79 | ##### Using NPM 80 | Use `npm` to install the project. 81 | 82 | ```sh 83 | npm install --global git-recall 84 | ``` 85 | ##### Manual install 86 | Clone the project and install it using make install. 87 | 88 | ```sh 89 | $ git clone https://github.com/Fakerr/git-recall.git 90 | $ cd git-recall 91 | $ sudo make install 92 | ``` 93 | ## Requirements 94 | - OS: Linux or OSX 95 | - Bash 4.3 or more 96 | - Tools: git, less, sed 97 | 98 | ##### Optional Requirements 99 | - For a better UX, it's recommended to have installed the `lesskey` program. 100 | 101 | ## Contribution 102 | Pull requests are welcome, along with any feedback or ideas. 103 | 104 | 105 | ## License 106 | 107 | MIT 108 | -------------------------------------------------------------------------------- /git-recall: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | # usage info 5 | usage() { 6 | cat </dev/null; then 68 | echo "abort: not a git repository." 1>&2 69 | exit 1 70 | fi 71 | 72 | # Parse options 73 | while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do 74 | case $1 in 75 | -v | --version ) 76 | echo "$VERSION" 77 | exit 78 | ;; 79 | -d | --date ) 80 | SINCE="$2 days ago" 81 | shift; 82 | ;; 83 | -a | --author ) 84 | AUTHOR="$2" 85 | shift 86 | ;; 87 | -f | --fetch ) 88 | FETCH=true 89 | ;; 90 | -h | --help ) 91 | usage 92 | exit 93 | ;; 94 | -b | --branch ) 95 | BRANCH="$2" 96 | shift 97 | ;; 98 | -p | --path ) 99 | SEARCH_PATH="$2" 100 | shift 101 | ;; 102 | * ) 103 | echo "abort: unknown argument" 1>&2 104 | exit 1 105 | esac 106 | shift 107 | done 108 | if [[ "$1" == "--" ]]; then shift; fi 109 | 110 | # Enable colors if supported by terminal. 111 | if [[ -t 1 ]] && [[ -n "$TERM" ]] && which tput &>/dev/null && tput colors &>/dev/null; then 112 | ncolors=$(tput colors) 113 | if [[ -n "$ncolors" ]] && [[ "$ncolors" -ge 8 ]] ; then 114 | colored 115 | else 116 | uncolored 117 | fi 118 | else 119 | uncolored 120 | fi 121 | 122 | # Set AUTHOR to current user if no param passed or display for all users if param equal to "all". 123 | if [[ ! -n $AUTHOR ]]; then 124 | AUTHOR=$(git config user.name 2>/dev/null) 125 | elif [[ $AUTHOR = "all" ]]; then 126 | AUTHOR=".*" 127 | fi 128 | 129 | # Fetch changes before. 130 | if [[ $FETCH == true ]]; then 131 | echo "${GREEN}Fetching changes...${NORMAL}" 132 | git fetch --all &> /dev/null 133 | tput cuu1 134 | clear_screen 135 | fi 136 | 137 | # Log template. 138 | GIT_FORMAT="%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" 139 | 140 | # Log command. 141 | GIT_LOG="git log --pretty=format:'${GIT_FORMAT}' 142 | --author \"$AUTHOR\" 143 | --since \"$SINCE\" --abbrev-commit --no-merges $BRANCH $SEARCH_PATH" 144 | 145 | # Change temporary the IFS to store GIT_LOG's output into an array. 146 | IFS=$'\n' 147 | COMMITS=($(eval ${GIT_LOG} 2>/dev/null)) 148 | unset IFS 149 | 150 | NI=${#COMMITS[@]} # Total number of items. 151 | SN=$(( `tput lines` - 1 )) # Screen's number of lines. 152 | CN=$(tput cols) # Screen's number of columns. 153 | TN=$(( $NI < $((SN -1)) ? $NI : $((SN -1)))) # Number of lines that we will display. 154 | OFFSET=0 # Incremented by one each time a commit's length is higher than teminal width. 155 | 156 | # If there is no items, exit. 157 | if [[ $NI = 0 ]]; then 158 | if [[ $AUTHOR = ".*" ]]; then 159 | echo "${YELLOW}All contributors did nothing during this period.${NORMAL}" && exit 0 160 | else 161 | echo "${YELLOW}The contributor \"${AUTHOR}\" did nothing during this period.${NORMAL}" && exit 0 162 | fi 163 | fi 164 | 165 | # Check if lesskey is installed. 166 | if command -v lesskey &> /dev/null; then 167 | LESSKEY=true 168 | fi 169 | 170 | # Set correct sed command according OS's type 171 | case "$OSTYPE" in 172 | darwin*) SED_CMD="sed -E s/"$'\E'"\[([0-9]{1,2}(;[0-9]{1,2})*)?m//g" ;; 173 | *) SED_CMD="sed -r s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" ;; 174 | esac 175 | 176 | # Create array with uncolred commits (removing escape sequences using sed) 177 | for elt in "${COMMITS[@]}" 178 | do 179 | ELT="$(echo "$elt" | $SED_CMD)" # remove colors escape codes 180 | COMMITS_UNCOL+=("$ELT") 181 | done 182 | 183 | # Add +1 to OFFSET if a commit's length is bigger than the current terminal session's width. (This is to fix a redraw issue) 184 | for C in "${COMMITS_UNCOL[@]}" 185 | do 186 | if [[ ${#C} -gt $CN ]]; then 187 | OFFSET=$(( OFFSET + 1 )) 188 | fi 189 | done 190 | 191 | # Create a temporary lesskey file to change the keybindings so the user can use the TAB key to quit less. (more convenient) 192 | if [[ $LESSKEY = true ]]; then 193 | echo "\t quit" | lesskey -o /tmp/lsh_less_keys_tmp -- - &> /dev/null 194 | fi 195 | 196 | # Get commit's diff. 197 | function get_diff() { 198 | ELT="$(echo "${COMMITS_UNCOL[$CP-1]}")" 199 | DIFF_TIP=${ELT:0:7} 200 | DIFF_CMD="git show $DIFF_TIP --color=always $SEARCH_PATH" 201 | DIFF=$(eval ${DIFF_CMD} 2>/dev/null) 202 | tmp_diff="$(echo "$DIFF" | $SED_CMD)" 203 | off=$(echo "$tmp_diff" | grep -c ".\{$CN\}") # Number of lines in the diff that are longer than terminal width. 204 | DIFF_LINES_NUMBER="$(echo "$DIFF" | wc -l)" 205 | DIFF_LINES_NUMBER=$(( DIFF_LINES_NUMBER + off )) 206 | } 207 | 208 | # This function will print the diff according the commit's tip. If the diff is too long, the result will be displayed using 'less'. 209 | function print_diff() { 210 | get_diff 211 | if [[ $(( TN + DIFF_LINES_NUMBER + OFFSET )) -ge $(( `tput lines` - 1 )) ]]; then 212 | trap - INT 213 | if [[ $LESSKEY = true ]]; then 214 | echo "$DIFF" | less -r -k /tmp/lsh_less_keys_tmp 215 | else 216 | echo "$DIFF" | less -r 217 | fi 218 | trap cleanup_and_exit INT 219 | clear_screen 220 | else 221 | stop=false 222 | clear_screen 223 | for i in `seq 1 $TN` 224 | do 225 | echo -n "$NORMAL" 226 | [[ $CP == "$i" ]] && echo -n "$REVERSE" 227 | echo "${COMMITS[$i - 1]}" 228 | [[ $CP == "$i" ]] && echo "$DIFF" 229 | done 230 | # Wait for user action. 231 | while ! $stop 232 | do 233 | read -sn 1 key 234 | case "$key" in 235 | "$nl" | "$nl_1") 236 | stop=true 237 | ;; 238 | "q") 239 | stop=true 240 | END=true 241 | ;; 242 | esac 243 | done 244 | [[ $END = false ]] && tput cuu $(( TN + DIFF_LINES_NUMBER + OFFSET )) && clear_screen 245 | fi 246 | } 247 | 248 | # Calculate OFFSET to avoid bad redraw. 249 | function calculate_offset { 250 | tmp=1 251 | index=$(( SI -1 )) 252 | while [[ $tmp -lt $SN ]] 253 | do 254 | el=${COMMITS_UNCOL[$index]} 255 | if [[ ${#el} -gt $CN ]] && [[ $CP -lt $((SN -1)) ]]; then 256 | OFFSET_2=$(( OFFSET_2 + 1 )) 257 | tmp=$(( tmp + 1 )) 258 | fi 259 | tmp=$(( tmp + 1 )) 260 | index=$(( index + 1 )) 261 | done 262 | } 263 | 264 | # Reset changes made by this script before exiting 265 | function cleanup_and_exit() { 266 | # remove temporary less keybindings 267 | [[ $LESSKEY = true ]] && rm /tmp/lsh_less_keys_tmp 268 | 269 | tput cuu 1 # move cursor up one line. (remove extra line) 270 | tput cnorm # unhide cursor 271 | echo "$NORMAL" # normal colors 272 | stty "$orig_stty" > /dev/null 2>&1 273 | exit 274 | } 275 | 276 | # Catch a control-C interrupt and perform cleanup operations before exiting 277 | trap cleanup_and_exit INT 278 | 279 | { # capture stdout to stderr 280 | 281 | tput civis # hide cursor. 282 | CP=1 # current position 283 | SI=1 # index 284 | END=false # end while loop 285 | EXT=0 # Used to extend the number of lines to display. 286 | 287 | while ! $END 288 | do 289 | # When the number of item is higher than screen's number of lines, OFFSET_2 is recalculated each time we select a new item. 290 | # Set last index to print. (based on OFFSET) 291 | END_INDEX=0 # Index for the last item to display 292 | if [[ $TN == $NI ]]; then 293 | END_INDEX=$TN 294 | OFFSET_2=$OFFSET 295 | elif [[ $TN == $(( SN - 1 )) ]]; then 296 | # Calculate new OFFSET. 297 | if [[ $OFFSET != 0 ]]; then 298 | [[ $CP -lt $((SN -1)) ]] && OFFSET_2=0 299 | EXT=1 300 | calculate_offset 301 | fi 302 | END_INDEX=$(( TN + SI -1 + EXT - OFFSET_2 )) 303 | fi 304 | 305 | # Loop and echo commits 306 | for i in `seq $SI $END_INDEX` 307 | do 308 | echo -n "$NORMAL" 309 | [[ $CP == $i ]] && echo -n "$REVERSE" 310 | echo "${COMMITS[$i - 1]}" 311 | done 312 | 313 | read -sn 1 key 314 | [[ "$key" == "$ec" ]] && 315 | { 316 | read -sn 2 k2 317 | key="$key$k2" 318 | } 319 | 320 | case "$key" in 321 | "$au" | "$au_1") 322 | CP=$(( CP - 1 )) 323 | [[ $CP == 0 ]] && [[ $SI == 1 ]] && [[ $TN == $(( SN - 1 )) ]] && CP=$NI && SI=$(( NI - SN + 2 + OFFSET_2 )) 324 | [[ $CP == 0 ]] && [[ $SI == 1 ]] && [[ $TN == $NI ]] && CP=$TN 325 | [[ $CP == $(( SI - 1 )) ]] && [[ $SI != 1 ]] && SI=$(( SI - 1 )) 326 | 327 | [[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 )) 328 | [[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT )) 329 | [[ $SI != 1 ]] && clear_screen 330 | ;; 331 | "$ad" | "$ad_1") 332 | CP=$(( CP + 1 )) 333 | [[ $CP == $(( NI + 1 )) ]] && CP=1 && SI=1 334 | [[ $CP == $(( SN + SI - 1 + EXT - OFFSET_2 )) ]] && [[ $TN == $(( SN - 1 )) ]] && SI=$(( SI + 1 )) 335 | 336 | [[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 )) 337 | [[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT )) 338 | [[ $SI != 1 ]] && clear_screen 339 | [[ $SI = 1 ]] && [[ $CP = 1 ]] && clear_screen 340 | ;; 341 | "$nl" | "$nl_1") 342 | [[ $TN == $NI ]] && tput cuu $(( TN + OFFSET_2 )) 343 | [[ $TN != $NI ]] && tput cuu $(( TN + EXT )) 344 | print_diff 345 | ;; 346 | "q") 347 | si=false 348 | END=true 349 | ;; 350 | * ) 351 | tput cuu $(( TN + OFFSET_2 )) 352 | esac 353 | done 354 | 355 | cleanup_and_exit 356 | 357 | } >&2 # END capture 358 | 359 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-recall", 3 | "version": "1.2.4", 4 | "description": "Simple and convenient Git tool to easily recall what you've done", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Fakerr/git-recall.git" 12 | }, 13 | "bin": { 14 | "git-recall": "./git-recall" 15 | }, 16 | "keywords": [ 17 | "git", 18 | "log", 19 | "cli" 20 | ], 21 | "author": "Walid Berrahal", 22 | "license": "MIT", 23 | "homepage": "https://github.com/Fakerr/git-recall" 24 | } 25 | --------------------------------------------------------------------------------