Tagged with “git”

Pruning old Git branches

Here’s a quick tip for Git users: if you want to delete every local branch that’s already been merged into master, you can run this command:

$ git branch --merged master | egrep -v "(^\*|master|dev)" | xargs git branch --delete

A quick breakdown:

I originally got the command from a Stack Overflow answer, although I tweaked it when I read the documentation, to more closely match my use case.

If you want to see what branches this will delete without committing to it, run everything before the second pipe — not the xargs bit at the end.

The other command I often use is this one:

$ git fetch origin --prune

If a branch has been deleted in the origin remote, and you had a local branch which was tracking it, the local branch gets deleted as well.

For example: suppose you had a branch called new-feature. You push the branch to GitHub, open a pull request, and later the branch gets merged and deleted through the GitHub web interface. When you do your next fetch with --prune, it’ll clean up the local branch new-feature.

Git branches are very cheap — usually a single file that references a commit hash — so deleting branches won’t save disk space or improve performance. I like to keep my repos neat and tidy, and not have a long branch list to scroll through, which is why I do this. If a long branch list doesn’t bother you, then you can ignore these commands.

A plumber’s guide to Git

Git is a very common tool in modern development workflows. It’s incredibly powerful, and I use it all the time — I can’t remember the last time I used a version control tool that wasn’t Git — but it’s a bit of a black box. How does it actually work?

For a long time, I’ve only had a vague understand of the Git’s inner workings. I think it’s important to understand my tools, because it makes me more confident and effective, so I wanted to learn how Git works under the hood. To that end, I gave a workshop at PyCon UK 2017 about Git internals. Writing the workshop forced me to really understand what was going on.

The session wasn’t videoed, but I do have my notes and exercises. There were four sections, each focusing on a different Git concept. It was a fairly standard format: I did a bit of live demo to show the new ideas, then people would work through the exercises on their own laptop. I wandered around the room, helping people who were stuck, or answering questions, then we’d come together to discuss the exercise. Repeat. On the day, we took about 2 ½ hours to cover all the material.

If you’re trying to follow along at home, the Git book has a great section on the low-level commands of Git. I made heavy reference to this when I wrote the notes and exercises.

If you’re interested, you can download the notes and exercises.

(There are a few amendments and corrections compared to the workshop, because we discovered several mistakes as we worked through it!)

Read more →

Some useful Git commands for CI

I spend a lot of time writing build scripts for interacting with Git repos. But Git’s documentation is notoriously opaque, and a lot of my Git knowledge comes from word-of-mouth rather than reading the docs. In that spirit of sharing, these are few of the Git commands I find useful when writing build scripts.

Read more →

Useful Git features: a per-clone exclude file

With Git, you can define a list of rules to tell it which files should never be checked in as part of a commit. These “ignore rules” could include files which auto-generated, compiled from source or temporary – anything you don’t need to keep around.

Until this morning, I only knew about two places where I could store these rules:

  1. Globally: use ~/.gitignore_global.

    The rules in this file apply to every Git repo on your computer. It’s useful, but not very interesting – mine is just a list of file types that I (almost) never want to check in to Git.

    This isn’t attached to a particular repo, so I use Dropbox to sync it between my computers.

  2. Per-repo: use .gitignore.

    The rules in this file can be tailed to fit one repo. You can check in this file alongside your code, so the same rules apply whenever the repo gets checked out.

Those two files cover about 95% of my use cases. But sometimes I write rules that I don’t want to be checked in or globally applied: locally-generated files that I’m unlikely to create again.

Doing a bit of Googling, I stumbled upon a solution:

  1. Per-clone: use .git/info/exclude.

    This file contains a list of ignore rules, but it doesn’t get checked in with the repo. It’s exactly what I was looking for.

Despite using Git for almost five years, I’ve never come across this file. It makes sense that it exists – it fills a natural gap left by the first two files – but I never knew it was there. It just goes to show: there’s always more to learn.