{
  "data": [
    {
      "api_url": "https://londo.me/blog/api/v1/posts/github-actions-beyond-ci.json",
      "cover": {
        "alt": "A terminal printing a scheduled GitHub Actions workflow, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/github-actions-beyond-ci/cover.png",
        "width": 1200
      },
      "description": "GitHub Actions is a free, event-driven computer attached to every repo. Running tests is just the start.",
      "published": "2026-10-22T09:00:00-07:00",
      "reading_time_minutes": 4,
      "slug": "github-actions-beyond-ci",
      "summary": "Most people meet GitHub Actions as “the thing that runs tests on pull requests.” But under the hood it’s much more general: a computer that wakes up when something happens, runs whatever you tell it, and goes back to sleep. For public repos, it’s free.\nHere are things you can do with it that have nothing to do with CI.\nHow it works in 30 seconds A workflow is a YAML file in .github/workflows/. It has:",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/github.json",
          "name": "github",
          "slug": "github",
          "url": "https://londo.me/blog/tags/github/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/github-actions.json",
          "name": "github-actions",
          "slug": "github-actions",
          "url": "https://londo.me/blog/tags/github-actions/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/automation.json",
          "name": "automation",
          "slug": "automation",
          "url": "https://londo.me/blog/tags/automation/"
        }
      ],
      "title": "Things GitHub Actions Can Do That Aren't CI",
      "updated": "2026-10-22T09:00:00-07:00",
      "url": "https://londo.me/blog/posts/github-actions-beyond-ci/",
      "word_count": 757
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/git-internals.json",
      "cover": {
        "alt": "A terminal hashing a file with git hash-object, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/git-internals/cover.png",
        "width": 1200
      },
      "description": "Git isn't magic. It's a small, clever key-value store with a few text files on top. Here's how to explore it by hand.",
      "published": "2026-10-15T09:00:00-07:00",
      "reading_time_minutes": 5,
      "slug": "git-internals",
      "summary": "Every Git repo has a hidden .git folder. Most people never open it. That’s where all of Git lives: every version of every file, every branch, every commit message. And it’s surprisingly simple once you look.\nLet’s take it apart.\nSetup Make a throwaway repo so we can poke at it safely:\nmkdir git-internals && cd git-internals git init -b main echo \"hello\" > hello.txt git add hello.txt git commit -m \"first commit\" Now look inside:",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/git.json",
          "name": "git",
          "slug": "git",
          "url": "https://londo.me/blog/tags/git/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/internals.json",
          "name": "internals",
          "slug": "internals",
          "url": "https://londo.me/blog/tags/internals/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/deep-dive.json",
          "name": "deep-dive",
          "slug": "deep-dive",
          "url": "https://londo.me/blog/tags/deep-dive/"
        }
      ],
      "title": "Your .git Folder Is a Database. Let's Read It.",
      "updated": "2026-10-15T09:00:00-07:00",
      "url": "https://londo.me/blog/posts/git-internals/",
      "word_count": 1022
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/git-bisect-run.json",
      "cover": {
        "alt": "A terminal running git bisect run to find the first bad commit, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/git-bisect-run/cover.png",
        "width": 1200
      },
      "description": "Something broke, and you don't know which of the last 400 commits did it. Git can binary-search your history and find the exact commit, automatically.",
      "published": "2026-10-08T09:00:00-07:00",
      "reading_time_minutes": 4,
      "slug": "git-bisect-run",
      "summary": "It worked last month. It doesn’t work now. There are 400 commits in between.\nYou could read them all. Or you could let Git find the guilty one in about nine steps.\nThe idea: binary search through history git bisect takes two points: a commit where things were good and one where they’re bad. It checks out the commit halfway between and asks you which it is. Then it throws away the half that can’t contain the bug and repeats.",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/git.json",
          "name": "git",
          "slug": "git",
          "url": "https://londo.me/blog/tags/git/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/debugging.json",
          "name": "debugging",
          "slug": "debugging",
          "url": "https://londo.me/blog/tags/debugging/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/tooling.json",
          "name": "tooling",
          "slug": "tooling",
          "url": "https://londo.me/blog/tags/tooling/"
        }
      ],
      "title": "git bisect run: Let Git Find the Bug for You",
      "updated": "2026-10-08T09:00:00-07:00",
      "url": "https://londo.me/blog/posts/git-bisect-run/",
      "word_count": 684
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/git-worktree.json",
      "cover": {
        "alt": "A terminal running git worktree commands, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/git-worktree/cover.png",
        "width": 1200
      },
      "description": "Check out multiple branches at the same time, in separate folders, from one repo. No stash, no second clone, no lost work.",
      "published": "2026-10-01T09:00:00-07:00",
      "reading_time_minutes": 4,
      "slug": "git-worktree",
      "summary": "You’re halfway through a feature. Files are open, tests are half-written, nothing compiles. Then someone says: “Production is broken, can you look?”\nMost people do one of these:\ngit stash, switch branches, fix, switch back, git stash pop, pray. Commit a “WIP” mess they’ll have to clean up later. Clone the whole repo again into another folder. There’s a better option that has been in Git since 2015: worktrees.\nWhat a worktree is A normal repo has one working directory: the folder where your files live. A worktree is an extra working directory attached to the same repo. Each one can have a different branch checked out, and they all share the same history, objects, and remotes.",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/git.json",
          "name": "git",
          "slug": "git",
          "url": "https://londo.me/blog/tags/git/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/workflow.json",
          "name": "workflow",
          "slug": "workflow",
          "url": "https://londo.me/blog/tags/workflow/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/tooling.json",
          "name": "tooling",
          "slug": "tooling",
          "url": "https://londo.me/blog/tags/tooling/"
        }
      ],
      "title": "git worktree: Stop Stashing, Start Branching in Parallel",
      "updated": "2026-10-01T09:00:00-07:00",
      "url": "https://londo.me/blog/posts/git-worktree/",
      "word_count": 668
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/diresq.json",
      "cover": {
        "alt": "A terminal running the DiresQ sweep: two responders checked in and one overdue, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/diresq/cover.png",
        "width": 1200
      },
      "description": "During Hurricane Harvey, volunteers in fishing boats saved thousands of people, and nobody kept track of the volunteers. We built the first version of DiresQ in one 14-hour night at our first hackathon ever, kept building it for four more hackathons, and it placed 3rd in the Software Development track at Reverie Hacks 2026. Here's how it works, and the three times our own code lied to us.",
      "published": "2026-09-26T09:00:00-07:00",
      "reading_time_minutes": 19,
      "slug": "diresq",
      "summary": "During Hurricane Harvey in 2017, ordinary people took their own fishing boats into the floodwater and pulled thousands of their neighbors off roofs. Some of them didn’t come back.\nHere’s the detail that stuck with me: when a volunteer like that heads out, nobody writes down that they went. There’s no dispatcher, no roster, no log. If they stop answering their phone, nothing notices. Eventually, someone realizes they haven’t heard from them in a while.",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/hackathon.json",
          "name": "hackathon",
          "slug": "hackathon",
          "url": "https://londo.me/blog/tags/hackathon/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/diresq.json",
          "name": "diresq",
          "slug": "diresq",
          "url": "https://londo.me/blog/tags/diresq/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/python.json",
          "name": "python",
          "slug": "python",
          "url": "https://londo.me/blog/tags/python/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/flask.json",
          "name": "flask",
          "slug": "flask",
          "url": "https://londo.me/blog/tags/flask/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/disaster-response.json",
          "name": "disaster-response",
          "slug": "disaster-response",
          "url": "https://londo.me/blog/tags/disaster-response/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/machine-learning.json",
          "name": "machine-learning",
          "slug": "machine-learning",
          "url": "https://londo.me/blog/tags/machine-learning/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/security.json",
          "name": "security",
          "slug": "security",
          "url": "https://londo.me/blog/tags/security/"
        }
      ],
      "title": "The App That Reports You Missing",
      "updated": "2026-09-26T09:00:00-07:00",
      "url": "https://londo.me/blog/posts/diresq/",
      "word_count": 3902
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/pescatarian.json",
      "cover": {
        "alt": "A terminal listing animals that religious rulings counted as fish, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/pescatarian/cover.png",
        "width": 1200
      },
      "description": "For two thousand years, religions have argued about where meat ends and fish begins, with rulings on beavers, alligators, and geese that grow on driftwood. I've lived on that line for eight years. Here's the history, the Daoist philosophy behind how I think about it, and how I actually eat.",
      "published": "2026-09-24T23:06:00-07:00",
      "reading_time_minutes": 16,
      "slug": "pescatarian",
      "summary": "In 2010, a Catholic in Louisiana asked his archbishop a very specific question. During Lent, Catholics skip meat on Fridays. So: was it okay to eat alligator?\nThe archbishop’s answer: yes. As far as the Church was concerned, alligator counted as seafood.\nHe wasn’t the first religious authority to get a question like that. Over the centuries, priests, bishops, and theologians have been asked to rule on beavers, muskrats, capybaras, and a goose that medieval Europeans believed grew on driftwood.",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/food.json",
          "name": "food",
          "slug": "food",
          "url": "https://londo.me/blog/tags/food/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/pescatarian.json",
          "name": "pescatarian",
          "slug": "pescatarian",
          "url": "https://londo.me/blog/tags/pescatarian/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/history.json",
          "name": "history",
          "slug": "history",
          "url": "https://londo.me/blog/tags/history/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/religion.json",
          "name": "religion",
          "slug": "religion",
          "url": "https://londo.me/blog/tags/religion/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/philosophy.json",
          "name": "philosophy",
          "slug": "philosophy",
          "url": "https://londo.me/blog/tags/philosophy/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/daoism.json",
          "name": "daoism",
          "slug": "daoism",
          "url": "https://londo.me/blog/tags/daoism/"
        }
      ],
      "title": "When Alligator Counts as Fish & Why I'm a Pescatarian",
      "updated": "2026-09-25T00:01:51-07:00",
      "url": "https://londo.me/blog/posts/pescatarian/",
      "word_count": 3380
    },
    {
      "api_url": "https://londo.me/blog/api/v1/posts/gitattributes.json",
      "cover": {
        "alt": "A terminal printing a .gitattributes file, above the post title",
        "height": 630,
        "url": "https://londo.me/blog/posts/gitattributes/cover.png",
        "width": 1200
      },
      "description": "Every repo has a .gitignore. Almost nobody has a .gitattributes. Here's everything it can do: line endings, smarter diffs, merge strategies, filters, release archives, and GitHub extras.",
      "published": "2026-09-24T01:50:00-07:00",
      "reading_time_minutes": 7,
      "slug": "gitattributes",
      "summary": "Every repo has a .gitignore. Almost nobody has a .gitattributes. That’s a shame, because this one small file controls how Git sees, diffs, merges, normalizes, and exports your files. Once you know what it can do, you’ll want one in every project.\nWhat it is .gitattributes is a plain text file that assigns attributes to paths. Each line is a pattern followed by one or more attributes:\n*.sh text eol=lf *.png binary docs/** linguist-documentation The patterns work much like .gitignore, with two catches. Negation (!pattern) isn’t allowed. And a directory pattern like vendor/ does not apply to the files inside it, so you need vendor/**.",
      "tags": [
        {
          "api_url": "https://londo.me/blog/api/v1/tags/git.json",
          "name": "git",
          "slug": "git",
          "url": "https://londo.me/blog/tags/git/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/github.json",
          "name": "github",
          "slug": "github",
          "url": "https://londo.me/blog/tags/github/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/gitattributes.json",
          "name": "gitattributes",
          "slug": "gitattributes",
          "url": "https://londo.me/blog/tags/gitattributes/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/tooling.json",
          "name": "tooling",
          "slug": "tooling",
          "url": "https://londo.me/blog/tags/tooling/"
        },
        {
          "api_url": "https://londo.me/blog/api/v1/tags/devops.json",
          "name": "devops",
          "slug": "devops",
          "url": "https://londo.me/blog/tags/devops/"
        }
      ],
      "title": "The Best Git Feature You've Never Used",
      "updated": "2026-09-24T01:52:31-07:00",
      "url": "https://londo.me/blog/posts/gitattributes/",
      "word_count": 1439
    }
  ],
  "meta": {
    "api": "londopy-blog",
    "docs": "https://londo.me/blog/api/",
    "generated": "2026-10-27T05:20:06Z",
    "self": "https://londo.me/blog/api/v1/posts.json",
    "version": "1.0.0"
  }
}