- Published on
Git forward and backward in tree history. It's not Klingon, it's a nice Bash oneliner
- Authors
- Name
- Lorenzo Pieri
- @404answnotfound
Table of Contents
Bash oneliner to move forward and backward in Git tree
This is not going to be one of the usual articles where I'm going to drop off some jokes while we all learn something new.
Who am I kidding.
So. Long story short, the other day I was developing a little CLI that should be helpful for beginners to learn the ways of git
while also embracing a very opinionated way of dealing with version control both locally and with origin.
The tool is called flig but this is not yet the time to unveil the badass tool so :bear: with me while we discover a really nice oneliner I developed to: * drum rolls *
git
commit tree without prior knowledge of the commit hashes.
Moving back and forth in the Yeah, I did tell you it was cool. You just didn't expect this cool. Deal with it.
git log --all --oneline | grep -B 1 $(git rev-parse --short HEAD) | awk '{print $1}' | head -1 | xargs -I {} git checkout {}
This is the little magical oneliner that can help us move forward while, to move backward, we need to do a little change:
git log --all --oneline | grep -A 1 $(git rev-parse --short HEAD) | awk '{print $1}' | tail -1 | xargs -I {} git checkout {}
Can you see the change?
I'll leave it as a very boring exercise to the reader to find the only thing that changed between those two. Or you can even go further and diff
to find the differences. That'd be an overkill tho.
So, anyway. Explanation time.
The little |
character is called pipe
and it's a very useful terminal tool that pretty much takes whatever the output of the command is and forwards it to the next command. Very badassy.
This first part of the command is the entry point. It pretty much asks git
to show the logs of all commits in a oneline
fashion. Afterwards, it pipes
everything that the command outputted to the next one.
git log --all --oneline |
The output would look like this:
c4cb3f1 (HEAD -> main, origin/main, origin/HEAD) A commit message
453a23b A commit message
e99539d A commit message
f073dd5 A commit message
973354d A commit message
90ff07c A commit message
...
With this command we are using the utility grep
which helps us find patterns, characters, words and so much more. We use grep
to look for what that other (command)
is going to output. Big spoilers, it's going to return the hash of the current commit we are on, with a short hash instead of the entire row.
Now, take a close look at that piece of magnificency that is -B 1
. That bad boi is actually allowing us to also return the previous row of the output, effetively returning not only the results of the git rev-parse
command, but also the previous line.
grep -B 1 $(git rev-parse --short HEAD) |
The output would look like this:
e99539d A commit message of the previous commit
f073dd5 A commit message of the current commit
That output is then passed on (or better yet, piped into
) the awk
command.
awk '{print $1}' |
The output would look like this:
e99539d
f073dd5
We are printing/returning just the necessary text we need, which is to say, the current and previous commit short hash :)
That output is then piped into
the head
command which takes care of selecting just the previous commit, leaving the current one alone.
head -1 |
It will look like this:
e99539d
And finally the xargs
magic comes into play. The head -1
command piped
the resulting commit short hash into the xargs
utility which will, in this particular case, use that value to replace the {}
in the git checkout {}
command.
xargs -I {} git checkout {}
By wrapping it all together in a single line command we just created a command to move back (and with the other) forth the git commit tree without having prior knowledge of the hashes it contains.
The goodbye
I hope you found this article useful and to your liking and if you have any requests, drop a message on one of my social media accounts or open an issue/start a discussion on github, on this repository!
As always you can find me on Twitter, listen to my Podcast on Spotify and add me on LinkedIn to talk professionally (yeah, right)