天天看點

Git需求: 快速切換項目目錄

不知道你有沒有和我一樣的需求,平常會負責幾個項目的開發,又習慣使用git指令行管理開發代碼。每次要送出代碼,都要找到項目的目錄,然後打開一個指令行視窗,或者頻繁切換目錄到想要的目錄,到最後,你的工作列可能有N個git指令行視窗,雖然操作也沒那麼麻煩,但是做重複的事總是很不舒服。

是以簡單的寫了個bash腳本,友善切換目錄,雖然簡單,但是用着還覺得挺友善的,有興趣的可以看下,https://github.com/eussi/SimpleScripts/tree/master/gitTools。

我用的電腦是windows系統,在我電腦上開發環境是這樣的,自己有個工作目錄,負責的項目都放在這個目錄下面,每個項目有他自己的辨別。假設這個目錄是APP,下面A,B,C等項目,目錄層級可能如下:

./APP
./APP/aaaa
./APP/aaaa/aaaa
./APP/aaaa/aaaa/app.properties
./APP/bbbbb
./APP/bbbbb/app.properties
./APP/cccccccc
./APP/cccccccc/app.properties
./APP/dddd
           

辨別每個項目資訊的檔案是app.properties,檔案裡内容可能包含appid等應用的資料,檔案内容可能是這樣:

appid=100012345
bb=e
cc=3
           

當然檔案app.properties可能不存在,檔案中的appid也可能不存在。

#1

剛剛開始想法是這樣的,需要有一個指令,這個指令不能很長,傳入工作目錄,這個指令會将所有項目以清單的形式展示出來,然後自己輸入想進入哪個項目目錄,就可以立刻進入,并且這個指令可以在電腦的任何一個目錄下執行。

這樣我随時打開git,随時切換目錄,即使在一個項目的目錄中,也可以切換到另外一個項目的目錄下。

‘很短的指令’可以通過alias别名來實作,邏輯可以通過bash腳本來實作,切換目前所在目錄,可以通過

source或.

執行bash腳本來實作。

于是有了下面一個版本的腳本

list_v1.sh

#!/bin/bash
#program:
#  Switch application directory
#author:
#  xuemingwang 2020-11-21
#usage:
#  source list_v1.sh dir  

#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"

#print func
printMsg() {
    mesg=$1
    head=$2
    tail=$3
    echo -e "${head}${mesg}${tail}"
}


ROOT_DIR=$1
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########


#main
main() {
    echo ""
    echo "******************************"
    printMsg "APP_DIR:"$ROOT_DIR $WHITE $BOLD
    echo "******************************"
    #get list
    echo -e "\nLIST:"
    index=0
    for var in `ls $ROOT_DIR`
    do
	subDir=$ROOT_DIR"/"$var
	if [ ! -d $subDir ]; then
            continue
		
	fi
	#find appid
	appfilePath=`find $subDir -name $APP_FILENAME`

        if [ -n "$appfilePath" ]; then
	    app_arr[index]="["$index"]. "`sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $appfilePath`" "$var
        else
	    app_arr[index]="["$index"]. "$NULL_APPID" "$var
	fi
	#echo "${app_arr[index]}"
	index=$((index+1))
    done
    #print list
    for ((k=0; k<$index; k++))
    do
        printMsg "${app_arr[$k]}" $WHITE $BOLD
    done
    #choose where to to
    echo "******************************"
    echo -e "\nOPTIONS:"
    while true
    do
	echo Please choose where to go or exit by Q:
        read input
	#echo $input
	if [ "Q" = "$input" -o "q" = "$input" ]; then
	    echo "exit"
	    #exit 0
	    break
	fi
	find=0
	for ((k=0; k<$index; k++))
	do
            echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
	    if [ $? -eq 0 ]; then
                #find
		find=1
		retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
                cd $ROOT_DIR"/"$retDir 
		break
	    fi
        done
	#for remove exit
	if [ "$find" = "1" ]; then
	    break
	fi
	echo -e "Please enter the string contained in the list.\n"
    done
}


if [ ! $# -eq 1 ]; then
    echo Usage: with one parameters, the root of application directory.
    #exit -1 #Exit cannot be used in order to switch execution directories
else
    if [ ! -d $ROOT_DIR ]; then
        echo $ROOT_DIR "is not exist."
        #exit -1  #Exit cannot be used in order to switch execution directories
    else
        if [ ! -d $ROOT_DIR ]; then
	    echo $ROOT_DIR "is not exist."
	else
	    main
	fi
    fi
fi
           

大緻邏輯是周遊工作目錄,并通過find指令查找辨別檔案app.properties,再在檔案中提取出appid對應的值,通過清單的形式展示出來。

此時将腳本加入path路徑中,我是在home目錄裡建立了bin目錄,即C:\Users\wangx\bin,腳本放在該目錄下,然後打開bash指令行通過alias設定指令别名,如下:

$ alias cmds='. list_v1.sh /C/Users/wangx/Desktop/APP'
           

上面指令用

cmds

(cmd switch)代替

. list_v1.sh /C/Users/wangx/Desktop/APP

指令,注意運作該指令的時候我使用的

.

或者

source

, 因為要切換目前執行的目錄,使用

sh

隻能切換子shell的目錄,對目前目錄切換無效。

這個時候便可以友善切換目錄了,操作如下:

$ cmds

******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************

LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************

OPTIONS:
Please choose where to go or exit by Q:
16789

$ pwd
/C/Users/wangx/Desktop/APP/bbbbb

$ cmds

******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************

LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************

OPTIONS:
Please choose where to go or exit by Q:
ddd

$ pwd
/C/Users/wangx/Desktop/APP/dddd

$ cmds

******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************

LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************

OPTIONS:
Please choose where to go or exit by Q:
q
exit

           

這樣看起來已經完全滿足需求了,于是拿到自己電腦上開始使用了,一用就尴尬了,工作目錄下一二十個應用,每次要切換目錄時,輸入指令,展示出來實在是太慢了,還不如我之前直接手動切換。

#2

一方面git的bash指令行執行linux上的一些指令速度确實慢很多,另一方面懷疑自己使用find指令查找appid效率可能太低了,畢竟一個項目中檔案可能很多,查找檔案數量多起來将會耗時很高,兩方面一起算下來,腳本執行速度慢也是理所當然的吧。于是想着先優化下find指令吧。

一般在一個公司,所有的項目的appid存放的位置一般是一樣的,比如都在應用根目錄下有個app.properties,或者在第二層目錄下,是以就沒必要通過find搜尋一遍了,采用直接讀取這兩個位置的app.properties,拿到appid,拿不到就結束。即:

getAppId() {
    rootDir=$1
    filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
    #src\main\resources\META-INF\app.properties
    if [ -f "$filePath" ]; then
        echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
    else
        find=0
        for var in `ls $ROOT_DIR'/'$rootDir`
        do
            secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
	    #echo $secondFilePath
	    if [ -f "$secondFilePath" ]; then
                echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
                find=1
		break  #At most two layer
            fi
	done
	if [ $find = "0" ]; then
            echo $NULL_APPID
        fi
    fi
}
           

于是有了第二版腳本

list_v2.sh

:

#!/bin/bash
#program:
#  Switch application directory
#author:
#  xuemingwang 2020-11-21
#usage:
#  source list.sh dir  

#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"

#print func
printMsg() {
    mesg=$1
    head=$2
    tail=$3
    echo -e "${head}${mesg}${tail}"
}


ROOT_DIR=$1
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########

getAppId() {
    rootDir=$1
    filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
    #src\main\resources\META-INF\app.properties
    if [ -f "$filePath" ]; then
        echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
    else
        find=0
        for var in `ls $ROOT_DIR'/'$rootDir`
        do
            secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
	    #echo $secondFilePath
	    if [ -f "$secondFilePath" ]; then
                echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
                find=1
		break  #At most two layer
            fi
	done
	if [ $find = "0" ]; then
            echo $NULL_APPID
        fi
    fi
}


#main
main() {
    echo ""
    echo "******************************"
    printMsg "APP_DIR:$ROOT_DIR" $WHITE $BOLD
    echo "******************************"
    #get list
    echo -e "\nLIST:"
    index=0
    for var in `ls $ROOT_DIR`
    do
	subDir=$ROOT_DIR"/"$var
	if [ ! -d $subDir ]; then
            continue
		
	fi
	#find appid
	#appfilePath=`find $subDir \( -path "./.git" -o -path ".git" -o -path "./.idea" \) -prune -o -name $APP_FILENAME`
	appId=`getAppId $var`

        #if [ -n "$appfilePath" ]; then
	#    app_arr[index]="["$index"]. "`sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $appfilePath`" "$var
        #else
	#    app_arr[index]="["$index"]. "$NULL_APPID" "$var
	#fi

	app_arr[index]=`printf "[%02s]. %-9s %s" "$index" "$appId" "$var"`
        printMsg "${app_arr[index]}" $WHITE $BOLD
	
	#echo "${app_arr[index]}"
	index=$((index+1))
    done
    #print list
    #for ((k=0; k<$index; k++))
    #do
    #    printMsg "${app_arr[$k]}" $WHITE $BOLD
    #done
    #choose where to to
    echo "******************************"
    echo -e "\nOPTIONS:"
    while true
    do
	echo Please choose where to go or exit by Q:
        read input
	#echo $input
	if [ "Q" = "$input" -o "q" = "$input" ]; then
	    echo "exit"
	    #exit 0
	    break
	fi
	find=0
	for ((k=0; k<$index; k++))
	do
            echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
	    if [ $? -eq 0 ]; then
                #find
		find=1
		retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
                cd $ROOT_DIR"/"$retDir
		echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
		break
	    fi
        done
	#for remove exit
	if [ "$find" = "1" ]; then
	    break
	fi
	echo -e "Please enter the string contained in the list.\n"
    done
}


if [ ! $# -eq 1 ]; then
    echo Usage: with one parameters, the root of application directory.
    #exit -1 #Exit cannot be used in order to switch execution directories
else
    if [ ! -d $ROOT_DIR ]; then
        echo $ROOT_DIR "is not exist."
        #exit -1  #Exit cannot be used in order to switch execution directories
    else
        if [ ! -d $ROOT_DIR ]; then
	    echo $ROOT_DIR "is not exist."
	else
	    main
	fi
    fi
fi
           

同樣将腳本設定放到path目錄下,然後設定别名

$ alias cmds='. list_v2.sh /C/Users/wangx/Desktop/APP'
           

運作效果如下:

$ cmds

******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************

LIST:
[00]. 100012345 aaaa/
[01]. 100016789 bbbbb/
[02]. 200016789 cccccccc/
[03]. ######### dddd/
******************************

OPTIONS:
Please choose where to go or exit by Q:
bbb

CURRENT: /C/Users/wangx/Desktop/APP/bbbbb/

$ pwd
/C/Users/wangx/Desktop/APP/bbbbb

$ cmds

******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************

LIST:
[00]. 100012345 aaaa/
[01]. 100016789 bbbbb/
[02]. 200016789 cccccccc/
[03]. ######### dddd/
******************************

OPTIONS:
Please choose where to go or exit by Q:
q
exit

$ pwd
/C/Users/wangx/Desktop/APP/bbbbb
           

運作沒問題,拿到自己電腦上測試,同樣的問題,還是運作的太慢,看來指令不是主要的影響因素,之後也嘗試網上查找優化git執行指令的速度,但是效果都不大。上面的方案看來并不能解決問題。

#3

因為git執行腳本始終速度都很慢,隻能通過其他方法來實作自己的需求了。

再細想想,由于自己負責開發的項目數量和名稱變動并不是很大,我可以将資訊先緩存起來,等到資料變動時,我再進行更新,并且我也沒必要每次列出來之後選擇要進入的目錄,我還想要一個立刻進入某目錄的功能,切換速度更快更友善。

于是想了另外一個方案,修改腳本,傳入不同的參數,實作三個功能:

  • 将項目資料緩存到某個檔案中
  • 讀取緩存檔案,展示資料,選擇進入目錄
  • 讀取緩存檔案,直接進入目錄

這樣,直接讀取一個緩存檔案,然後選擇進入某個項目的目錄,不至于執行也是龜速吧。于是産生了下面的腳本

list_v3.sh

:

#!/bin/bash
#program:
#  Switch application directory
#author:
#  xuemingwang 2020-11-21
#usage:
#  source list_v3.sh dir -g
#  source list_v3.sh dir -l
#  source list_v3.sh dir -s str

#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"

#params
[email protected]
INPUT_PARAMS_NUM=$#

#variable
TEMP_FILE=/.list_v3
ROOT_DIR=$1
FLAG=$2
FLAG_VALUE=$3
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########

#print func
printMsg() {
    mesg=$1
    head=$2
    tail=$3
    echo -e "${head}${mesg}${tail}"
}

getAppId() {
    rootDir=$1
    filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
    #src\main\resources\META-INF\app.properties
    if [ -f "$filePath" ]; then
        echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
    else
        find=0
        for var in `ls $ROOT_DIR'/'$rootDir`
        do
            secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
	    #echo $secondFilePath
	    if [ -f "$secondFilePath" ]; then
                echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
                find=1
		break  #At most two layer
            fi
	done
	if [ $find = "0" ]; then
            echo $NULL_APPID
        fi
    fi
}

#Generate temporary cache
generate() {
    tempFile=$TEMP$TEMP_FILE
	> $tempFile
	index=0
    for var in `ls $ROOT_DIR`
    do
	    subDir=$ROOT_DIR"/"$var
	    if [ ! -d $subDir ]; then
            continue
	    fi
	    appId=`getAppId $var`
	    printf "%-9s %s\n" "$appId" "$var" >> $tempFile
	    index=$((index+1))
    done

}

#List the options
list() {
    tempFile=$TEMP$TEMP_FILE
	if [ ! -f $tempFile ]; then
	    echo "err: need a temporary document."
	else
	    echo -e "\nLIST:"
	    index=0
        while read line
	    do
		    app_arr[index]=`printf "%02s %s" "$index" "$line"`
		    echo ${app_arr[index]}
		    index=$((index+1))
	    done < $tempFile
		echo -e "\nOPTIONS:"
		while true
        do
	        echo Please choose where to go or exit by Q:
            read input
	        #echo $input
	        if [ "Q" = "$input" -o "q" = "$input" ]; then
	            echo "exit"
	            #exit 0
	            break
	        fi
	        find=0
	        for ((k=0; k<$index; k++))
	        do
                echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
	            if [ $? -eq 0 ]; then
                    #find
		            find=1
		            retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
                    cd $ROOT_DIR"/"$retDir
		            echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
		            break
	            fi
            done
	        #for remove exit
	        if [ "$find" = "1" ]; then
	            break
	        fi
	        echo -e "Please enter the string contained in the list.\n"
        done
	fi
}

#Switch directory
switch(){
    tempFile=$TEMP$TEMP_FILE
	if [ ! -f $tempFile ]; then
	    echo "err: need a temporary document."
	else
	    find=0
        while read line
	    do
		    echo "$line" | grep "$FLAG_VALUE" > /dev/null 2>&1
			if [ $? -eq 0 ]; then
				#find
				find=1
				retDir=`echo ${line} | awk '{print $2}'`
				cd $ROOT_DIR"/"$retDir
				echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
				break
			fi
	    done < $tempFile
		if [ "$find" != "1" ]; then
	        echo -e "No such app dir.\n"
	    fi
	    
	fi
}


#main
main() {
	if [[ $FLAG != -* ]]; then
		FLAG_VALUE=$FLAG
		FLAG="-s" #default value -s
	fi
	
	case $FLAG in
	    "-l")
		    list
			;;
		"-g")
		    generate
			;;
		"-s")
		    switch
			;;
		*)
		    echo "Unsupported commands."
		;;
	esac
}

#basic check
if [ $# -gt 3 ]; then
    echo Usage: Up to three parameters, root_dir, flag and the value.
    #exit -1 #Exit cannot be used in order to switch execution directories
else
    if [ ! -d $ROOT_DIR ]; then
        echo $ROOT_DIR "is not exist."
        #exit -1  #Exit cannot be used in order to switch execution directories
    else
        if [ ! -d $ROOT_DIR ]; then
	        echo $ROOT_DIR "is not exist."
	    else
	        main
	    fi
    fi
fi
           

同樣将腳本設定放到path目錄下,然後設定三個功能的别名

$ alias cmdg='sh list_v3.sh /C/Users/wangx/Desktop/APP -g'
$ alias cmdl='. list_v3.sh /C/Users/wangx/Desktop/APP -l'
$ alias cmds='. list_v3.sh /C/Users/wangx/Desktop/APP -s'

           

執行效果如下:

$ cmdg

$ cmdl

LIST:
00 100012345 aaaa/
01 100016789 bbbbb/
02 200016789 cccccccc/
03 ######### dddd/

OPTIONS:
Please choose where to go or exit by Q:
bb

CURRENT: /C/Users/wangx/Desktop/APP/bbbbb/

$ cmds aaa

CURRENT: /C/Users/wangx/Desktop/APP/aaaa/

$ cmds 2000

CURRENT: /C/Users/wangx/Desktop/APP/cccccccc/

$ pwd
/C/Users/wangx/Desktop/APP/cccccccc
           

其中cmdg生成檔案内容如下:

$ cat $TEMP/.list_v3
100012345 aaaa/
100016789 bbbbb/
200016789 cccccccc/
######### dddd/
           

如果你往工作目錄裡添加了新的項目,運作一下

cmdg

更新下這個檔案,然後又可以使用

cmdl

cmds

切換目錄了,速度完全能達到需求。

終于算是搞定了。

使用了大概一個月了,确實用着比之前舒服多了。

另外,如果你有多個工作目錄,這個腳本也可以使用,你可以将别名設定成不同的名字,來操作不同目錄。不過需要注意的是,存放生成的檔案要調整,否則會互相覆寫,可以将傳入工作目錄的字元串進行hash,然後拼接到生成檔案名的後面來做區分。不過目前我這裡這樣就夠了,就不多搞了。