0

The shell-script is creating files for a Flyway delta release, which applies all changes for a new release into an Oracle database.

  1. "git checkout" new release-tag with all the new changes
  2. Check that returncode of the "git checkout" call is ok
  3. Retrieve a list of all files, which have changed between the releases
  4. Files, which have changed are basically copied to a new directory and receive a generated prefix for Flyway2

Later on those files can be easily applied with Flyway...

Problem that happened recently: Step 1 might fail due to a "fatal: Unable to create '.../.git/index.lock': File exists." error (Most likely due to a status update by SourceTree).

Unfortunately git's returncode is 0 in this case (meaning no error), which means the script does not notice, that the files were not updated in step 2 and goes on with steps 3 and 4 (but with wrong files).

In this example I try to circumvent the problem by waiting until the "index.lock" is removed, however this is not fail safe! There might be a index.lock created right after the while-loop is passed, but before the git checkout and I have the same problem again.

GIT="Path to Git.exe"
INDEXLOCK="Path to potential .git/index.lock"

#Unfortunately git checkout returns 0 (everything is ok), when it failed due to an existing index.lock
#The script would then commence, although the sources were not checkout correctly!
#Loop until index.lock does not exist anymore
while [ -f "$INDEXLOCK" ]
do
    echo "Index.lock exists! Waiting until open git process is finished."
    sleep 5
done

echo " "
echo "Trying to check out tag: $2"
$GIT checkout "$2" -q
if [ $? = 1 ]; then
    echo "Error: Can't checkout tag: $2"
    exit;
fi
echo "Check out finished"

Is there a possibilty to make sure the shell-script stops on a ".git/index.lock" error?

  • 1
    As an aside, `GIT="Path to Git.exe"` and then later using `$GIT` is not good practice. Among other things, it'll fail if your path contains spaces. Better is to set `PATH=/path/to/directory/containing/git/:$PATH`, or if you really must make things explicit, use a function: `git() { /path/to/directory/containing/git "$@"; }` -- then below you can just run `git checkout` or such. – Charles Duffy Feb 20 '20 at 17:10
  • 1
    As for checking for a lock, the risk you take is that the lock gets created between you check for it and when you actually start git. It's better for your wrapper to actually retry the git command if it fails (up to a limited number of retries, of course), rather than trying to anticipate that failure ahead-of-time. – Charles Duffy Feb 20 '20 at 17:11
  • 1
    As another aside, btw -- [checking `$?` is generally an antipattern](https://stackoverflow.com/questions/36313216/why-is-testing-to-see-if-a-command-succeeded-or-not-an-anti-pattern); better to just have your `if` branch on exit status: `if git checkout "$@" -q; then echo "Check out finished" >&2; else retval=$?; echo "Error: Can't checkout tag: $2" >&2; exit "$retval"; fi` -- note the need to explicitly store `retval` or else your `exit` exits with the successful exit status of the `echo` that preceded it, not the exit status of the `git` command that came still before that. – Charles Duffy Feb 20 '20 at 17:13
  • 1
    ...if git's exit status doesn't reflect the lock, then the fallback is to capture its stdout and/or stderr and pattern match on them. We have Q&A entries describing how to do that (for any command, not just git) already in the knowledgebase. See for example [bash script - check for specific string in output is failing](https://stackoverflow.com/questions/41286378/bash-script-check-for-specific-string-in-output-is-failing) -- you aren't making the same mistake the OP there is, but the same answer is applicable. – Charles Duffy Feb 20 '20 at 17:14

1 Answers1

0

Capturing the stdout worked. I was able to verify the functionality by placing an index.lock in the directory.

GIT="Path to Git.exe"
INDEXLOCK="Path to potential .git/index.lock"

#Unfortunately git checkout returns 0 (everything is ok), when it failed due to an existing index.lock
#The script would then commence, although the sources were not checkout correctly!
#Loop until index.lock does not exist anymore
while [ -f "$INDEXLOCK" ]
do
    echo "Index.lock exists! Waiting until open git process is finished."
    sleep 5
done

echo " "
echo "Trying to check out tag: $2"
OUTPUT=$($GIT checkout "$2" -q 2>&1)
RETURNCODE=$?

if [[ $OUTPUT == *"fatal: Unable to create"*".git/index.lock': File exists."* ]];
then
    echo "Error: Can't checkout release tag '$2' due to index.lock"
    exit;
elif [ $RETURNCODE = 1 ]; then
    echo "Error: Can't checkout tag: $2"
    exit;
fi
echo " "
echo "Check out attempt finished"