Display Random Git Tips in Your Terminal

Tonight I want to show you a simple way to display a random Git tip on the command-line.

Assumptions

  1. You are using a UNIX-ish shell like GNU Bash, zsh, or Fish, which is my shell of choice and what I will be using for this example. Although the code will be easy to port to other shells.

  2. You have a local clone of the git-tips repository.

  3. You have installed jq.

What the Command Looks Like

$ git-random-tip
"Quickly switch to the previous branch"
"git checkout -"

The Implementation

Again, this is a function for Fish, but you should have no trouble porting it to other shells. The major differences here between Fish are the commands and syntax for creating locally-scoped variables (set) and command-substitution (using parentheses instad of $() like in the standard /bin/sh).

First I will show the function and then walk through the code, namely explaining our use of jq. For the sake of example we will say ~/Documents/git-tips is the location of the git-tips repository on our computer.

function git-random-tip --description="Show a random Git tip"
        set -lx tip_file "~/Documents/git-tips/tips.json"
        set -lx tip_index (seq 0 (jq "length" $tip_file) | sort -R | head -1)
        jq ".[$tip_index] | .title, .tip" $tip_file
end

Step 1. Create a Variable for the File of Tips

The git-tips project contains all information on tips in a JSON document named tips.json. We will reference this file multiple times. So in order to avoid copy-pasting, and to simplify things if we later move the location of the repository, we first create the $tip_file variable which is a string containing that filename.

Step 2. Find Out How Many Tips There Are

Note: For the rest of this article I will assume the reader has a basic understanding of JSON structure and syntax.

The tips.json file contains one large array where each element is an object describing an individual tip. What we want our git-random-tip function to do is randomly select an object from that array and then extract data from that object to display on the terminal. So we want a random number between zero and the length of that array, which will be our $tip_index variable.

Calculating the length of the array is our first use of jq, a command-line program that is like sed and awk, but built specifically for use with JSON. Our command is this:

jq "length" $tip_file

The first argument tells jq what to do with the input. Often we use jq to select specific parts of JSON data from input, and then perform some operation or function on that specific data. But in this scenario all we want to do is apply length() to the entire array that makes up the file of tips. The output of this command will be the number of elements in the array.

Now we want the sequence of numbers from zero to that length, for which we use seq, a standard Unix command:

seq 0 (jq "length" $tip_file)

This gives us output like:

0
1
2
3
4
# And so on…

Next we use sort to randomize that list:

seq 0 (jq "length" $tip_file) | sort -R

Now our output is like so:

22
3
12
0
4
5
# …

All we have left to do now is choose one line from that list of randomized array indices:

seq 0 (jq "length" $tip_file) | sort -R | head -1

This gives us a single number that we save in our $tip_index variable.

Step 3. Display the Tip Given That Random Index

We can use jq to select an element from an array of input by using the syntax ".[$index]". So for example, if we run this…

jq ".[3]" $tip_file

…we get the object at that index, which looks like this:

{
  "title": "List all the conflicted files",
  "tip": "git diff --name-only --diff-filter=U"
}

Now what we want to do is tell jq to display the values for the title and tip properties of that object. There are different ways to accomplish this in jq, but since it is such a common operation jq provides a convenient shortcut: we can get the values of object properties simply by writing .name_of_the_property, which leads us to this command:

jq ".[$tip_index] | .title, .tip" $tip_file

Here we insert out $tip_index variable, thus selecting a random element from the array of tips. Then we ‘filter’ that via the pipe |, like in shells, to another set of jq commands. The element we select with ".[$tip_index]" will be a JSON object, so our commands on the right-hand side of the pipe are simply .title, .tip, which tells jq: "Select the properties title and tip from the object and display their values on standard output."

Conclusion

And that’s how we end up with this:

$ git-random-tip
"Stage parts of a changed file, instead of the entire file"
"git add -p"

Note: I actually use an alias in my Git configuration so that I can write git random-tip, without the initial dash like standard Git commands. The alias merely invokes the function defined in this post via !fish -c git-random-tip.

I hope this was easy to follow, but if you’re confused about anything regarding jq or porting this to more common shells, don’t hesitate to ask questions in the comments. And yeah—you could definitely use a program like curl to fetch the tips from the web instead of relying on a local clone of that repository. But I leave that as an exercise for the reader. ::wink::

Advertisements

Add Your Thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s