Gitgo or: How I learned to live with VCS

UPDATE: Only keeping thins post around as a reminder of how far I've come.

UPDATE: This is a bit outdated now, as I have added some features and polished up the code a bit. I will post the update after the migration to Ghost is done.

UPDATE: Changed order of main to try to avoid push conflicts
UPDATE: Multi-directory bug squashed! (I think)
UPDATE: Found a bug that breaks the script if you are deep in a multi-directory Git repo and call this script. (All of my repos are currently only one directory deep, so it might be a bit before I squash this bug...)


Personally, I've never been one to use a version control system. Even during university, when it was a 'requirement' to use such a system, I opted out and used either no version control at all or Google Docs.

I didn't know what I was missing.

I have started using Git in my professional career, and I have to say I'm hooked. I'm just not overly fond of one aspect of Git. The commands.

Sure, after using it day in and day out it became less of a chore and more of a required familiarity, but I still wanted a better way so I decided to write a script in bash to help streamline my interactions with git.

#!/bin/bash - 
#===============================================================================
#
#          FILE: gitgo.rewrite.sh
# 
#         USAGE: ./gitgo.rewrite.sh 
# 
#   DESCRIPTION: 
# 
#       OPTIONS: ---
#  REQUIREMENTS: ---
#          BUGS: ---
#         NOTES: ---
#  ORGANIZATION: 
#       CREATED: 01/25/2013 01:46:29 PM CST
#      REVISION:  ---
#===============================================================================
#-------------------------------------------------------------------------------
#  Set Colors for pretty output
#-------------------------------------------------------------------------------
txtred=$(tput setaf 1) # Red
txtgrn=$(tput setaf 2) # Green
txtylw=$(tput setaf 3) # Yellow
txtwht=$(tput setaf 7) # White
txtrst=$(tput sgr0) # Text reset.

#-------------------------------------------------------------------------------
#  Trap Control-C and react by resetting HEAD for git
#-------------------------------------------------------------------------------
	trap control_c SIGINT
	control_c(){
		  echo -en "\n*** Ctrl^c caught.  Exiting ***\n"
		    git reset HEAD;
		      exit 1
	}

#-------------------------------------------------------------------------------
# Main Case Statement for setting flags 
#-------------------------------------------------------------------------------
flags=$1
case "$flag" in
	-y)
		answer=$flag;;
	-h)
		echo "Help Documentation HERE";;
	"")
		echo "No Flags" > /dev/null ;;
	*)
		echo "Invalid Flag";;
esac

#-------------------------------------------------------------------------------
#  Check if you are in a Git Reop, and fail/exit if not
#-------------------------------------------------------------------------------
	isGit(){
		check_repo=`git rev-parse --is-inside-work-tree`
		if [ "$check_repo" == "true" ]
			then
				git_base_dir=`git rev-parse --show-toplevel`
				cd $git_base_dir
				main
			else
				echo "Not a git repository!"
				exit
		fi
	}

	gitLists(){
	#-------------------------------------------------------------------------------
	# Set Internal Field Seperator to NewLine 
	#-------------------------------------------------------------------------------
		IFS=$'\n'
	#-------------------------------------------------------------------------------
	#  Get list of untracked files
	#-------------------------------------------------------------------------------
		N=0
		for i in $(git ls-files -o) ; do
			#j="${git_base_dir}/$i"
			untracked[$N]="$i"
			let "N= $N + 1"
		done

	#-------------------------------------------------------------------------------
	#  Get list of modified files
	#-------------------------------------------------------------------------------
		N=0
		for i in $(git diff --name-only --diff-filter=M) ; do
			#j=`basename $i`
			#modified[$N]="$j"
			j="${git_base_dir}/$i"
			modified[$N]="$j"
			let "N= $N + 1"
		done

	#-------------------------------------------------------------------------------
	#  Get list of renamed files
	#-------------------------------------------------------------------------------
		N=0
		for i in $(git diff --name-only --diff-filter=R) ; do
			#j=`basename $i`
			#modified[$N]="$j"
			j="${git_base_dir}/$i"
			renamed[$N]="$j"
			let "N= $N + 1"
		done
	#-------------------------------------------------------------------------------
	#  Get list of delted files
	#-------------------------------------------------------------------------------
		N=0
		for i in $(git ls-files --deleted) ; do
			deleted[$N]="$i"
			let "N= $N + 1"
		done

	}

	gitStage(){
	#-------------------------------------------------------------------------------
	#  Check for array lengths of 0
	#-------------------------------------------------------------------------------
		length_untracked=${#untracked[@]}
		length_modified=${#modified[@]}
		length_renamed=${#renamed[@]}
		length_deleted=${#deleted[@]}

		echo "$txtwht************** Changes **************$txtrst"
		if [ $length_untracked -eq 0 ]
			then
				echo "$txtylw No new or untracked files found $txtrst"
			else
				for i in "${untracked[@]}"
				do
					echo -e "$txtgrn Adding new file: $i $txtrst"
					git add $i
				done
		fi

		if [ $length_modified -eq 0 ]
			then
				echo "$txtylw No modified files found $txtrst"
			else
				for i in "${modified[@]}"
				do
					echo -e "$txtgrn Updating modified file: $i $txtrst"
					git add $i
				done
		fi

		if [ $length_renamed -eq 0 ]
			then
				echo "$txtylw No renamed files found $txtrst"
			else
				for i in "${renamed[@]}"
				do
					echo -e "$txtgrn Adding renamed file: $i $txtrst"
					git add $i
				done
		fi

		if [ $length_deleted -eq 0 ]
			then
				echo "$txtylw No deleted files found $txtrst"
			else
				for i in "${deleted[@]}"
				do
					echo "$txtred Removing deleted file: $i $txtrst"
					git rm $i
				done
		fi
		echo "$txtwht*************************************$txtrst"
	}

	gitGo(){
	#-------------------------------------------------------------------------------
	#  Ask to commit changes
	#-------------------------------------------------------------------------------

		if [ $length_untracked -eq 0 ] && [ $length_modified -eq 0 ] && [ $length_renamed -eq 0 ] && [ $length_deleted -eq 0 ]
		then
			echo "No Changes at all.  No Need to Commit"
			exit
		fi
		if [[ $flags == "-y" ]]
		then
			answer="yes"
		else
			echo -e "\nCommit Changes?  (Yes/No)"
			read -e answer
		fi
		case "$answer" in
			[yY] | [yY][Ee][Ss])
				echo "Comments?  ENTER THEM NOW!!!";
				read -e comments;
				if [ "$comments" == "" ]
				then
					echo "Cannot commit without comments, ya turkey!!!"
					git reset HEAD
					exit 0
				fi
				git commit -m "$comments";
				git push;
				exit 0;;
			[nN] | [nN][oO])
				git reset HEAD;
				exit 0;;
			*)
				echo Invalid option selected;
				git reset HEAD;;
		esac
	}

	#-------------------------------------------------------------------------------
	#  Main Function (calls err-body else)
	#-------------------------------------------------------------------------------
	main(){
	gitLists
	gitStage
	git pull
	gitGo
	}

#-------------------------------------------------------------------------------
#  Kick this pig
#-------------------------------------------------------------------------------
isGit

I'll be the first to admit that this has (in one way or another) already been done, and probably better too, but I wanted to create my own. I'm sure I'll keep adding to it, polishing it, and making sure I've accounted for most (if not all) edge cases or errors, and of course all the while using Git to keep track of the changes and GitLab to have a more visually pleasing view into it all.

Mastodon