unexpected operator [: git: in bourne shell script 'if' conditional statement - debugging

I've watched an excellent shell scripting course through a multitude of videos. Now that I think I am fairly familiar with the Bourne shell, I decided to write my first shell script.
Script goal: check if git working directory is clean. If so, overwrite working directory to a branch named deployment. Finally, push the deployment branch to origin.
I ended up with this code:
#!/bin/sh
######################################################
# Deploys working directory to git deployment branch.
# Requires that the working directory is clean.
######################################################
#check if the working directory is clean
if [ git diff-index --quiet HEAD ]
then
if [ git branch -f deployment ]
then
if [ git push origin deployment ]
then
echo
echo "OK. Successfully deployed to git deployment branch."
echo
exit 0 #success
else
echo
echo "Error: failed to push deployment branch to origin."
echo
exit 1 #failure
fi
else
echo
echo "Error: failed to create or overwrite deployment branch."
echo
exit 1 #failure
fi
else
echo
git status #show the status of the working directory
echo
echo "Error: working directory is not clean. Commit your changes first..."
echo
exit 1 #failure
fi
Unfortunately, this seems to give me an error: ./tools/deploygit: 9: [: git: unexpected operator
Why is this so? What operator am I using in if [ git diff-index --quiet HEAD ] that is unexpected?
As a bonus, do you have any suggestions or tips on how to improve the efficiency, logic or readability of this script?

In this statement:
if [ git diff-index --quiet HEAD ]
The [ is an alias for the test command, so what you're actually running is...
if test git diff-index --quiet HEAD ]
...which isn't what you mean. You don't need to use the test command in order to evaluate the result of a command; you should just do this:
if git diff-index --quiet HEAD
Take a look at the documentation for the if command:
$ help if
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
The conditional argument to the if statement is command. Normally, the test command is used to make it look like other languages, but you can put any command there. Things that exit with a return code of 0 evaluate to true and anything else evaluates to false.

Related

Bash - check if repository exists

I am trying to create if statement which will check if repository with name X exists, if it doesn't => create it.
Made following code. It works, but when repository doesn't exists, then it shows error. I couldn't find any ways of removing that error in console. Make I was using &>/dev/null not in correct way...
myStr=$(git ls-remote https://github.com/user/repository);
if [ -z $myStr ]
then
echo "OMG IT WORKED"
fi
As soon as you completely silence git ls-remote I will suggest to check the exit code of the command ($?) rather than its output.
Based on your code you could consider a function in this way:
check_repo_exists() {
repoUrl="$1"
myStr="$(git ls-remote -q "$repoUrl" &> /dev/null)";
if [[ "$?" -eq 0 ]]
then
echo "REPO EXISTS"
else
echo "REPO DOES NOT EXIST"
fi
}
check_repo_exists "https://github.com/kubernetes"
# REPO DOES NOT EXIST
check_repo_exists "https://github.com/kubernetes/kubectl"
# REPO EXISTS

git run command if nothing to commit

This question is probably about bash as much as it is about git.
How do I run a command if there is nothing to commit? I did the following, but it runs the echo hello command even if there is nothing to commit:
if git diff --exit-code; then
echo hello
fi
Coming from a python background, what I assumed would happen is if git ... command is empty then the stuff inside the if statement would not execute. I have confirmed that git diff --exit-code returns nothing.
TLDR: Your current code echoes hello in the success case, not the failure case.
We can fix this by inverting the condition, so it becomes:
if ! git diff --exit-code; then
echo hello
fi
I'd recommend having a look at How to check the exit status using an 'if' statement which provides a few options for how to do this.
Try something like this:
git diff --exit-code # exit code will be "0" if no changes
if [ $? -gt 0 ]; then
echo hello
fi

While loop with if statement plus result of variable

I was doing a script for myself to summarize commands I use daily in one handy script. So basically I ended doing it with a conditional checking if the .git folder exists first but I'd like to make it more interesting and like so understand better the loop. My desire is to have a variable like:
"output=$(git status)" and if the result is 0, continue depending on the statement. If the result is other than 0, break the loop and end the script with a message like "the actual directory hasn't a .git repo".
I let you my first idea of it but without the git status as I don't know how to add it neither where to. Thank you guys!
set -e
gitrepo=true
while [ $gitrepo == true ]; do
if [[ $? -ne 0 ]]; then
echo "not a git directory"
$gitrepo=false
else
read -p "Commit message: " commit
git commit -am "$commit"
fi
done
Try this: I did as Cyrus suggested:
#!/usr/bin/env bash
set -e
gitrepo=True
while [[ $gitrepo ]]; do
if [[ ! $? ]]; then
echo "not a git directory"
gitrepo=False
else
read -p "Commit message: " -r commit
git commit -am "$commit"
exit 0
fi
done

How to trigger a fail in Travis CI?

One of my test is a simple bash command with an if condition. I want Travis CI to consider a build as failed if the condition is positive.
I try to do it this way (a part of the .travis.yml file):
# ...
script:
- npm run build
- if [[ `git status --porcelain` ]]; then >&2 echo "Fail"; fi
# ...
But when the condition is positive, the message is just printed and the build is considered as successful.
What should I do to make a build failed when the condition is positive?
Just add exit 1; after the echo. More info.
If you just want to assert a condition but continue with testing, the following worked for me:
bash -c 'if [[ `git status --porcelain` ]]; then >&2 echo "Fail"; exit 1; fi'
This will make the build results fail but not terminate it.
Add return 1;
Travis compiles the different commands into a single bash script so exit 1 or travis_terminate 1 will abruptly interrupt the workflow and skip the after_script phase.
For complex commands that you want to make more readable and don't want to move to their own script, you can take advantage of YAML's literal scalar indicator:
script:
- |
if [[ `git status --porcelain` ]]; then
>&2 echo "Fail"
return 1
fi

Git Bash Script Check Working Tree

Is there a way in Git Bash to check if the working tree is clean, that is no uncommitted changes or untracked files?
I'm working on a bash script for my group to automate the process of daily rebasing working branches. Unclean working trees is a common problem. I can manually correct the problem by executing git checkout .. This would have the desired result most of the time, but not always, so I need to be able to have my script programatically check that the working directory/tree is clean.
The git-sh-setup script included with git contains a number of useful functions for working with git repositories. Among them is require_clean_work_tree:
require_clean_work_tree () {
git rev-parse --verify HEAD >/dev/null || exit 1
git update-index -q --ignore-submodules --refresh
err=0
if ! git diff-files --quiet --ignore-submodules
then
echo >&2 "Cannot $1: You have unstaged changes."
err=1
fi
if ! git diff-index --cached --quiet --ignore-submodules HEAD --
then
if [ $err = 0 ]
then
echo >&2 "Cannot $1: Your index contains uncommitted changes."
else
echo >&2 "Additionally, your index contains uncommitted changes."
fi
err=1
fi
if [ $err = 1 ]
then
test -n "$2" && echo >&2 "$2"
exit 1
fi
}
This is in addition to being able to check the output from git status --porcelain and/or git status -z if you need to be more specific about what the state currently is.

Resources