Wednesday, June 3, 2015

More Git Commit Recovery With RefLog

Yesterday I blogged about how I lost and then recovered a few commits in a small project I'm working on using git's cherry-pick command. Till Maas pionted out on G+ that you can get a list of the commits in your git repo with "git reflog".

The reflog command (for reference log in case the contraction was lost in you) lets you look back into the repository history beyond what makes up its current state. In our case, it can show past commit hashes so we can find and recover a commit. This would have come in handy had I not had the output of a git log in my terminal yesterday.

So, for example, I could look back through the history of my project to find all of my previous commits with:

 $ git reflog show  | grep commit
b3c1cf2 HEAD@{0}: commit (amend): Created the initial application shell.
1fc7d5a HEAD@{1}: commit (amend): Created the initial application shell.
f8df984 HEAD@{2}: commit (amend): Created the initial application shell.
801787d HEAD@{9}: commit (amend): fixup! Created the initial application shell.
c23dde8 HEAD@{10}: commit (amend): Added a Glade described main window.
d16b829 HEAD@{18}: commit (amend): Got a basic running application.
c49a3cb HEAD@{19}: commit: Got a basic running application.
f43fe07 HEAD@{25}: commit (amend): Added a Glade described main window.
f02d3bd HEAD@{26}: commit (amend): Added a Glade described main window.
92a16aa HEAD@{30}: commit (amend): fixup! Created the initial application shell.
4c8b148 HEAD@{31}: commit: fixup! Created the initial application shell.
5db5426 HEAD@{32}: commit (amend): Added a Glade described main window.
11a6b02 HEAD@{33}: commit (amend): Added a Glade described main window.
df9f92e HEAD@{34}: commit (amend): Added a Glade described main window.
3deafab HEAD@{35}: commit: Added a Glade described main window.
6330fe5 HEAD@{36}: commit (amend): Created the initial application shell.
a5eda9c HEAD@{37}: commit (amend): Created the initial application shell.
fcb58eb HEAD@{38}: commit (amend): Created the initial application shell.
2a0d994 HEAD@{39}: commit (amend): Created the initial application shell.
32b8ea8 HEAD@{40}: commit (amend): Created the initial application shell.
165ae57 HEAD@{41}: commit (amend): Created the initial application shell.
33f9885 HEAD@{42}: commit: Created the initial application shell.
5ea907a HEAD@{43}: commit: Created an initial to-do list of tasks for the project.
40a2f7a HEAD@{44}: commit (amend): Updated the README file with a little more details.
7d32cb2 HEAD@{45}: commit (amend): Updated the README file with a little more details.
53984e2 HEAD@{46}: commit (amend): Updated the README file with a little more details.
360ea5c HEAD@{47}: commit (amend): Updated the README file with a little more details.

And from this list I would have been able to find the commit(s) I wanted to recover using git show and then cherry-picked the appropriate one once found.

Thanks Till!

Tuesday, June 2, 2015

Recovering A Lost Commit With Git

Ever have one of those days where you make a bad decision?

No, I mean with writing code.

You do?

How about with source control? Things like deleting a commit on your work branch and then realizing you didn't mean to delete it?

Well, guess what? You're in luck! Git doesn't throw away your commits! And if, like me, you've accidentally.....okay, INTENTIONALLY deleted some work and then realized you want to recover it, you can!

A little background: I'm playing around with a tool to let me create and post a series of entries on the blog for my comic book podcast (The Comic Book Update). What I do now is manually schedule hourly posts of comic previews when the publishers send them to me. Which results in about two hours throughout the week (usually while drinking coffee and watching the news) of creating 60 posts (10 posts per day) and setting the scheduled time.

Tedious, I know. So I want to create a tool to do this.

Long story short, I started playing with a Ruby solution, a Python and a Java solution. But after deleting Ruby, I realized I in fact DO want to use it. And it was the one I had explored the most, but dammit I already deleted it!

Except, in my terminal buffer, I could still get to the commit hashes for the Ruby version!

So what I did was checkout a clean branch in my project repo. I then scrolled up and, one by one, did a git cherry pick of each of those hashes.

Voila! Commits were recovered!

The reason why is that, even when you delete a commit with "git reset --hard HEAD~1" or doing an interactive rebase and deleting commits from the list to be included, git does NOT actually throw the commit away. Instead it leaves it in the set of objects in your .git directory until such a time as you do garbage collection.

If you go into a repo and peek in the .git/objects directory you'll see a series of directories name 00, 01, ..., fe and ff (or some subset of them). Each of those is composed of multiple files, each representing a different commit. The parent directory is from the first two characters of the commit hash, and the filename is from the remainder of the hash. So if your hash id was f43fe07d9df08fdb6440c562639eb4ad4ce4c49e then you'll find that specific commit itself in .git/objects/f4/3fe07d9df08fdb6440c562639eb4ad4ce4c49e.

Such a nice turn of luck not having to rewrite that initial bit of code....thank you git!

Monday, June 1, 2015

Finding That Sweet Spot: Focus On Guake

One of the things I do quite often is go to a terminal, do some short command or two, then close the terminal. I do this away from my coding terminal as I don't want to contaminate bash history with those commands, mainly because I do a lot of repetitive things [1].

The application I use for such things is Guake, a great little popup terminal application that gives me exactly what I need: a simple terminal that I can show and hide without having to launch a new app. It's available on pretty much all Linux distros, so I don't think I need to tell you how to get it on your system.

The way I have Guake configured is to popup up as a small window (50% width, 50% height) at the center bottom of my current display (on my two-monitor desktop it follows the mouse pointer).

I like to have my desktop be visually appealing since I spend so much time in front of it, so I've played with various colors, layouts, etc. to get things just right. And for me, what I have now works well.

Placement shows the terminal the currently active desktop (the one where my mouse is at the time), and it pops up on top and stays on top of any other application. I have the transparency of the window set to about 15% or so to allow me to see through the window: this way I can read something on my browser or editor, for example, without having to close and re-open Guake.

To open Guake, I have F12 as my hotkey, with F11 to make it full screen. These are the default and they make perfect sense to me. Though, on my keyboards when I'm docked, F12 and Print Screen are close enough together that I will hit the latter at least once per day by mistake. So every weekend it seems I'm deleting a half dozen screen shots.... :D

The color scheme I chose is called "Hipster Green" (yeah, I hate that name too). For me I find the monochrome-like colors more visually appealing, not to mention less harsh on the eyes if I'm on my laptop in a dimly lit room [2]. I use auto-colors in ls and the monochrome color scheme fits well with it.

The option I go back and forth on is showing the tab bar. On the one hand I like to be able to quickly jump to a tab I want if it's open. But on the other hand I don't normally have more than two or three open at a time. So I hate sacrificing even that small bit of real estate. So it depends on how I'm feeling at any point whether it's enabled or not.

To open URLs that appear in the window, I've checked the Enable Quick Open when Ctrl+clicking on a filename in the terminal option (verbose, right?) on the Quick Open tab.

All in all, Guake is a great, useful tool for me to perform quick tasks from a command line without having to either pollute my primary command history with trivial little things. All in a tool that is easily launched, used, and dismissed quickly.

[1] - I will, for example, have the following three commands in my coding terminal's history:

  $ git clean -xfd && cmake all
  $ [run some test script, example app or other]

My main workflow in those cases it to build the world, run whatever I'm working on, then scroll through the output and fix things in my editor. Then I go back to the coding terminal and hit Up Up Enter, wait a second, then Up Up Enter again.

[2] - I LOVE to write code during a rain storm. Some of my favorite times have been to sit on the couch in my office at home while it's pouring rain out and work on code to the soothing sounds of rainfall.