# Return the branch name if we're in a git repo, or nothing otherwise.
git_check (){local gitBranch=$(git branch 2> /dev/null | sed-e"/^[^*]/d"-e"s/* \(.*\)/\1/")if[[$gitBranch]];then
echo-en$gitBranchreturn
fi}
To be honest I don't exactly know how this works. But if we're in a git repo it outputs the branch name, otherwise it does nothing.
Let's talk about it!
git_check (){
...
}
This defines a function, git_check, which you can call later in the script.
local gitBranch=$(...)
This defines a local variable, gitBranch, which can only be used within the scope of git_check. The assigned value will be the output of the command within the $(...).
git branch 2> /dev/null
This runs the git branch command, and sends the stderr to /dev/null, effectively wiping the error message from existence. Stdout will still be printed, though. Thus, if you are inside a git repository, then you'll see the output of git branch; and if you're not, you won't see any error message.
As a reminder, here's what git branch output will look like if you're in a git repository...
bar
* foo
quux
In the above example, we see all the branches in your local checkout, alphabetized; and the active branch is prefixed with *.
Moving on.
| sed-e"/^[^*]/d"-e"s/* \(.*\)/\1/"
We're piping the output of git branch into the sed command. sed is short for "stream editor"; we'll use it to transform the output of the git branch command, line-by-line. Each -e flag denotes a transformation script. Let's look at the two scripts.
-e"/^[^*]/d"
The /.../d command is documented as "Delete pattern space. Start next cycle." So, any line matching the regex pattern ^[^*] will be ignored. That regular expression has two components:
^: Start-of-line.
[^*]: Match any character other than the literal *.
Thus, the regex will match any line which begins with a character other than the literal *. If you look at the example git branch output I pasted above, this would match the line for any branch except the active branch. Putting it all together, sed -e "/^[^*]/d" will ignore any line except for the active branch line.
Then, we have the other sed command:
-e"s/* \(.*\)/\1/"
The s/regexp/replacement/ command will attempt to match the regexp against the input, and if successful, will replace that portion with the replacement. So let's look at the regexp and the replacement.
First, let's look at the regex: * \(.*\).
* at the beginning of the regex matches the literal *. matches the literal space character, . \(...\) creates a capture group. sed will replace the escaped characters \( and \) with parentheses. (If we wanted to capture literal parenthesis characters, we would use \\(foo\\)). .* matches any quantity (including zero) of any character(s). It's a wildcard.
In short, this regex will match any line starting with the literal *, and everything thereafter will be remembered in a capture group.
Next, let's look at the replacement, \1. This syntax refers to the first capture group: which, recall, is everything after the *.
In summary, -e "s/* \(.*\)/\1/ would replace a line like * foo with just foo. It strips away the leading *. If the regex doesn't match, then there is no effect: the line bar would just become bar.
The sum total of our sed statement is that we have eliminated all lines from git branch except the active branch line, and we have removed the leading * from that active branch line. All we are left with is the name of the active branch. And, if we are not inside a git repository, then the sed command would have received no lines for input, and thus would yield no output.
Let's check in with our script. Where are we now? We are in a function called git_check, and we have just created a local variable gitBranch whose value is the name of the active branch. If we are not in a git repository, then the value would instead be the empty string.
Moving on.
if[[$gitBranch]];then
...
fi
This conditional block will execute if (and only if) the gitBranch variable has a non-empty value. Remember that gitBranch equals the name of the active git branch, but only if we are inside a git repository. Thus, the conditional block will execute if (and only if) we are inside a git repository.
echo [FLAGS] MESSAGE will print out the message. In this case, we'll print the value of the gitBranch variable, and then return from (exit) our function.
The -e flag enables interpretation of backslash escapes: for example, echo "\t" will print the literal string \t, whereas echo -e "\t" will interpret \t as a special tab character, and will print a tab. (I don't think this flag is necessary here.)
The -nwill suppress the trailing newline. echo will normally print out a newline at the end of your output. For example:
So, that's every part of the code-block! To review, we defined a function git_check, which runs git branch, discards any errors, and extracts the active git branch (if any) into the local variable gitBranch. Then, if that variable is not empty, we printed its contents without any surrounding whitespace.
Hope this helps! Thanks for your write-up; I stole several of your nifty tricks :)
Let's talk about it!
This defines a function,
git_check
, which you can call later in the script.This defines a local variable,
gitBranch
, which can only be used within the scope ofgit_check
. The assigned value will be the output of the command within the$(...)
.This runs the
git branch
command, and sends the stderr to/dev/null
, effectively wiping the error message from existence. Stdout will still be printed, though. Thus, if you are inside a git repository, then you'll see the output ofgit branch
; and if you're not, you won't see any error message.As a reminder, here's what
git branch
output will look like if you're in a git repository...In the above example, we see all the branches in your local checkout, alphabetized; and the active branch is prefixed with
*
.Moving on.
We're piping the output of
git branch
into thesed
command.sed
is short for "stream editor"; we'll use it to transform the output of thegit branch
command, line-by-line. Each-e
flag denotes a transformation script. Let's look at the two scripts.The
/.../d
command is documented as "Delete pattern space. Start next cycle." So, any line matching the regex pattern^[^*]
will be ignored. That regular expression has two components:^
: Start-of-line.[^*]
: Match any character other than the literal*
.Thus, the regex will match any line which begins with a character other than the literal
*
. If you look at the examplegit branch
output I pasted above, this would match the line for any branch except the active branch. Putting it all together,sed -e "/^[^*]/d"
will ignore any line except for the active branch line.Then, we have the other
sed
command:The
s/regexp/replacement/
command will attempt to match the regexp against the input, and if successful, will replace that portion with the replacement. So let's look at the regexp and the replacement.First, let's look at the regex:
* \(.*\)
.*
at the beginning of the regex matches the literal*
.matches the literal space character,
.
\(...\)
creates a capture group.sed
will replace the escaped characters\(
and\)
with parentheses. (If we wanted to capture literal parenthesis characters, we would use\\(foo\\)
)..*
matches any quantity (including zero) of any character(s). It's a wildcard.In short, this regex will match any line starting with the literal
*
, and everything thereafter will be remembered in a capture group.Next, let's look at the replacement,
\1
. This syntax refers to the first capture group: which, recall, is everything after the*
.In summary,
-e "s/* \(.*\)/\1/
would replace a line like* foo
with justfoo
. It strips away the leading*
. If the regex doesn't match, then there is no effect: the linebar
would just becomebar
.The sum total of our
sed
statement is that we have eliminated all lines fromgit branch
except the active branch line, and we have removed the leading*
from that active branch line. All we are left with is the name of the active branch. And, if we are not inside a git repository, then thesed
command would have received no lines for input, and thus would yield no output.Let's check in with our script. Where are we now? We are in a function called
git_check
, and we have just created a local variablegitBranch
whose value is the name of the active branch. If we are not in a git repository, then the value would instead be the empty string.Moving on.
This conditional block will execute if (and only if) the
gitBranch
variable has a non-empty value. Remember thatgitBranch
equals the name of the active git branch, but only if we are inside a git repository. Thus, the conditional block will execute if (and only if) we are inside a git repository.For more info, you might look into the
[[
built-in: mywiki.wooledge.org/BashFAQ/031echo [FLAGS] MESSAGE
will print out the message. In this case, we'll print the value of thegitBranch
variable, and then return from (exit) our function.The
-e
flag enables interpretation of backslash escapes: for example,echo "\t"
will print the literal string\t
, whereasecho -e "\t"
will interpret\t
as a special tab character, and will print a tab. (I don't think this flag is necessary here.)The
-n
will suppress the trailing newline.echo
will normally print out a newline at the end of your output. For example:So, that's every part of the code-block! To review, we defined a function
git_check
, which runsgit branch
, discards any errors, and extracts the active git branch (if any) into the local variablegitBranch
. Then, if that variable is not empty, we printed its contents without any surrounding whitespace.Hope this helps! Thanks for your write-up; I stole several of your nifty tricks :)
This is incredible! Thank you for taking the time to explain this part!