Linux, Python, vim, git & nix LPvgn Short Stack
Future-proof your skills and escape the tech hamster wheel with Linux, Python, vim & git — now with nix (LPvgn), an AI stack to resist obsolescence. Follow along as I build next generation AI/SEO tools for porting Jupyter Notebooks to FastHTML / HTMX Web apps using the Pipulate free AI SEO software.

Git Branch Takeover: A Solo Developer's Guide to Promoting a Feature Branch

I’m at a crossroads between starting a new home-hosting project and continuing the cleanup of my Pipulate codebase. I’m choosing momentum. I need to stop deferring critical skills to AI and internalize them myself, starting with Git. My immediate goal is to confidently promote my modularize feature branch to become the new main, and then systematically purge all the obsolete local and remote branches to declutter my workspace. This isn’t just cleanup; it’s about taking back the reins and building the muscle memory I need to steer this project effectively.

Setting the Stage: Context for the Curious Book Reader

This technical journal entry captures a developer regaining control over a project named Pipulate after a period of heavy reliance on AI coding assistants. The narrative is a compelling blend of high-level strategic decision-making and hands-on, command-line execution. At the heart of the entry is the developer’s choice to prioritize momentum in codebase cleanup over tackling a new “rabbit hole” project like home-hosting. This decision leads to a series of practical refactoring and Git repository management tasks, all performed with a renewed focus on “internalizing” skills rather than delegating them.

The entry serves as a live demonstration of a solo developer’s workflow, showcasing how to manage a feature branch takeover, clean up a cluttered repository, and perform project-wide code modifications. The core technical skills on display are the use of command-line tools like ripgrep (rg), sed, and xargs for refactoring, and a specific, robust git workflow for promoting a feature branch to main and then pruning obsolete branches. This is all framed within the author’s larger goal of taking back the “reins” of the codebase from AI and re-establishing a strong personal mental model of the project’s architecture.


Choosing Momentum Over Rabbit Holes

We are always standing at the precipice of rabbit hole projects that could uselessly consume the discretionary time of your weekend — or the rest of your life. Some of those journeys down into the rabbit hole are valuable learnings to move forward better in life while others are complete wastes of time. The real trick is knowing one from the other.

I have to choose between home-hosting and the general iterative improvements on the Pipulate codebase to make it leaner, meaner and more ready for public consumption. But home-hosting gets me the increasingly critical ability to watch the bots come visit my site in real-time by watching the logfiles like a fishtank as part of AI-readiness. These are both equally urgent.

Once I start the home-hosting work, momentum shifts and I risk losing it. I’m on a roll with the code cleanup so I’m going to run with that for awhile.

I’m gonna drop the whole .cursor/rules directory into cruft given that I’m quitting Cursor cold turkey. There are good rules in there, but that’s part of the whole markdown bloat thing. I’m going to try to let the codebase speak for itself to the AI code assistants.

Applying the rg | xargs sed Pattern for Code Refactoring

Okay, let’s keep cleaning up the Pipulate repo root. I shouldn’t have to look at that many files and folders. I feel piper_models is an asset that belongs in the assets folder.

[mike@nixos:~/repos/pipulate]$ rg piper_models
modules/voice_synthesis.py
61:            local_model_dir = "./piper_models"

helpers/docs_sync/archive/stale_progress_reports/ai_chip_otheseus_voice_integration_plan.md
34:mkdir -p piper_models/en/en_US/amy/low/
104:        local_model_dir = "./piper_models"

[mike@nixos:~/repos/pipulate]$

Okay, this one is a bit trickier because I have to backslash the forwardslash in order to neutralize it because the forwardslash is part of the search-and-replace API. This is the same issue as in vim so I know how to handle it. If I were to search and replace all the back to the “from here” symbol it would be a lot more backslashing to get the ./ but that’s not necessary in this case:

[mike@nixos:~/repos/pipulate]$ \rg -l --null piper_models | xargs -0 sed -i 's/piper_models/assets\/piper_models/g'

[mike@nixos:~/repos/pipulate]$ rg piper_models
modules/voice_synthesis.py
61:            local_model_dir = "./assets/piper_models"

helpers/docs_sync/archive/stale_progress_reports/ai_chip_otheseus_voice_integration_plan.md
34:mkdir -p assets/piper_models/en/en_US/amy/low/
104:        local_model_dir = "./assets/piper_models"

[mike@nixos:~/repos/pipulate]$

And then finally I actually move the folder:

[mike@nixos:~/repos/pipulate]$ mv piper_models/ assets

[mike@nixos:~/repos/pipulate]$

I do this without a git mv because that folder is not actually in the git repo. As a fetched-from-the-net resource it doesn’t have to take up room in the repo so it’s filtered out with .gitignore, which reminds me that’s an instance where I have to edit it manually.

Once this is done I test it with nix develop .#dev which constructs the piper_modules folder inside my assets folder and when I go to the Pipulate app and do the magic demo keyboard shortcut: Ctrl+Alt+D the demo runs and as I do the follow-up Ctrl+Alt+y responses, it gets to the voice synthesis part and talks! And so I’m pretty sure this worked but I’ll keep an eye on it because you never know with caching. I won’t be satisfied until after a full reboot or testing on a different system.

Taking Back the Reins: The Need to Internalize Git

Okay, so now I have a few urgent steps I want to get back into the main branch, especially this one about the new python312full no longer being in the nix repo. That broke it for everyone and it wasn’t me. Important lesson there. Use the version names that won’t break, even in the unstable repo!

Now I have to do things I’ve done with AI assistance a bunch of times but never internalized! That’s got to stop. I figure it out and make the strong mental model now, and I commit these moves to muscle memory.

When you are on a git branch and it should become the new main trunk, there are several paths.

The path we take keeps the entire history intact. There have been no new changes in the main trunk that we need to merge in. And even if there were changes there, they would have been mistakes and we do not need to merge them in. I am working as a singleton developer for the most part, using git mostly for infinite undo’s and for a distribution method to the public. If I start receiving pull requests (PR’s) that might change, but for now it’s just me and I can do this sort of stuff safely.

That being the case, my preferred method is… well, it’s also worth pointing out that the git branch that I’m on does have its own remote endpoint that I made on GitHub as a matter of safety so that I could git push from this branch and have the code in 2 places so that I can always do a git reset --hard to any hash and if I make a mistake I can always just git pull and get back to the HEAD. There may be other ways that are more effective, but after all these years I still consider myself a git novice and this is that way that’s worked for me.

Okay, so the preferred method is to actually rename the current branch that I’m on which happens to be modularize into main. And then I have to make the changes so that when I do my next git push it actually replaces the remote branch named main with this branch. modularize does in fact have the complete git history of main thus far and so this is really just a git branch naming swaparoo. Help me out Gemini. How do I do this?


The Three-Step Branch Takeover: Promoting modularize to main

Gemini: Of course. You’ve described the perfect scenario for a branch “takeover.” Since you’re the sole developer and your modularize branch is the definitive source of truth, you can safely and cleanly make it the new main.

Here is the step-by-step process to rename your current branch to main and replace the old main on GitHub.


✅ Safety First: A Quick Backup

Before you start, do one last regular push of your current branch to its remote backup on GitHub. This ensures you have a complete copy of your work stored safely under the modularize name before you begin the renaming process.

git push origin modularize

The Three-Step Takeover

This process will make your local and remote main branches identical to your current modularize branch.

Step 1: Force Rename Your Local Branch

First, rename your local modularize branch to main. We use the -M flag (a capital M) which is a force rename. This is necessary because you likely already have an old branch named main locally, and this command tells Git, “I know main exists, overwrite it.”

git branch -M modularize main

Your terminal prompt should now show that you are on the main branch, which contains all of your modularize history.

Step 2: Force Push to Remote main ⚠️

This is the most important step. You need to force push your new local main branch to the remote repository (origin). A regular push will be rejected because the history of your new main has diverged from the old main on GitHub. A force push tells the remote, “Discard your version of main and accept mine as the new, correct history.

git push --force origin main

(You can also use the shorthand -f instead of --force)

After this command completes, the main branch on GitHub will be a perfect mirror of your work.

Step 3: Clean Up the Old Remote Branch

Your work is now safely on main, so the modularize branch on GitHub is redundant. It’s good practice to delete it to avoid confusion.

git push origin --delete modularize

For Muscle Memory

To internalize this, just remember the three key actions:

  1. Rename: git branch -M <current> main
  2. Force Push: git push --force origin main
  3. Clean Up: git push origin --delete <current>

Me:

[mike@nixos:~/repos/pipulate]$ git push origin modularize
Everything up-to-date
[mike@nixos:~/repos/pipulate]$ git branch -M modularize main
[mike@nixos:~/repos/pipulate]$ git push --force origin main
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To github.com:miklevin/pipulate
   920903b..e7268d8  main -> main
[mike@nixos:~/repos/pipulate]$ git push origin --delete modularize
To github.com:miklevin/pipulate
 - [deleted]         modularize
[mike@nixos:~/repos/pipulate]$

The Great Pruning: Deleting All Other Local and Remote Branches

Excellent, I’m right with you there, Gemini! It all worked perfectly. How do I delete all my local and remote branches now except for main?

[mike@nixos:~/repos/pipulate]$ git branch
  backup-before-reset
  botify-extraction-experiment
  bughunt_20250709_090905
  clean-oz-transition
  database-fix
  database-persistence-fix
  ebb
  extractions
  fix-cherry-pick-mcp-improvements
  golden-path-cascading-v2
  golden-path-mcp-complete
* main
  main_pre_merge
  mainbeforecatchmeup
  poppyfield
  poppyfield2
  safety_golden_path_restoration
  teststuff
  working-monolithic-version
  yellowbricklion
  yellowbricklion2
  yellowbricklion3
  yellowbricklion4
  yellowbricklion5
  yellowbricklion6
  yellowbricklion7
  yellowbrickroad
  yellowbrickscarecrow
  yellowbricktinman
  yellowbrickwogglebug
  yellowbrickwogglebug2

[mike@nixos:~/repos/pipulate]$

Gemini: Of course. You can clean up all your old branches with two one-liner commands: one for your local machine and one for the remote repository on GitHub.


Delete Local Branches (Except main) 🧹

This command lists all your branches, filters out the main branch, and then passes the resulting list to the delete command.

git branch | grep -v "* main" | xargs git branch -d
  • git branch: Lists your local branches.
  • grep -v "* main": Inverts the match (-v), finding all lines that do not contain * main.
  • xargs git branch -d: Passes each branch name to the git branch -d (delete) command.

⚠️ If you have unmerged work on some branches, the command above will fail for those specific branches. To force delete them regardless of their status, use a capital -D instead:

git branch | grep -v "* main" | xargs git branch -D

Delete Remote Branches (Except main) ☁️

You can use the same logic to clean up the branches on GitHub. This command gets your local branch list (excluding main) and tells GitHub to delete each one.

git branch | grep -v "* main" | xargs git push origin --delete

It’s perfectly fine if you see errors for branches that never existed on the remote; the command will still successfully delete all the ones that do.


Okay, I followed the instructions and deleted all my local branches that aren’t main and tried doing the command to do the same remote but got an error.

Gemini: That error is happening because you’ve already successfully deleted all your local branches. The previous command relied on that local list, which is now empty, so there are no branch names to pass along to the delete command.

To clean up the remote branches, you need a command that gets the list of branches directly from the remote server.


The Correct Command for Remote Cleanup

This command will list all branches on the remote (origin), filter out main, clean up the names, and then delete them.

git branch -r | grep -v "main" | sed 's/origin\///' | xargs git push origin --delete

How It Works

  • git branch -r: Lists all remote-tracking branches (e.g., origin/some-branch).
  • grep -v "main": Filters out any lines containing “main”, which takes care of the origin/main branch itself.
  • sed 's/origin\///': This is the key change. It uses the stream editor to find the text origin/ in each line and replaces it with nothing, leaving just the clean branch name.
  • xargs git push origin --delete: Passes the clean branch names to the remote delete command.

Me:

[mike@nixos:~/repos/pipulate]$ git branch -r | grep -v "main" | sed 's/origin\///' | xargs git push origin --delete
To github.com:miklevin/pipulate
 - [deleted]         backup-before-reset
 - [deleted]         botify-extraction-experiment
 - [deleted]         catchmeup
 - [deleted]         ebb
 - [deleted]         extractions
 - [deleted]         golden-path-cascading-v2
 - [deleted]         golden-path-mcp-complete
 - [deleted]         poppyfield
 - [deleted]         poppyfield2
 - [deleted]         poppyfield3
 - [deleted]         poppyfield4
 - [deleted]         poppyfield5
 - [deleted]         pumpkinhead
 - [deleted]         rubyslippers
 - [deleted]         yellowbricklion
 - [deleted]         yellowbricklion3
 - [deleted]         yellowbricklion4
 - [deleted]         yellowbricklion5
 - [deleted]         yellowbricklion6
 - [deleted]         yellowbrickscarecrow
 - [deleted]         yellowbricktinman
 - [deleted]         yellowbrickwogglebug
 - [deleted]         yellowbrickwogglebug2

[mike@nixos:~/repos/pipulate]$

And now that’s a good cleanup and decluttering!

While it’s not quite down to my rule of 7 yet, the repo root is looking a lot more clean that it did before:

mike@nixos:~/repos/pipulate]$ ls -la
total 1148
drwxr-xr-x 22 mike users   4096 Sep 12 14:03 .
drwxr-xr-x 10 mike users   4096 Sep  9 19:46 ..
-rw-r--r--  1 mike users     11 May 13 12:07 app_name.txt
drwxr-xr-x  8 mike users   4096 Sep 12 13:55 assets
-rw-r--r--  1 mike users     66 Jul 18 11:15 botify_token.txt
drwxr-xr-x 16 mike users   4096 Sep  9 19:30 browser_automation
drwxr-xr-x 11 mike users   4096 Sep  4 20:20 client
-rw-r--r--  1 mike users  21047 Sep  9 19:22 cli.py
-rw-r--r--  1 mike users  14929 Sep  8 05:31 config.py
drwxr-xr-x  5 mike users   4096 Sep 12 14:01 cruft
drwxr-xr-x  4 mike users   4096 Sep 12 14:01 data
-rw-r--r--  1 mike users   9516 Sep  8 05:31 demo.json
-rw-r--r--  1 mike users   7196 Jul  9 11:47 discover_mcp_tools.py
drwxr-xr-x  2 mike users   4096 Jul  8 11:50 dist
drwxr-xr-x  9 mike users   4096 Jul 18 11:28 downloads
-rw-r--r--  1 mike users 215294 May 11 12:04 favicon.ico
-rw-r--r--  1 mike users   1497 Sep 12 14:17 flake.lock
-rw-r--r--  1 mike users  29141 Sep 12 13:59 flake.nix
drwxr-xr-x  7 mike users   4096 Sep 12 14:28 .git
-rw-r--r--  1 mike users     70 May 11 12:04 .gitattributes
-rw-r--r--  1 mike users   1992 Sep 12 13:59 .gitignore
-rw-r--r--  1 mike users    926 Sep 12 13:16 hello_world.ipynb
drwxr-xr-x 17 mike users   4096 Sep  9 19:29 helpers
-rw-r--r--  1 mike users   1556 Jul 12 13:58 __init__.py
-rw-r--r--  1 mike users   9517 Sep  8 05:31 install.sh
drwxr-xr-x  2 mike users   4096 Sep 12 13:17 .ipynb_checkpoints
drwxr-xr-x  4 mike users   4096 Jun 14 07:49 .jupyter
-rw-r--r--  1 mike users   1073 Jul  9 11:33 LICENSE
drwxr-xr-x  2 mike users   4096 Sep 12 14:18 logs
-rw-r--r--  1 mike users 218622 Sep  9 19:30 mcp_tools.py
drwxr-xr-x  5 mike users   4096 Sep 12 14:02 modules
drwxr-xr-x  2 mike users   4096 Jul  8 11:50 pipulate.egg-info
drwxr-xr-x  3 mike users   4096 Sep  9 19:31 plugins
drwxr-xr-x  2 mike users   4096 Sep  9 19:48 __pycache__
-rw-r--r--  1 mike users   2277 Sep  9 17:59 pyproject.toml
-rw-r--r--  1 mike users 104465 Sep 12 13:05 README.md
-rw-r--r--  1 mike users   5957 Sep  9 15:41 requirements.txt
-rw-r--r--  1 mike users 377450 Sep  9 19:25 server.py
-rw-r--r--  1 mike users     36 May 11 12:06 .sesskey
drwxr-xr-x  3 mike users   4096 Sep  9 19:30 tools
drwxr-xr-x  3 mike users   4096 Sep  4 20:20 training
drwxr-xr-x  7 mike users   4096 Jul 13 17:19 .venv

[mike@nixos:~/repos/pipulate]$

It’s also important to note that to be able to git push up to main again after this I had to do the 1-time:

git push -u origin main

Alright, this is where I have to give my brain a little rest. Get some food. Take a break and come back fresh. I can really feel that the urgency of getting a stronger and stronger mental model around all this, what files are what and what files are where is taking a priority over home hosting again, especially as I dive down into the helpers and tools directory.

The other day I moved almost everything that gets imported as a Python module by server.py into the modules folder with the exception of a few things left out on the repo root, like mcp_tools.py. But that files has some conceptual overlap with the tools directory where I tied deconstructing my MCP tools into a plugin system but failed, and that is the remains now which AI is telling me is a dependency.

I feel I want to go all-in one way or the other getting rid of tools and making it one big file in mcp_tools.py or going the other way and eliminating mcp_tools in favor of the plugin system, if it’s still actually working properly. That’s the level of loss of control that happened deferring too much to AI coding assistance over the months.

The magic rolling pin procedure instead of being yet another AI-deferred task (which I tried and failed) it will instead be a process of me regaining a tight grip on the codebase reins.

Book Analysis

Crafting Compelling Narratives: Title & Filename Brainstorm:

  • Title Option 1: Git Branch Takeover: A Solo Developer’s Guide to Promoting a Feature Branch
    • Filename: git-branch-takeover-promote-feature-branch.md
    • Rationale: This title is highly practical and keyword-rich, directly targeting a common and often confusing task for developers. It’s an excellent, discoverable title for a technical “how-to” guide.
  • Title Option 2: From Clutter to Clean: A Command-Line Workflow for Repo Hygiene
    • Filename: git-command-line-repo-hygiene-cleanup.md
    • Rationale: This title focuses on the outcome—a clean repository—and the method. It appeals to developers who feel overwhelmed by branch clutter and are looking for a systematic, command-line-based solution.
  • Title Option 3: Taking Back the Reins: Internalizing Git for Codebase Control
    • Filename: internalizing-git-codebase-control.md
    • Rationale: This is a more philosophical title that captures the author’s core motivation. It resonates with developers who feel they’ve become too reliant on GUI tools or AI assistants and want to build a deeper, more fundamental understanding of their tools.
  • Preferred Option:
    • Title (plain text for YAML): Git Branch Takeover: A Solo Developer’s Guide to Promoting a Feature Branch
    • Filename: git-branch-takeover-promote-feature-branch.md
    • Rationale: It is the most direct and useful title for a book chapter. It clearly states the problem and the solution, making it an invaluable, actionable resource for any developer, especially those working alone who need a safe and repeatable process for managing their main branch.

Book Potential Analysis:

  • Strengths as Book Fodder:
    • High-Value, Common Problem: The entry provides a clear, step-by-step solution to a frequent and intimidating problem for many developers: how to safely replace the main branch with a feature branch.
    • Authentic Learning Process: It captures the author’s explicit goal of moving from “AI-assisted” to “internalized” knowledge, which is a highly relatable narrative for developers in the current AI-heavy landscape.
    • Complete, End-to-End Workflow: It doesn’t just show one command; it presents a full workflow from a small code refactor, to a major branch promotion, to the final cleanup of dozens of stale branches, including debugging the process.
    • Safe and Repeatable Commands: The provided one-liner commands for bulk branch deletion are extremely practical, powerful, and immediately useful for any developer looking to clean up their repositories.
  • Opportunities for Enrichment (for Book Adaptation):
    • Diagram the Branch Takeover: Create a simple “before and after” Git graph diagram. The “before” would show origin/main and origin/modularize as divergent branches. The “after” would show the old main gone and the new main pointing to the modularize commit history.
    • Add a “Why Not Rebase or Merge?” Sidebar: Briefly explain the common alternatives (git merge and git rebase) and articulate precisely why the author’s “rename and force push” method was the correct choice for this specific solo-developer context, clarifying the trade-offs.
    • Create a “Git Hygiene” Checklist: Distill the cleanup actions into a reusable checklist for developers. This would include steps like “Regularly prune merged local branches,” “Delete remote branches after merging PRs,” and “Periodically review and delete stale experimental branches.”

AI Editorial Perspective: From Journal to Chapter:

This entry is a perfect case study for a chapter on “Practical Version Control for the Solo Developer.” It demystifies a set of Git operations that are often presented with confusing complexity or dire warnings, and reframes them as a safe, powerful workflow when applied in the right context. The narrative strength lies in the author’s explicit desire to build “muscle memory.” This transforms a dry technical guide into a story about skill acquisition and empowerment.

The human-AI dialogue is particularly effective here. The AI acts as a Socratic mentor, providing the precise commands needed, while the human provides the crucial context, intent, and then works through the entire process, including the predictable follow-up problems (like how to delete remote branches after local ones are gone). This interaction is a realistic model of how developers can use AI as a tool to accelerate learning and build confidence. The entry’s raw, step-by-step log of commands and their outputs is its greatest asset, serving as an authentic, “over-the-shoulder” lesson that is far more impactful than a sanitized tutorial.


Suggested Next AI Processing Steps:

  1. Task Suggestion 1: Generate a Visual Metaphor for the Git Process.
    • Potential Prompt Snippet for Next AI: “Read the description of the ‘branch takeover’ in the text. Create a simple, non-technical analogy to explain the process. For example, ‘It’s like replacing the master blueprint for a house (the main branch) with a completely revised blueprint from a side project (the feature branch), then shredding all other old drafts.’”
  2. Task Suggestion 2: Create a “Safety and Context” Advisory Box.
    • Potential Prompt Snippet for Next AI: “Based on the git commands for force-pushing and deleting branches, write a concise ‘Warning’ or ‘Use With Caution’ advisory box. Explain in what specific situations (e.g., collaborative projects with shared branches) this workflow would be dangerous and should be avoided, contrasting it with the solo-developer context where it is safe.”
Post #387 of 388 - September 12, 2025