When working on many feature branches, they tend to accumulate in the local Git clone. Even if they get deleted in upstream shared repos, they need to be cleared locally, too, otherwise they will stick around forever.

Here’s a quick one-liner to clean up every branch that is fully merged to main. It does make sure not to delete main and develop, though.

git branch -d $(git branch --merged main | grep -vE '(^\*|master|main|develop)')
Continue reading

Backups. What a better time to test ’em than when you need ’em. Don’t lie. I know you’ve been there too. In an unfortunate turn of events, I had to restore a number of bare git repos from recent off-site copies (made with the handy rdiff-backup), but they needed a bit more work to be functional.

Once restored, I couldn’t pull or push from my existing working copies. I was greeted with cryptic error messages instead: fatal: git upload-pack: not our ref 0000000000000000000000000000000000000000 and ! [remote rejected] master -> master (missing necessary objects), respectively.

No amount of searching led to an adequate solution. So I simply leveraged git’s distributedness, and used one of the clone to recreate my bare repo. I was nonetheless a bit worried about having lost a few commits on the tip.

Playing in the bare repo later on led me to a more satisfying solution. Apparently, the refs/heads/master file was corrupted (empty), and editing it to contain the full sha-1 of the tip was enough to fix the issue. I found the sha-1 of the desired commit in the packed-refs file at the root of the bare repo. Once done, everything worked as before, and pre-existing working copies were able to pull and push without issue.

I learned two things:

  • A bit more about git
  • That I didn’t actually have any more commits there

Backups! Yay!

Continue reading
A Git workflow showing feature branches merged into master and tagged as releases

I wrote this article for the Learnosity blog, where it originally appeared. I repost it here, with permission, for archival.

A few weeks ago, a debate started on our channel for Git-related discussions. Following someone posting a link to Nicola Paolucci’s article on Core [Git] Concept, Workflows And Tips, a question was raised:

Do we really need merge commits?

What sounded like a fairly straightforward question quickly snowballed into one of those long chat threads that left us none the wiser. A follow-up face-to-face discussion helped us get down to the root of the problem: code and functional reviews on feature branches may leave us exposed to integration issues after non-fast-forward merges, and can only be caught too late for comfort.

We had to consider our Git workflow alongside the lifecycle of our tickets to come up with an improvement. Merge commits remain, but we rebase (and fix conflicts) on the latest main branch before any review in order to make sure we look at the final code.

The rest of this article describes our Git workflow, our ticket lifecycle, their interactions, and how we made them better.


  1. Rebase onto develop before code review (original developer)
  2. Rebase onto develop before functional review (functional reviewer)
  3. Deploy to staging as soon as possible (i.e., all codebases merged for the feature; original developer)

Continue reading

git has many useful features in git log(1) and git blame(1) to display the history of a file, or who contributed each line in said file, respectively. However, it might be useful to get the full history not of a file or a line but, say, a function (that is, more than one line in a coherent structure). This can be interesting for things such as displaying all the authors of a given function.

Continue reading

Posted in tip.