5
\$\begingroup\$

I have been slowly evolving some code for Git and VSS interop based on a quest I started a while ago

And the code is now working, some parts have been updated without test (such as the init) and I am not 100% sure everything is doing what it should/is the best way and some parts seem really round the houses!

Its certainly past the point where it needs some input.

The basic concept is

  • "Pulling" from source safe is achieved by keeping a separate "vss_branch"
    • vss_branch is kept up to kept up to date with source safe via a full source safe get
    • master treats vss_branch as its "upstream/origin" so master pulls from vss_branch
  • "Pushing" to source safe
    • is achieved by figuring out what is different between master and vss_branch
    • saving and then pushing to vss_branch
    • then I go through all the modified/deleted/added files, and applying the appropriate operation e.g. checking them out and checking them in

The code is currently used in the context of git, vss, beyondcompare and trackgear

I am keeping an up to date version here:

Code at time of question:

#--useful aliases
alias gitremove="git ls-files --deleted -z | xargs -0 git rm"
alias bcompare="START / \"C:\Program Files (x86)\Beyond Compare 3\BCompare.exe\""
alias initgitss=InitGitAndSourceSafeProject
alias ssclone="ss get "$CURRENT_SOURCE_SAFE_PROJECT" -W -R -Q -Y$SSNAME -I-N"
alias ssdiff="ss Diff -Y$SSNAME"    

#----These Need Setting:
##Your source safe project
CURRENT_SOURCE_SAFE_PROJECT=
##You Working directory 
CURRENT_PROJ_DIR=

#--For Source Safe Comments
ACTIVE_TRACK_REF=
PROJECT_NAME=

##Your BeyondCompare Session
#its better to create a beyond compare session so you can set it up how you like
BEYOND_COMPARE_SESSION=

#----SysVars
REF_APPEND="_REF"


#--variable set up helper 
sset()
{
    if [ $# -eq 0 ]
    then
        echo "No arguments supplied, please supply the SS project name"
    fi

    CURRENT_SOURCE_SAFE_PROJECT=$1
    CURRENT_PROJ_DIR=$(pwd)
}

#--create a git project from a VSS project and set everything up ---#
InitGitAndSourceSafeProject()
{

    if [ -z ${CURRENT_SOURCE_SAFE_PROJECT+x} ]; 
        then echo "CURRENT_SOURCE_SAFE_PROJECT is unset"; 
        exit;
    fi

    git init

    #get all the SS sourcecode
    echo "Switching to $CURRENT_SOURCE_SAFE_PROJECT"
    ss cp $CURRENT_SOURCE_SAFE_PROJECT

    ssclone

    git add --all
    git commit -m "Initial Source Safe Clone"
    #create fake upstream
    git checkout -b vss_branch
    #create a dev branch
    git checkout -b dev
    git checkout master
    #set master to treat "vss_branch" as upstream
    git branch --set-upstream-to vss_branch
    SynchMasterToSS

}


#---reset to current project---#
sreset()
{
    echo "Make sure we are in the correct source safe project"
    ss CP $CURRENT_SOURCE_SAFE_PROJECT
    ss project
}
quietsreset()
{
    ss CP $CURRENT_SOURCE_SAFE_PROJECT -O-
}


#----Commit *one file* -that is already added- to SS----#
sscommitone()
{

    FULLPATH=$1
    DIR=$(echo ${FULLPATH%/*})

    SS_COMMENT="$PROJECT - TGR: $TGR\n\n"

    #go to correct place in working directory 
    pushd $DIR  
    #checkout file without overwriting local copy
    #echo Y | ss checkout "$FULLPATH" -G-WR -Y$SSNAME
    ss checkout "$FULLPATH" -G-WR -Y$SSNAME -I-Y
    #check in the file with comment
    #echo Y | ss checkin "$1" -C"$SS_COMMENT" -W -Y$SSNAME  
    ss checkin "$1" -C"$SS_COMMENT" -W -Y$SSNAME -I-Y   
    #go back to the directoy we were in -root-
    popd

}
#----bulk commit---#
sscommit()
{
    for file in $1; do
        sscommitone $file
    done
}
#----bulk add-----#
AddEachNewFile()
{
    printf "\n\nAdding files requires us to loop, so we can add to the correct directory"

    for file in $1; do

    printf "\n--Resetting Dir---\n"
    quietsreset

    new_file=$(echo ${file##*/})
    directory=$(echo ${file%/*})


    #cp to folder
    echo "Directory is: $directory"
    quietsreset
    test=$(ss CP $directory 2>&1 | grep -c 'exist' 2>&1)


    if (( "1"== $test )); 
    then
    echo "Did not to find directory! It does not exist!....yet :)";

    new_directory=$directory;
    last_directory=$directory;
    while (( "1"== $test )); 
    do
        echo "->This parent directory does not exist, try going up";
        echo "---trying to cp to $new_directory"
        last_directory=$(echo ${new_directory})
        new_directory=$(echo ${new_directory%/*})

        quietsreset
        test=$(ss CP $new_directory 2>&1 | grep -c 'exist' 2>&1)

        echo "[+]"
    done

    echo "Directory does not exit, need to add $last_directory";
    ss Add $last_directory -R -C"$SS_COMMENT" -Y$SSNAME 

    else
    echo "Directory already exist, need to add file: ${file}";
    ss Add $file -C"$SS_COMMENT" -Y$SSNAME 
    fi 



    done

}

#use this function for when you forgot to fill in TGR info
ptgr()
{
    updateModDelAddVars $1
    printTGRInfo
}
#--- vars needed for to perform ss operations ----
updateModDelAddVars()
{
    #files to check out and in again from SS
    MODIFIED_FILES=$( git diff --name-only $1  --diff-filter=M) 
    #files to add to SS
    ADDED_FILES=$( git diff --name-only  $1  --diff-filter=A) 
    #file to delete from SS
    DELETED_FILES=$( git diff --name-only  $1  --diff-filter=D) 
}

printTGRInfo()
{
    printf "Please update the TGR with the following changed files:"
    printf " \n***********************\n"
    printf "|--Modified Files --\n\n"
    printf "$MODIFIED_FILES"
    printf " \n--\n"
    printf "|--New Files --\n\n"
    printf "$ADDED_FILES"
    printf " \n--\n"
    printf "|--Deleted Files --\n\n"
    printf "$DELETED_FILES"
    printf " \n\n ********************* \n"
}



##------Pull -todo- find out what other command is assigned to sspull!
sspullb()
{
    if [ ! -d ".git" ]; then
    echo "Must be ran from root git/ss rep"
    exit;
    fi

    #save branch we are on
    BRANCH=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')



    #jump to "fake upstream"
    git checkout vss_branch

    #update vss branch to match vss..   
    echo "grabbing all files from sourcesafe"
    ssclone

    ##figure out files I have changed
    FILES=$( git diff --name-only master vss_branch) 

    ##grab the recent history for those files & everything else seperately  
    NOW=$(date)
    SSFILEHISTORY=$(ss History . $FILES -#3)
    SSHISTORY=$(ss History . -#3)

    ##now add & commit those files with a comment
    git add --all   
    MESSAGE=$(echo -e "Source safe sync: $NOW \n Changes to my files: \n $SSFILEHISTORY  \nChanges To Other Files:\n $SSHISTORY")
    git commit -a -m"$MESSAGE"


    #jump back to branch that wants to pull
    git checkout $BRANCH
    git pull    

}

##------ 'Push' 
sspush()
{
    if [ ! -d ".git" ]; then
    echo "Must be ran from root git/ss rep"
    exit;
    fi

    BRANCH=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

    ##-TODO- check for git error at checkout attempt instead!
    ##we might have some work uncommitted (naughty) 
    ##git stash

    #get a suitable amount of git master comments for SS comment SS comment IS limted to 500chars though...
    GIT_COMMENT=$(git log --pretty=format:"%h %s" --no-merges -n 3)
    git log --no-merges > fullGitHistory.githistory

    #figure out files that need to go into source safe
    updateModDelAddVars vss_branch

    #ok now make vss_branch up to date -this keeps git happy :)-
    #the odd syntax is due to the fact we are treating vss_branch as our upstream
    git push . HEAD:vss_branch


    #check the file in with latest git comments but keep files as writeable
    #--TODO-- read -p "Please enter the TGR this commit relates to: " TGR 
    TGR=$ACTIVE_TRACK_REF

    #Add each file (and possible directory)
    printf "\n---------------------------------------------------\n"
    printf "Adding new files \n->\n $ADDED_FILES"
    printf "\n---------------------------------------------------\n"
    SS_COMMENT="$PROJECT - TGR: $TGR  \n\n$GIT_COMMENT" 
    AddEachNewFile $ADDED_FILES

    printf "\n---------------------------------------------------\n"
    printf "Deleting old files \n->\n $DELETED_FILES"
    printf "\n---------------------------------------------------\n"
    ss Delete $DELETED_FILES -Y$SSNAME -I-N

    #Loop through the files, checking in and out from correct directory 
    printf "\n---------------------------------------------------\n"
    printf "Overwriting modified files \n->\n $MODIFIED_FILES"
    printf "\n---------------------------------------------------\n"    
    sscommit $MODIFIED_FILES

    #update git history file -this way SS has all the rich comment history I store with git despite SS's 500 comment character limit-
    ss Add fullGitHistory.githistory -C"Log of all git history"
    sscommitone fullGitHistory.githistory

    #now print the message needed for the TGR comment
    printTGRInfo


    #"unpop" all the things we just did to restore working tree
    git checkout $BRANCH

    ##--TODO-- check for git error at checkout attempt instead!
    ##git stash apply 



}

#replace Source-safe code with my master branch code
masterpushss()
{   
    echo "to master branch"
    git checkout master 
    sspush  
}
#merge master with source safe code
masterpullss()
{   
    git checkout master
    sspullb
}

#get master to perform pull and push 
synch()
{
    masterpullss
    masterpushss
}


##----True Diff---
hardrefupdate()
{
    REF_FOLDER="$CURRENT_PROJ_DIR$REF_APPEND"
    rm -rf $REF_FOLDER
    updateref

}
updateref()
{
    REF_FOLDER="$CURRENT_PROJ_DIR$REF_APPEND"
    if [ ! -d $REF_FOLDER ]; then     
        mkdir $REF_FOLDER
    fi
    pushd $REF_FOLDER
    ssclone
    popd

}

compare_toREF()
{

    if [ -z "$BEYOND_COMPARE_SESSION" ]; then
        bcompare $CURRENT_PROJ_DIR $REF_FOLDER /iu /filters="-*.scc;-*.opensdf;-*.sdf;-*.orig" /qc=size 
    else    
        bcompare $BEYOND_COMPARE_SESSION
    fi



}
#should only be needed for sanity checks -diff with vss_branch *should* achieve the same-
diffallss()
{
    if [ -z ${CURRENT_PROJ_DIR+x} ]; 
        then echo "CURRENT_PROJ_DIR is unset"; 
        exit;
    fi

    UpdateRef
    compare_toREF   
}
harddiffallss()
{
    if [ -z ${CURRENT_PROJ_DIR+x} ]; 
        then echo "CURRENT_PROJ_DIR is unset"; 
        exit;
    fi

    hardrefupdate
    compare_toREF   
}



#PS1='[\u@\h`__git_ps1` \W]\$ 
\$\endgroup\$
  • \$\begingroup\$ I will admit this has become more of a "is it possible" then a proper solution :p \$\endgroup\$ – chrispepper1989 Nov 25 '14 at 9:11
3
\$\begingroup\$

A couple of minor issues, from top to bottom.


When you need to embed double-quotes in a string, and you don't need to embed variables inside, then it's easier to use single-quotes. So instead of this:

alias bcompare="START / \"C:\Program Files (x86)\Beyond Compare 3\BCompare.exe\""

This is easier:

alias bcompare='START / "C:\Program Files (x86)\Beyond Compare 3\BCompare.exe"'

No need to break out of the double-quotes here:

alias ssclone="ss get "$CURRENT_SOURCE_SAFE_PROJECT" -W -R -Q -Y$SSNAME -I-N"

You could embed the variable simply:

alias ssclone="ss get $CURRENT_SOURCE_SAFE_PROJECT -W -R -Q -Y$SSNAME -I-N"

Regarding this piece:

if [ -z ${CURRENT_SOURCE_SAFE_PROJECT+x} ];

...What the heck is ${CURRENT_SOURCE_SAFE_PROJECT+x} ??? I'd appreciate if you could explain in comments :-) Especially a keyword would be nice that I can search for in man bash. I'd be really interested to know.

As it stands, it seem to me the expression will always evaluate to the letter "x", which is not empty, so the if will always be false.


Unnecessary ; at the end of some lines:

    then echo "CURRENT_SOURCE_SAFE_PROJECT is unset"; 
    exit;

Remove those.


In some ss commands you use cp, in others you use CP. I suggest to be consistent and stick with the same style everywhere.


The echo in a subshell here is unnecessary:

DIR=$(echo ${FULLPATH%/*})

This is better:

DIR=${FULLPATH%/*}

The same goes for these:

new_file=$(echo ${file##*/})
directory=$(echo ${file%/*})

In AddEachNewFile you have a for-loop with the body not well-indented:

for file in $1; do

printf "\n--Resetting Dir---\n"
quietsreset

In the same method you also have an if block not well-indented. I suggest to fix these, as they hurt readability and can easily lead to bugs.


No need to quote exist here:

test=$(ss CP $directory 2>&1 | grep -c 'exist' 2>&1)

This is the same and simpler:

test=$(ss CP $directory 2>&1 | grep -c exist 2>&1)

The rest of the code has similar issues to the ones I already pointed out:

  • bad indents
  • unnecessary trailing ;
  • unnecessary quotes
  • unnecessary echo subshells

Review the entire code, and follow the suggestions above.

When done, copy-paste your code on http://www.shellcheck.net/#, and correct the remaining warnings it tells you.

\$\endgroup\$
  • 1
    \$\begingroup\$ Some great suggestions, thank you janos. I will read through and update accordingly. Regarding the updated code, should I just put it in an edit? As for the +x. I honestly for the life of me can't remember (comments ftw) so its either a typo or a bad attempt to check that the folder exists. \$\endgroup\$ – chrispepper1989 Dec 9 '14 at 15:18
  • 1
    \$\begingroup\$ Hi @chrispepper1989, no, you shouldn't edit the code in your question, as that would invalidate my review. You can post a new question with the revised version for another round of reviews if you still need. \$\endgroup\$ – janos Dec 9 '14 at 15:26
  • \$\begingroup\$ I was wondering new question or an ---Update--- to the question? \$\endgroup\$ – chrispepper1989 Dec 9 '14 at 16:43
  • \$\begingroup\$ Don't wonder: new question is the way we do here. It's also better for you, more questions usually lead to more rep ;-) \$\endgroup\$ – janos Dec 9 '14 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.