Recently, I worked on a visual object tracker implemented in C++. The project has several compile configurations and a time-consuming test suite, some parts of which need a GPU not present in my laptop. Because many parts of the code depend heavily on compile configuration, changing them requires recompilation and ideally also retesting of all configurations to make sure that everything works correctly. Since my development laptop not only lacks the GPU needed for testing but also has only four cores, which makes the compilation unnecessarily slow, I looked for an easy way to compile and test the code being edited on a powerful remote server.
Initially, I tried to use git commit
and git push
to capture the
state of the working directory and transfer it to the remote server,
but this was not ideal for many reasons. Then I discovered git stash
create
, which captures the state of the working directory and creates
a “volatile” commit object not attached to any branch. This command
became the basis of my git-sarah
script, which is an acronym
standing for git stash and run at host, and you can see find its
code below.
With git-sarah
script, instead of instructing my editor or IDE to
run:
make
I instruct it to run the following:
git sarah example.org dir -- make
This command copies the current state of the work tree to $HOME/dir
on the example.org server and runs make
in the directory
corresponding to the current directory on the local host. For example,
if the current local directory is ~/projects/kcf/src
, with kcf
being the root directory of the git repository, the make
command
will be run in $HOME/dir/src
on the server. In the output (both
stdout and stderr) of the command, the path of the server directory,
e.g., /home/mylogin/dir
is replaced with its local counterpart:
/home/me/projects/kcf
.
If a single command (make
) is not enough, you can instruct
git-sarah
to run commands from a script (e.g., commands.sh
), which
need not to be stored in your git repository. For that, run:
git sarah example.org dir -- sh < ./commands.sh
The code of git-sarah
(further development happens on GitHub) is quite simple:
#!/bin/bash set -e -o pipefail OPTS_SPEC="\ git sarah <host> <remote_dir> [ -- ] [ command ... ] git stash and run at host -- h,help show the help " eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" echo "$*" while \[[ $# -gt 0 ]]; do case "$1" in -h) exit 0;; --) shift; break;; esac shift done HOST=${1:?Host not specified}; shift DIR=${1:?Remote directory not specified}; shift PREFIX=$(git rev-parse --show-prefix) worktree=$(git stash create) worktree=${worktree:-HEAD} git push -f $HOST:$DIR $worktree:refs/heads/git-sarah # Use ssh to translate possibly relative $DIR to the absolute one. ABS_DIR=$(ssh "$HOST" "cd '$DIR' && pwd") # Run the command at $HOST and translate its output so that # file/directory names appear as on localhost. Use perl's \Q to limit # the possibility of interpretating ABS_DIR as a search pattern. ssh "$HOST" "cd '$DIR/$PREFIX' && git -c advice.detachedHead='' checkout --detach git-sarah && ${*:?Command not specified}" \ |& perl -pe "s|\Q${ABS_DIR}\E|$(git rev-parse --show-toplevel)|g"