Basic Git Setup

Every time I change my computer or my operating system1, one of the first things I have to do is to configure Git. This article simply covers the basic Git settings that I always adjust.

So, here’s what I’d typically do:

# user identity
$ git config --global user.name "Bozhidar Batsov"
$ git config --global user.email bozhidar@example.com
# editor to use by default for things like commit messages
$ git config --global core.editor emacs
# auto-rebase when pulling
$ git config --global pull.rebase true
# auto-convert CRLF to LF
# useful if you're working on Windows and there are people on your team who are working on Unix
$ git config --global core.autocrlf true
# the name of the primary branch (formerly known as master)
# that's a pretty recent setting, but it's useful for new projects
$ git config --global init.defaultBranch main

I guess for many people it’d also be useful to specify their preferred merge tool:

$ git config --global merge.tool some-tool

To me, however, that’s irrelevant as almost all of the time I’m interacting with Git via Magit. If you’re looking for an excuse to try out Emacs, you’ll be hard pressed to find a better excuse than Magit.

The global Git user settings are simply stored under ~/.gitconfig, so you can easily review and update them there as well. You check your current configuration running this command:

$ git config --list

Note that this effective configuration would be a combination of OS-wide config (e.g. /etc/gitconfig), your user-wide config (e.g. ~/.gitconfig) and the config of the Git repo that you’re currently in (e.g. `repo/.git/config).

When working on company projects, I would change for each company repository my email to whatever my work email is:

$ cd company-project
$ git config user.email bozhidar@company.com

If you’re working on multiple company repositories the above solution will quickly become annoying. In such cases you may want to use Git conditional includes, which basically allow you to include a different configuration file in your main Git config, based so on some rules.2 In our case we can have a different configuration for the e-mail based on the repository directory path. Here’s an example .gitconfig to illustrate this:

[includeIf "gitdir:personal/"]
  path = .gitconfig-personal
[includeIf "gitdir:work/"]
  path = .gitconfig-work

Now, any Git repository under a folder called personal (anywhere on your file system) will use the personal email address, and any repository under a folder called work will use your work email address. This matches my preference to keep my personal projects under ~/projects/personal and the work under ~/projects/work.

The contents of .gitconfig-personal can be something like:

[user]
  email = bozhidar@home.com

And the contents of .gitconfig-work can be something like:

[user]
  email = bozhidar@work.com

And that’s it. Turns out my basic Git setup is pretty basic. Check out this section of the official docs for an expanded coverage of the topic. You can find way more configuration options here.

That’s all I have for you today. I’d appreciate it if you shared in the comments some snippets of Git configuration that you consider essential.

  1. This has been happening quite often recently and I’ll cover it in a separate article or two. 

  2. Special thanks to my readers who suggested this setup to me. 

Rename Multiple Files in Linux

From time to time we need to rename a bunch of files according to some pattern. One simple example that comes to mind is that recently I noticed that some articles in my blog had a .md extension and some had a .markdown extension. I don’t like inconsistencies, so I wanted them all to have a .md extension. Bellow I’ll cover several ways to do this on Linux1. All the examples will assume you’re renaming files in the same folder, but it’s typically trivial to extend them to a directory tree by combining a command with find -exec or extended globbing (e.g. **/*.markdown). So, here we go.

One simple option is to use the rename utility from the util-linux package:

$ rename markdown md *.markdown

Basically you’re doing a text substitution in the list of files passed to the command. The problem with this is that it won’t work properly in cases like markdown.markdown. Fortunately, Debian and Debian-derived distributions (e.g. Ubuntu) ship a more powerful version of this command, that’s written in Perl, and supports regular expressions.

$ sudo apt install rename
$ rename 's/\.markdown$/.md/' *.markdown

The regular expression allows us to be specific about the match and prevents the problem listed above. By the way, generally it’s a good idea to first preview any changes that the command might perform with the -n option:

$ rename -n 's/\.markdown$/.md/' *.markdown
rename(2008-05-05-first-post.markdown, 2008-05-05-first-post.md)
rename(2008-06-16-das-keyboard.markdown, 2008-06-16-das-keyboard.md)
rename(2008-06-19-emacs-rails.markdown, 2008-06-19-emacs-rails.md)
rename(2008-07-27-zsh-prompt.markdown, 2008-07-27-zsh-prompt.md)
rename(2008-09-29-singleton-java-ruby.markdown, 2008-09-29-singleton-java-ruby.md)
rename(2009-05-04-switch-string-idiom-java.markdown, 2009-05-04-switch-string-idiom-java.md)

Super handy!

If you don’t want to use an external command you can leverage some shell features instead:

$ for f in *.markdown; do
    mv -- "$f" "${f%.markdown}.md"
done

This relies on some relatively advanced substitution features of Bash and Zsh, that are beyond the scope of today’s article, but it gets the job done. Interestingly enough, Zsh provides a much simpler and way more powerful way to tackle mass rename, via the zmv utility it bundles:

$ zmv '(*).markdown' '$1.md'

While zmv doesn’t use regular expressions, it’s matching and substitution functionality should cover pretty much everything you decide to throw at it. Note that zmv is usually not enabled by default and you might have to load it manually before using it:

$ autoload -Uz zmv

Notice also that in the first argument of zmv you’ve specifying both the search pattern for files and substitution groups you can use in the second argument. You can do way more complex renamings with zmv:

# rename dir1/file.txt, dir2/file.txt, etc to file-1.txt, file-2.txt, etc
$ zmv zmv 'dir(*)/file.txt' 'file-${1}.txt'

Obviously sky is the limit here, although this applies to the Perl version of the rename command as well. One cool thing about zmv is that you just like with rename you can preview the changes it’s going to do with the -n option.

$ zmv -n '(*).markdown' '$1.md'

This will help you to quickly find the right pattern for the mass rename you’re trying to perform.

That’s all I have for you today. I’ve barely scratched the surface of what’s possible, but I still hope you learned something new and useful. Keep hacking!

  1. Most of those suggestions should also work on other Unix-like operating systems like macOS, *BSD, etc. 

HEY

That’s going to be one really short post. I just wanted to share with you that I’ve been using HEY (a new e-mail service from Basecamp) for the past few months and overall I’m quite happy with it. This article is not a review of HEY, it’s more an announcement that now you can reach me at myfirstname@hey.com if you’re into e-mail.1

I’ll keep my @batsov.com e-mail backed by GMail for the time being, as I didn’t really have any fundamental issues with GMail, other than my dislike for Google’s (mis)handling of private data. That being said, I want to expand my usage of HEY going forward. I’ve already moved there all my newsletter subscriptions, as HEY has great support for newsletter, and I’ve also been trying to have most of my conversations with people over HEY as well. To help with this I’ve updated most public mentions of my e-mail (e.g. on GitHub) to point to the new HEY-powered address.

HEY is definitely not perfect (e.g. the message editor feels inferior to what you get in GMail, and the same goes for search functionality), but I love the philosophy of the service and I’m always open to trying new ideas and workflows. I hope that down the road I’ll manage to break free from the grip of Google and leave GMail for good, but that mostly depends on how HEY will evolve and how well will I adapt to using it. In the mean time - I’m looking forward to chatting with more of you over HEY!

  1. I hope it’s clear that you have to replace myfirstname with my real first name. :D 

Ubuntu Tip: Removing All Packages Installed from a PPA

PPAs (Personal Package Archives) are a popular way to install pre-built packages that for some reason are not (yet) available in Ubuntu’s standard package repositories. Some common examples that come to my mind:

  • installing the newest release of Emacs
  • installing the newest GPU drivers

Eventually, if you’re lucky1 you might not need the packages from the PPA anymore, so this brings us to the question of today’s article - how can you quickly remove everything you installed from a PPA? If you installed only a single package that’s not a big deal, but you might have installed dozens of packages from one PPA. A good example would be oibaf/graphics-drivers. Once you no longer need the newest drivers (e.g. after a distro upgrade) you can remove all of them like this:

$ sudo apt install ppa-purge
$ sudo ppa-purge ppa:oibaf/graphics-drivers

This will remove all packages installed from the PPA. Depending on whether the packages exist in other enabled repos or not that might result in downgrade or complete removal of those packages. In the specific example I’ve given we’d just downgrade all video driver packages to their versions available in Ubuntu’s own repos.

That’s all I have for you today. Keep hacking!

  1. Or unlucky - imagine some snapshot versions crashing constantly. 

Meta Redux

This site was my first attempt to write. I failed miserably and I produced some pretty crappy content, but I also learned a lot in the process.

Over the course of a decade the blog saw quite a few transformations and shifts in my focus and interests. For a few years it was named DevCraft1 and it was hosted on wordpress.com. Afterwards I adopted the (think) title and switched to Jekyll, Octopress and then again to Jekyll. Originally I was writing mostly tutorials on topics like Linux, Java, Emacs and Ruby, but eventually I started writing some essays as well (my favorite type of posts). As my OSS portfolio grew it started to gain significant coverage in my blog as well. (think) was a bit messy and without a clear direction, but I guess it was a somewhat accurate reflection of myself as well.

I’ve thought at times about deleting some of my lame articles and heavily copy-editing the rest to make them fit my current beliefs and standards of quality, but this approach felt like cheating to me. I was who I was and I wrote what I wrote. To me that certainly has a lot of value. I’ve been thinking lately that being (very) critical of your old work is a good indicator that you’re moving in the right direction. We can always do better, but we need to reach a certain level of experience to see that.

For various reasons (mostly a combination of frustration with Octopress and my (immense) laziness), I didn’t write anything between 2015 and 2018 and when I finally mustered the will to return to writing I decided to go with a clean slate and a new blog.2

These days most of my writing happens at Meta Redux, but I still plan to post here things that are worth sharing, but don’t fit the overall idea of Meta Redux (where my primary focus is my OSS work and essay-like articles).3

I guess I’ll still be writing here on programming-related topics, but who knows… Knowing me there’s a high chance I won’t actually write anything at all! There’s a good chance this will be final (think) article.

At any rate - it’s still a lot of fun to be re-reading my old articles (especially the rants) and comparing the person I used to be with the person I am today. I’m starting to think that’s the biggest value of running a personal blog - it’s a written account of our evolution as human beings.

  1. I used to be a huge StarCraft fan. 

  2. I also wanted a blog with a cool (for some definition of cool) name this time around. 

  3. I still write the occasional short Emacs article at https://emacsredux.com