Saturday, 24 May, 2014 —
git
development
My team is responsible for maintaining a production line in our various Git repositories. After releases, we’re responsible for merging the development line to the production line, so any bug fix release starts from the basis of what’s currently running in production.
Making a longer story shorter, we had a release that we cancelled and decided to roll into a future release. But this was after we’d already made the merge to the production branch. We further had a mix of fast-forward commits with no merge commit and non-fast-forward merges across the different repositories that comprise a product release. We want to get our production line back to where production is actually at.
I researched a few strategies, centered around git revert and git reset for how to step forward and wanted to test them out.
Since each Git clone is complete unto itself (and we use a single remote versus multiple points of authority), I have the entire public history. So, it’s very easy to make a copy of a repo, make a bare clone as a “remote” and test changes locally.
Before we start
First, some words about safety. Out of an abundance of caution, I recommend the following before we start the experiment:
- Make sure your remote origin is up-to-date
- Make sure you are up-to-date with the remote origin
- Make sure the remote origin is backed-up
- Disable networking on your machine until the experiment is concluded
I also need your understanding that I’m describing procedures for experimentation, not trying to solve for your problem. We’re going to use git reset below and it is a destructive action. You own your data and are much better equipped to understand your repository and situation. Act with prudence.
If you’re looking for info on addressing various changes to repositories, you’d do worse than having a look at Kai Howelmeyer’s “Git Undo by Example” post.
Local and destructive testing
Our safety pre-check complete, here’s how to test destructive Git repository changes locally:
Determine where you’re going to be working on this test. I recommend something like git-experiment underneath /tmp.
1
| $ mkdir -p /tmp/git-experiement/
|
Copy the repository in question to git-experiment, or clone if it’s a small repository. For this example, let’s pretend this repository is named smith. I’m going to refer to this as the local clone.
1
| $ cp -R /path/to/repo/smith /tmp/git-experiment/smith
|
Create a bare clone of smith in a new remotes directory. This will allow us to push the local clone to what we’ll call the remote.
1
2
3
| $ cd /tmp/git-experiment
$ mkdir remotes
$ git clone --bare smith remotes/smith.git
|
Go into your experimental copy of smith and open the .git/config file and update the url for the remote origin to point to your bare clone of smith.
1
2
| $ cd smith/.git
$ vim config
|
Before:
1
2
3
4
5
6
7
8
9
| [remote "origin"]
url = git@example.com:smith.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "production"]
remote = origin
merge = refs/heads/production
|
After:
1
2
3
4
5
6
7
8
9
| [remote "origin"]
url = file:///tmp/git-experiment/remotes/smith.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "production"]
remote = origin
merge = refs/heads/production
|
Go into the remote clone of smith. Instead of .git/config, open config here. Remove the remote origin block. Also remove branch info that ties back to origin. This isn’t strictly necessary, but we’re just going to keep things clean and not run the risk of pushing changes where they shouldn’t go.
1
2
| $ cd ../remotes/smith.git
$ vim config
|
Before:
1
2
3
4
5
6
7
8
9
| [remote "origin"]
url = git@example.com:smith.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "production"]
remote = origin
merge = refs/heads/production
|
After:
1
2
3
4
| [branch "master"]
merge = refs/heads/master
[branch "production"]
merge = refs/heads/production
|
With this done, clone the bare remote repository as a second working copy, if you’d like to check the workflow once you publish your destructive change.
1
2
| $ cd /tmp/git-experiment
$ git clone remotes/smith.git smith-two
|
Since there’s a good chance you’ll want to try a few different approaches of your destructive change, make a copy of your test set-up and set it as read only:
1
2
3
| $ cd /tmp
$ cp -R git-experiment git-experiment.orig
$ chmod -R ugo-w git-experiment.orig
|
Go into your experimental clone and make your destructive change and see what happens with it. You can safely push to your remote and see how that process works with doing a push and then git fetching or git pulling changes into the second copy.
In my case, I was experimenting with reverting branch merges and resetting and doing git push --force to publish changes. Below, I’m using HEAD@{3} but this could just as easily be a hash reference or a tag.
1
2
3
4
| $ cd /tmp/git-experiment/smith
$ git checkout production
$ git reset --hard HEAD@{3}
$ git push --force
|
The --force is important here, because otherwise, Git believes you to be doing something it doesn’t think you should. And 99 percent of the time, Git would be correct, but we’re explicitly seeking to do something destructive.
Go check the results of your experiment in the second local clone:
1
2
3
| $ cd /tmp/git-experiment/smith-two
$ git checkout production
$ git pull --rebase
|
When you’re done, package everything up with a note or just rm -rf /tmp/git-experiment. If you’re saving the iteration, give it a meaningful name:
1
2
| $ cd /tmp
$ tar -czf git-experiment.git-reset.tgz git-experiment
|
Results and Iteration
The first experiment is complete. You can shake out what to do and discuss it with your team, safely not affecting what other users are seeing on a repository. Determine what your next steps are, then move your original test aside, copy in the back-up and run further iterations.
In particular, you may have other questions to consider, such as determining what happens if you force a merge commit, provide tags, delete branches, and so on. What’s it going to be like publishing the changes? What’s it going to be like trying to fetch or pull the changes? Are there any other workflow considerations? How are you going to inform other users?
Hopefully, these experiments help you sort that out and provide a well-known path for your users. This contained experiment gives you a margin of safety to answer those questions.
Happy experimenting.
Saturday, 17 May, 2014 —
development
improvement
For some background on what’s going on here, see the first tool sharpening post
In the past week, I’ve put a heavy focus on tuning up BBEdit. As part of this, I reread the BBEdit 10.x release documentation to get a better sense of features I was overlooking. I found number things to identify and tweak.
- Installed new-to-me BBEdit language modules
- Installed two new BBEdit packages
- Better Tongs for improving text selection and manipulation with some helper scripts
- Email for working with email composition through BBEdit. This is built for Mutt, but I’m going to see if I can make it useful anyhow
- Created a BBEdit project with
/etc/hosts, ~/.ssh/config and ~/.ssh/known_hosts, files I typically need to touch or update frequently as I work with local Vagrant virtual machines
- Created a Text Expander shortcut to set-up Jinja2
if blocks for Ansible templates
- Created a BBEdit project for working with BBEdit packages, scripts and settings
- Updated BBEdit keyboard shortcuts to:
- Copy the url of a given file. That ends up looking like
file://localhost/foo/bar/baz/bippy/2014-05-18-tool-sharpening.html.md
- Set-up a Git commit message template
- Removed some OS X system-level keyboard shortcuts that were interfering with BBEdit-specific shortcuts for manipulating text
- Unbeknownst to me before reading the 10.x documentation, BBEdit has shortcuts for moving lines up and down and deleting lines without needing to invoke the clipboard or select the whole line. No, this isn’t different than what vi(m) or Emacs provide for, but a particularly good reason for me to review what the capabilities of my editor are.
A larger aim I’ve had with this project is finding somewhat like activities and starting to refactor them so they can be automated. For instance, I want to have a standard way of prefacing new OmniFocus entries I make for ideas. Then, I can trigger that same entry with Text Expander. From there, I expect I could script a pass through OmniFocus and either auto-file things or do some other post-processing with them. The goal I have is to use OmniFocus on my desktop, iPad or iPhone as an entry point, but have a desktop-based script go into my OmniFocus inbox and filter those idea items into text files, like the one I keep as a Markdown list for improving my environment set-up.
Sunday, 11 May, 2014 —
development
improvement
For some background on what’s going on here, see the first tool sharpening post
In the last couple of weeks, I’ve made the following adjustments to my developer environment + closely related computing set-up:
- Created an initial MiddleMan template to make aggregating my tool sharpening changes easier. I expect this will make it easier to prep tool sharpening blog posts on a regular basis I can go back and review.
- Tuned my work email rule filtering so most automated/generated messages bypass my in box to their final destination
- I then use two Smart Folders, one called “New” and the other “Recent” to see unread messages and recent messages regardless of read status
- Added an OmniFocus perspective called “Recent Additions” based on a Merlin Mann suggestion on a past Back to Work episode. I keep my iPad with me and update OmniFocus during my team’s daily standup and this perspective is a good help to find and further process entries I make when I get back to my desk
- Added Solarized theme for BBEdit
- Built a BBEdit text filter in Ruby that takes a column of numbers and adds them
- Created an initial BBEdit Package for the text filter and posted it to GitHub.
- Installed Editor Actions for BBEdit
- Created an “Exploration” BBEdit project so I have a workspace for one-off investigations
- Created an “Exploration” Tmuxinator profile so I have a workspace for one-off investigations
- I also made a lot of OmniFocus entries regarding additional BBEdit text filters, shell environment improvements and Text Expander shortcuts to add
Looking over the list, I’m pretty happy. I’m still integrating a few of these changes as habit. A few of these items may not end-up sticking. The key improvement I’d like from here is improving my consistency. The schedule of my work day has shifted around some, so it’s not quite as feasible to pull an desired improvement off the stack for implementation. To that end, I am going to attempt to pull an improvement to implement at the end of the day when everything is winding down. That way, I’m quite likely to have a small accomplishment to bridge into the next work day with.
Saturday, 3 May, 2014 —
practice
development
podcasts
I have a roughly 20 to 25 minute commute five days a week from our house in North Raleigh to NC State’s Centennial Campus. Most days, I use the drive time to listen to a podcast.
I have two must listen podcasts every week:
There are two other, more technical, podcasts that I also listen to and cycle in every couple of weeks:
I have about 3 1/3 to 4 hours of otherwise lost time each week driving. I use that time to listen to these podcasts for two related reasons.
First, I do not have a better time to listen to these podcasts, largely because of how my sense of time and focus work. All four of these podcasts demand my full attention. I could not be successful in listening to these podcasts and trying to program or read attentively. I use music in those instances. I can, however, focus well on the task of driving, and pay attention to the podcast fairly well.
Second, all four of these podcasts feature smart people in their respective crafts thinking out loud. I, in turn, find myself thinking as a result and drive time is time I am not otherwise trying to focus creative attention elsewhere.
Each of these four podcasts is worth a post of it’s own, which will come in due time. I am, however, capped at these four. There are weeks that I can listen to only one full and part of another episode, depending on episode length. There are weeks where I really need to listen to music for a day or two. While there are many other great podcasts around that I would love to also listen to, I listen to these four at most because that’s as much as I can stay reasonably close to caught up with given how much time I’m willing to spend on it.
This is one of my established daily practices.
Tuesday, 29 April, 2014 —
development
improvement
Back in the fall, Ben Orenstein of thoughtbot was on the Ruby Rogues podcast and talked about sharpening tools. Making his vim profile better, interacting with his desktop better. In some way, he’s making his life as a developer better, every day.
He said:
I’m a huge believer in the power of habits. I think the things you can manage to make yourself do regularly can have incredible results. And so, a few years ago, I’d say five years ago, I decided to get kind of serious about making my environment really excellent and improving my efficiency that way. And so, I got in this habit of spending the first ten or 15 minutes of my day on tool sharpening. And so, what I started was I started a little text file that I would add to during the day. So, when I was doing something that felt inefficient or felt like whenever I had that inkling, “There must be a better way of doing this,” I’d add it to the list. And then I’d pull one of them off in the morning.
And so, I started most mornings by just doing something simple like making an alias for a command I use in the shell a lot. Or something like, I finally need to research how the Vim expression register works and go do some diving on a readme or something like that. And I thought of it as sort of slowly sanding down the rough edges of my environment. So, anything that kind of like irked me, I would try to spend a little time on every morning. And what I found was not very long of this, I was noticeably faster at the things I needed to do every day. And it was starting to have a huge impact on my productivity. And so, I started talking about that.
Five years of daily tool sharpening or tool making seems like it would lead to some transformative changes in work habits and flow. To that end, I’ve spent some time recently attempting to make some adjustments to my own environments. I’ll enumerate some of them:
- Read up on homebrew services
- Adjusted my tmuxinator set-up
- Added a profile for a Tech Week project
- Added tmuxinator invocation shortcut
- Installed the Silver Searcher
- Set-up ctags in a project as an experiment
- Installed + purchased Dash
- Repaired tools + resources links on my tools page
- Installed MsgFiler
- Created a clipping to insert an Emacs-style counterpart comment in BBEdit source files
- Found a Safari extension that can normalize the size of Safari windows
- Installed Total Terminal for a keyboard shortcut available terminal window I can use for one-off commands.
- Updated BBEdit prefs to use Dash for “Find in Reference”
This isn’t an exhaustive list of what I’ve done since my curiosity was piqued by what Orenstein was describing. I wanted to share the list to inspire someone else to try out the practice and prompt myself to reestablish the habit.
I plan to revisit this with new entries occasionally.