Search code examples
gitaliasgit-subtree

How to make an alias for git subtree push command with repository and refspec


I want to define a shortcut (alias) for the following command:

    git subtree push --prefix=_site [email protected]:mertnuhoglu/blog_datascience.git gh-pages

I want to be able to use the shortcut such that I won't need to specify the repository name. Even when using it in different repos.

Is this possible? How can I do this?


Solution

  • In the home directory of your user

    1. Windows: C:\Users\<user-name> (or in git-bash: /c/Users/<user-name>)
    2. Linux: /home/<user-name>
    3. Mac: /Users/<user-name>

    create or open a file called .bashrc and append the following line

    alias gsp="git subtree push --prefix=_site [email protected]:mertnuhoglu/blog_datascience.git"
    

    Then open a new (git-)bash and the alias gsp should be available.

    UPDATE

    This update describes a more general approach, which should work for multiple subtrees and for any git repository (that has been configured accordingly).

    The requested alias would require a mechanism to automatically infer

    1. the prefix
    2. the name of the remote or its address, and,
    3. the remote branch

    for each subtree.

    As far as I know git-subtree only stores the hash of a commit in the remote repository that has been referenced (and possibly its history), but it does not store the address of that remote, as can be seen in the output of git-log of a toy example:

    *   1ffc070 Merge commit '7a9390a29011dad36b2def6b0d0881b0361875e8' as 'bar.st'
    |\  
    | * 7a9390a Squashed 'bar.st/' content from commit 10e3347
    * 429987f - Added foo.
    

    So, there goes the easy solution.

    But what about storing the required information from the enumeration above in a config file, e.g. .gitsubtrees alongside each repository? That file uses a simple file format:

    # <prefix>;<remote address/name>;<remote branch>
    bar.st:../bar:master
    _site;[email protected]:mertnuhoglu/blog_datascience.git;master
    # ...
    

    Then add the following function to your .bashrc:

    function gsp
    {
        # Config file for subtrees
        #
        # Format:
        # <prefix>;<remote address>;<remote branch>
        # # Lines starting with '#' will be ignored
        GIT_SUBTREE_FILE="$PWD/.gitsubtrees"
    
        if [ ! -f $GIT_SUBTREE_FILE ]; then
            echo "Nothing to do - file <`basename $GIT_SUBTREE_FILE`> does not exist."
            return
        fi
    
        OLD_IFS=$IFS
        IFS=$'\n'
        for LINE in $(cat $GIT_SUBTREE_FILE); do
    
            # Skip lines starting with '#'.
            if [[ $LINE = \#* ]]; then
                continue
            fi
    
            # Parse the current line.
            PREFIX=`echo $LINE | cut -d';' -f 1`
            REMOTE=`echo $LINE | cut -d';' -f 2`
            BRANCH=`echo $LINE | cut -d';' -f 3`
    
            # Push to the remote.
            echo "git subtree push --prefix=$PREFIX $REMOTE $BRANCH"
            git subtree push --prefix=$PREFIX $REMOTE $BRANCH
        done
    }
    

    If, for some git repository, the config file .gitsubtrees does not exist, gsp won't do anything otherwise it will print the command it executes and the corresponding output.

    $ gsp
    git subtree push --prefix=bar.st ../bar master
    git push using:  ../bar master
    -n 1/       3 (0)
    -n 2/       3 (1)
    -n 3/       3 (1)
    

    Note: for readability the code of gsp neglects sanity checks and also doesn't handle exceptions. If git subtree push fails your back to manual labour.