/ GIT, CHERRY-PICK, BASH

Cherry-pick automation with Bash

I manage my Jekyll blog in a Git repo. My publication process uses 2 branches:

  • master contains all production content
  • feature/newposts has the new blog posts, ready to get published, one commit per post

To publish an existing post:

  1. I check the to-be-published post in the feature/newposts branch
  2. Then, get the associated commit
  3. And cherry pick it in the master branch
  4. Finally, I push

While not that slow, this is very boring. This post explains how I "automated" the above process using bash magic.

Date

Bash users know how to get the current date:

date

This outputs:

Sun Aug  5 12:15:23 CEST 2018

However, the Jekyll blog post filename is formatted as 2018-08-05-xxx-yyy-zzz.adoc. Having a look at the man page, the relevant syntax is:

date +'%Y-%m-%d'

It outputs the expected string:

2018-08-05

Path

To get the path of a file in a Git tree, one needs to use the git ls-tree command:

git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'`

This yields:

100644 blob 2cb14109c9a41b67609b93a9fea904735d082a5c	_posts/2018-08-05-spring-boot-integration-intellij-idea.adoc

Note that the hash is the blob’s hash, and not the commit’s hash. From that point, there are two ways:

  1. Get the commit with this blob
  2. Get the commit with this path

For no real reason, I chose the second option.

To get the path only, the output needs to be cut:

git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-

This now correctly prints:

_posts/2018-08-05-spring-boot-integration-intellij-idea.adoc

Commit

git log is the command to get the commit for a specific path. It allows a branch option.

git log feature/newposts -- $(git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-)

This outputs:

commit dcc9dc60dc7ee615f35703c9a8e696d2dcae6d41
Author: Nicolas Fränkel <[email protected]>
Date:   Sun Apr 1 23:36:20 2018 +0200

    Add Spring Boot integration in IntelliJ IDEA post

      Fix #25

To limit the output to the commit value, use the --format option:

git log feature/newposts --format=%H -- $(git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-)

The result is:

dcc9dc60dc7ee615f35703c9a8e696d2dcae6d41

Cherry-pick

The final step is to cherry-pick the relevant commit. At this point, this is a no-brainer:

git cherry-pick $(git log feature/newposts --format=%H -- $(git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-))

Final touch

I didn’t find a way to cherry-pick into a specific branch, so that it adds the commit to the current one.

The above command just needs to be padded with a checkout to the master branch, and back.

git checkout master && \
git cherry-pick $(git log feature/newposts --format=%H -- $(git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-)) && \
git checkout -

As we’ve seen in an earlier post, if the snippet above is written in a bash script whose name starts with git- and that is located on the PATH, then it’s possible to invoke it through git:

git-publish
#!/bin/bash
git checkout master && \
git cherry-pick $(git log feature/newposts --format=%H -- $(git ls-tree -r feature/newposts  | grep `date +'%Y-%m-%d'` | cut -c54-)) && \
git checkout -

At this point, the script can be invoked like this:

git publish
Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Currently working for Exoscale. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Read More