Recently I’ve been working with PHP applications in varying states of modernity/antiquity, and very regularly have to switch the current PHP version to accomodate the PHP flavors of the day. Homebrew un/link commands are super simple and at this point all I want is to be able to switch the PHP version with a single command. With a little bit of searching, I found a script that comes pretty close to what I need:

I made a fork, and then removed Apache stuff and unused code, converted conditionals to guard clauses, ran the remainder through shellcheck, and addressed a couple of minor consistency/grammar issues to achieve the following result:

During a recent group debugging session at work, I was reminded about tmux. I hadn’t really used it outside of a couple of brief experiments that were little more than opening the application (and then struggling to kill it), so on this occasion I used screen. Whatever the reason, apparently now is the time for tmux! In this post, I’ll cover a few of the impediments and blessings encountered so far, since I seem to have gotten the good kind of tmux bug.

I’ve had an inherited .tmux.conf file in my forked “dots” repo for years, but it’s done little more than gather dust. In fact, firing up tmux for the “first” time revealed that my config was not entirely compatible with the latest version of tmux. I started by commenting out offending lines and then read up on what most of the config declarations were meant to do. In the end, I landed on a config that’s a blend of niceties discovered through researching various bugs and peeves.

I’m a zsh user. After working through the obvious errors printed to screen on tmux startup, I hit a bit of a roadblock with substring history search not working. This one plugin is a major reason I’m a zsh user. After trying a bunch of suggestions from the Internet, this bug was stubbornly not budging. Then I stumbled on a reference to this issue having been addressed in the plugin, and realized I hadn’t updated my zsh plugins in a loooonnnggg while. I ran zgen selfupdate && zgen update, and the bug was no more.

I’ve come to appreciate immersive computer applications, and the iTerm2 app title bar just seems like so much wasted screen real estate. Newer versions of iTerm2 provide a config for this in Preferences > Profiles > Window > Style > No Title Bar. With the move to tmux, this seemed like an especially useful config change.

Next I had to learn the “tmux way” for viewing backscroll. I’m very patterned to using the mouse to scroll up or the iTerm2 “find” feature to locate strings in the backscroll. At first I thought, “Maybe the backscroll is just gone? Guess I’ll pipe to less and that will be a new thing I’ll have to add to commands now.” Silly brain… of course, this is built into tmux (Yay copy-mode!). It turns out tmux copy-mode is kinda better than I could have hoped. It encourages a consistent experience between editor and command line, and makes it so easy and seamless to navigate these contexts.

The last thing I’ll mention is CMD-K. I use this in the terminal all the time to make it easier to know where output from a particular command or session begins. It’s super helpful when debugging tests or with verbose commands such as strace, and in a variety of other contexts. In tmux, CMD-K doesn’t work so well. But you can get basically the same result with mapping CTRL-K as follows:

# Clear the current pane.
bind -n C-k send-keys -R \; clear-history

That’s all for now. Happy multiplexing!


I found that the above pane clear declaration was a little aggressive in that the prompt string doesn’t re-appear. The following doesn’t have that problem:

# Clear the current pane.
bind -n C-k send-keys C-l \; clear-history

I haven’t been very active on here lately, but hopefully that will change in the coming months. As a part of reinvigorating my technical writing and removing barriers to writing new blog posts, I converted the generator for this site from Jekyll/Octopress to Hugo.

The conversion process was smooth and now the site is generated in much less than a second. Probably the biggest benefit is that dependency concerns to build and manage the site have dropped off a cliff.

I’ve been thinking about the vulnerability of the primary Git branch for the last several weeks. Mostly out of paranoia about destroying a critical application. I added protective measures to my local clones on important projects and was content in thinking that I was now safe. But today I was reminded that this is only a small part of protecting a collaborative project.

Here’s what happened:

  1. User 1 made a commit on master and pushed to origin
  2. User 2 fixed a bad merge on branch feature and ran git push --force
  3. User 1 made a tag directly on the remote and deployed to Production
  4. User 1 saw the new tag in production, but the new commit was missing

The problem was introduced with the git push --force. User 2 must have had a Git push configuration of default = matching. This is the default in Git version pre-2.0, but can still be set explicitly on newer versions. The result was that the intended feature branch was force pushed, AND the master branch was also force pushed!! Yikes.

We lucked out, as the newly deployed tag was identical to the previous tag and there was no production impact. But the result could have been much, much worse.

Here’s what we’re doing about it:

  1. Add local force push protection for the master branch with a pre-push Git hook and push config enforcement
  2. Add protection to the master branch of our Github mirror if possible

We already use a script to add a pre-commit static code checker, so it should be pretty quick to add a pre-push hook from the following Gist:

The one case this hook doesn’t cover is the exact scenario described above. In order to protect against this, we can add local Git configuration to ensure the default push behavior as anything other than matching. My current preference is for nothing, but really any of simple, current, or upstream should work fine.

We use Github primarily for code reviews and mirror our repo there via Jenkins. It’s not clear whether branch protection is compatible with mirroring via Jenkins, so that’ll need some more research.

Over the weekend, I’ve been cleaning up, organizing and improving my dotfiles. Below are a couple of things that I’m most excited about.

Zsh in Vim Mode

I’ve been using zsh for a while, but only recently starting using zsh in Vim mode. One thing that’s been sorely missing is moving by word in INSERT mode. I got this working by adding the following to ~/.zshrc:

bindkey '^b' backward-word
bindkey '^w' forward-word

With this config loaded, I can move forward by word boundaries with Control-w and backward with Control-b. Lot’s more configurations are listed here.

Git Advanced Aliases

I’ve been assembling Git shortcuts into a separate “functions” dotfile, but learned that it’s maybe cleaner to use Git advanced aliases. You can read more about advanced aliases here.

The advanced alias I’m most excited about is triggering a post-push hook, which is not provided in Git core. The below solution is adapted to a Git advanced alias from this Stack Overflow thread:

  # Wrapper for git push to enable a post-push hook
  push-with-hooks = !"f() { \
      local GIT_DIR_="$(git rev-parse --git-dir)" \
        && local BRANCH="$(git rev-parse --symbolic --abbrev-ref $(git symbolic-ref HEAD))" \
        && local POST_PUSH="$GIT_DIR_/hooks/post-push" \
        && git push "$@" \
        && test $? -eq 0 && test -x "$POST_PUSH" \
        && exec "$POST_PUSH" "$BRANCH"; \
    }; f"

With the above in place, put the following in an executable file at .git/hooks/post-push:


echo "$@"

This doesn’t do much as-is outside of echoing the current branch to STDOUT, but could be used to trigger a build, or all kinds of fun things!