Today I learned

Short notes on things I pick up along the way. Many started as posts on X.

Clean up merged branches with git branch --delete-merged

Also on X

Git 2.56 adds git branch --delete-merged, so you can stop using this:

git branch --merged | grep -v "^\*\|main\|master" | xargs git branch -d

It deletes local branches whose work has already landed on the upstream they track:

git branch --dry-run --delete-merged origin  # preview
git branch --delete-merged origin

It’s also safer than the one-liner: it skips branches checked out in any worktree and any branch with branch.<name>.deleteMerged set to false. Docs

CSS content accepts alternative text

Also on X

The CSS content property accepts alternative text after a slash, so generated content in ::before and ::after no longer has to hurt screen reader users.

.new-item::before {
  /* "black star" and element content is read out */
  content: "★";

  /* "Highlighted item" and element content is read out */
  content: "★" / "Highlighted item";

  /* Generated content is ignored and only element content is read out */
  content: "★" / "";
}

Supported in every major engine since Firefox 128. Via Stefan Judis.

Copy changes without the commit: git cherry-pick --no-commit

Also on X

--no-commit applies a commit’s changes to your working tree and index without creating a commit. Super handy when I want the changes from another branch but not the commit itself.

git cherry-pick <commit-hash> --no-commit

The short form is -n, and it works with ranges too: git cherry-pick -n A..B stages the combined changes so you can commit them as one.

Chain errors with the cause option

Also on X

When throwing a new error, pass the original one as cause. Debugging gets easier because the original error and its stack trace are kept.

try {
  connectToDatabase();
} catch (err) {
  throw new Error("Connecting to database failed.", { cause: err });
}

This way, the logs show both what failed and why. MDN: Error.cause

JSON Feed: RSS, but JSON

Also on X

JSON Feed is a feed format like RSS and Atom, written in JSON instead of XML. I stumbled upon it while playing with a project that required converting RSS to JSON.

{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "My Example Feed",
  "home_page_url": "https://example.org/",
  "feed_url": "https://example.org/feed.json",
  "items": [
    {
      "id": "2",
      "content_text": "This is a second item.",
      "url": "https://example.org/second-item"
    }
  ]
}

Why are we still using XML for feeds when JSON seems to be a more direct, streamlined option?

Validate URLs with the URL constructor

Also on X

A nice way to validate a URL without a regex: let new URL() try to parse it.

/**
 * Check if supplied href is a valid URL or not.
 * Note "example.com/contact" is not a valid URL.
 * The protocol has to be supplied as well:
 * => "https://example.com/contact"
 * => "mailto:iron.man@gmail.com"
 * => "tel:+188899956754"
 */
function isUrl(href: string) {
  try {
    new URL(href);
    return true;
  } catch (e) {
    return false;
  }
}

Via André Landgraf’s remix-isomorphic-link.

Update: browsers now ship this built in. URL.canParse(href) returns a boolean, no try/catch needed.

Check out several branches at once with git worktree

Also on X

git worktree checks out another branch into a separate folder, backed by the same repository. No more stashing half-done work just to review a PR or fix something on main.

git worktree add ../hotfix main
cd ../hotfix
# fix, commit, push
git worktree remove ../hotfix

I’m in good company: even Guido van Rossum asked why he hadn’t known about it sooner. Docs · Video

The ping attribute sends a POST when a link is clicked

Also on X

The ping attribute on <a> makes the browser send an asynchronous POST request to a URL when the link is clicked. You might need this for tracking clicks without redirecting through your own server first. Google uses it in search results, with a workaround for Firefox, which disables ping by default.

<!-- Sends an asynchronous POST request to /track -->
<a href="https://www.reddit.com/" ping="/track">reddit</a>

<!-- Ping several URLs, separated by spaces -->
<a href="https://www.reddit.com/" ping="/track https://tracking.example/">reddit</a>

The request body is just PING with Content-Type: text/ping, and the Ping-From and Ping-To headers tell the server which page the click came from and where it went.

For tracking things other than link clicks, the Beacon API (navigator.sendBeacon()) sends a request that survives the page unloading. It was still experimental when I tweeted this; it now works in every major browser.

More: Spec: hyperlink auditing · Video