Posts tagged: git

All posts with the tag "git"

9 posts latest post 2025-10-28
Publishing rhythm
Oct 2025 | 1 posts

You can reference a git repo in compose’s “build” argument for a service as of this PR

You suck at git - but it’s honestly fine

You suck at git - but it’s honestly fine

Git is for everyone # I just started listening to localfirst.fm podcast podcast and would recommend it after 2 episodes. In the first episode, the hosts discuss where the term comes from, what it means, and examples of some localfirst, or semi-localfirst projects. One of them is the de-facto standard by which developers share code today. There’s a reason it’s the standard. I’m not arguing that it’s perfect, and there’s new abstractions that may help people adopt usage like jujutsu, but ultimately is a great tool, and anyone can use it who works with text files (lookin at you book-writing nerds) But as I was enjoying the pod the co-host/guest said “and we all know the git user experience isn’t that great” heavy sigh Git isn’t that hard - you probably just aren’t that good at it It’s OK # Don’t hear me say that you suck at git like that’s a bad thing… It’s totally fine to not be a wizard. Many people can use git like 80-90% efficiently for their own use cases. In fact, my usage of git do…

I started deploying a website to Cloudflare on a branch called pages. Similar to one of the GH Pages deployment patterns. But when my CI was pushing the branch I couldn’t see it locally…

git fetch -a wasn’t pulling any new branches, and git branch -a was only showing my development and main branches at the remote… so what gives?

I checked my git config, and to this moment I have no idea how this happened but check out my fetch config:

git config --get remote.origin.fetch
+refs/tags/*:refs/tags/*

So to fix this:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

Now git fetch -a works again

> git fetch -a

From github.com:DigitalHarbor7/DigitalHarbor
   357a28a..969b027  develop    -> origin/develop
   c052ac9..6d40210  main       -> origin/main
 * [new branch]      pages      -> origin/pages

git config –add –local core.sshCommand ‘ssh -i «<PATH_TO_SSH_KEY»>’

In vim G clog % does a git clog {current file}. You get every commit that the target file is apart of (so there might be info in those commits unrelated)

I try to commit a lot, and I also try to write useful tests appropriate for the scope of work I’m focusing on, but sometimes I drop the ball…

Whether by laziness, ignorance, or accepted tech debt I don’t always code perfectly and recently I was dozens of commits into a new feature before realizing I broke something along the way that none of my tests caught…

Before today I would’ve manually reviewed every commit to see if something obvious slipped by me (talk about a time suck 😩)

There must be a better way

Bisect?

git bisect is the magic sauce for this exact problem…

You essentially create a range of commits to consider and let git bisect guide you through them in a manner akin to Newton’s method for finding the root of a continuous function.

How to do it?

Start with git bisect start and then choose the first good commit (ie. a commit you know the bug isn’t present in)


sandbox   bisect-post   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect start

sandbox   bisect-post (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect good 655332b
bisect-post  HEAD         main         ORIG_HEAD
5b31e1e  -- [HEAD]    add successful print (52 seconds ago)
308247b  -- [HEAD^]   init another loop (77 seconds ago)
4555c59  -- [HEAD^^]  introduce bug (2 minutes ago)
9cf6d55  -- [HEAD~3]  add successful loop (3 minutes ago)
bcb41c3  -- [HEAD~4]  change x to 10 (4 minutes ago)
3c34aac  -- [HEAD~5]  init x to 1 (4 minutes ago)
12e53bd  -- [HEAD~6]  print cwd (4 minutes ago)
655332b  -- [HEAD~7]  add example.py (10 minutes ago)  # <- I want to start at this commit
59e0048  -- [HEAD~8]  gitignore (23 hours ago)
fb9e1fb  -- [HEAD~9]  add reqs (23 hours ago)


sandbox   bisect-post (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect bad 5b31e1e
bisect-post                                                ORIG_HEAD
HEAD                                                       refs/bisect/good-655332b6c384934c2c00c3d4aba3011ccc1e5b57
main
5b31e1e  -- [HEAD]    add successful print (5 minutes ago)  # <- I start here with the "bad" commit
308247b  -- [HEAD^]   init another loop (6 minutes ago)
4555c59  -- [HEAD^^]  introduce bug (6 minutes ago)
9cf6d55  -- [HEAD~3]  add successful loop (7 minutes ago)
bcb41c3  -- [HEAD~4]  change x to 10 (8 minutes ago)
3c34aac  -- [HEAD~5]  init x to 1 (9 minutes ago)
12e53bd  -- [HEAD~6]  print cwd (9 minutes ago)
655332b  -- [HEAD~7]  add example.py (14 minutes ago)
59e0048  -- [HEAD~8]  gitignore (23 hours ago)
fb9e1fb  -- [HEAD~9]  add reqs (23 hours ago)

After starting bisect with a “good” start commit and a “bad” ending commit we can let git to it’s thing!

Git checksout a commit somewhere about halfway between the good and bad commit so you can see if your bug is there or not.


sandbox   bisect-post (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect bad 5b31e1e
Bisecting: 3 revisions left to test after this (roughly 2 steps)
[bcb41c3854e343eade85353683f2c1c4ddde4e04] change x to 10

sandbox   HEAD (bcb41c38) (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯

In my example here I have a python script with some loops and print statements - they aren’t really relevant, I just wanted an easy to follow git history.

So I check to see if the bug is present or not either by running/writing tests or replicating the bug somehow.

In this session commit bcb41c38 is actually just fine, so I do git bisect good


sandbox   HEAD (bcb41c38) (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect good
Bisecting: 1 revision left to test after this (roughly 1 step)
[4555c5979268dff6c475365fdc5ce1d4a12bd820] introduce bug

And we see that git moves on to checkout another commit…

In this case the next commit is the one where I introduced a bug

git bisect bad then gives me:


sandbox   HEAD (4555c597) (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[9cf6d55301560c51e2f55404d0d80b1f1e22a33d] add successful loop

At 4555c597 the script works as expected so one more git bisect good yields…

sandbox   HEAD (9cf6d553) (BISECTING)   ×1 via   v3.8.11(sandbox)  on  (us-east-1)
❯ git bisect good
4555c5979268dff6c475365fdc5ce1d4a12bd820 is the first bad commit
commit 4555c5979268dff6c475365fdc5ce1d4a12bd820
Author: ########################### 
Date:   Tue May 3 09:00:00 2022 -0500

    introduce bug

 example.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


What happened?

Git sliced up a range of commits based on me saying of the next one was good or bad and localized the commit that introduced a bug into my workflow!

I didn’t have to manually review commits, click through logs, etc… I just let git checkout relevant commits and I ran whatever was appropriate for reproducing the bug to learn when it was comitted!

If you work with a template for several projects then you might sometimes need to do the same action across all repos. A good example of this is updating a package in requirements.txt in every project, or refactoring a common module. If you have several repos to do this across then it can be time consuming… enter mu-repo

Mu #

mu-repo is an awesome cli tool for working with multiple git repositories at the same time. There are several things you can do:

  1. mu status will give you the git status of every registered repo (see below)
  2. mu sh will let you execute system level commands in every repo
  3. mu stash will stash all changes across all registered repos
  4. There’s literally a ton more but these are some handy ones

Registration #

mu tracks its own groups, and there is a default group when no particular one is active. It’s as simple as mu register proj1 prog2 ... to get repos registered


❯ mu register proj1 proj2
Repository: proj1 registered
Repository: proj2 registered

❯ mu status

  proj1 : git status
    On branch main

    No commits yet

    Untracked files:
    (use "git add <file>..." to include in what will be committed)
    requirements.txt

    nothing added to commit but untracked files present (use "git add" to track)

  proj2 : git status
    On branch main

    No commits yet

    Changes to be committed:
    (use "git rm --cached <file>..." to unstage)
    new file:   requirements.txt


Working with mu #

As you can see above I have two projects each with a requirements.txt added but not committed yet. Using mu I can stage this change across both repos at once.


❯ mu add requirements.txt

  proj1 : git add requirements.txt

  proj2 : git add requirements.txt

Then as you might imagine, I can make the commit in each repo


❯ mu commit -m "Add requirements.txts"

  proj1 : git commit -m Add requirements.txts
    [main (root-commit) 18376d7] Add requirements.txts
    1 file changed, 1 insertion(+)
    create mode 100644 requirements.txt

  proj2 : git commit -m Add requirements.txts
    [main (root-commit) 18376d7] Add requirements.txts
    1 file changed, 1 insertion(+)
    create mode 100644 requirements.txt

mu groups #

The other thing I got a lot of use out of recently was mu’s groups. At work I have about 40 repos cloned that are all based on the same kedro pipeline template. Some of these projects have been deprecated. I also have several more repos that are not kedro template - custom libraries or something. group let me utilize mu across different groups of repos.

Say proj2 is a deprecated project that I don’t need to worry about making changes to anymore. I don’t just have to unregister it, instead I can make a group called “active” and register proj1 in that group


❯ mu group add active --empty

~/personal
❯ mu group add deprecated --empty

~/personal
❯ mu group
  active
* deprecated

The * tells me which group is active. The --empty flag tells mu to not add all registered repos to that group. If I don’t want to use any groups then mu group reset will go back to the default group with all registered repos.

With groups I can register only the repos that I want to be working across in their own group and not worry about affecting other repos with my batch changes!

Git-Worktrees-01

Git # Hopefully if you write code you are using git, if not go learn the basics of,,, and / like… right now. Assuming you are at least familiar with git then you probably work the same way I have since I’ve been using it. clone or initialize a repo checkout a branch, work on and when ready open a PR into then etc… What if you need to switch between branches for some reason? Often I’m jumping into projects with my co-workers left and right, and I’ll have changes that I’m either working on or exploring for them. When it’s time to switch branches I think there’s more elegant ways than this but I’ve always done this: the current changes checkout out the relevant branch helped out re-checkout my original branch the Now, that’s not awful but I think will make this nicer for a few reasons! Worktrees # Worktrees are linked branches that have their own directories somewhere on your computer. To checkout a branch you don’t have to worry about stashing any changes, you just into the directory of…

After carefully staging only lines related to a specific change and comitting I suddenly realized I missed one… darn, what do I do?

Old me would have soft reset my branch to the previous commit and redone all my careful staging… what a PIA…

New me (credit: ThePrimeagen)…

# stage other changes I missed
git commit --amend --no-edit