<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://devin.uk/</id>
  <title type="text">Devin Cheung</title>
  <subtitle type="text">Firefly 是一款基于 Astro 框架和 Fuwari 模板开发的清新美观且现代化个人博客主题模板，专为技术爱好者和内容创作者设计。该主题融合了现代 Web 技术栈，提供了丰富的功能模块和高度可定制的界面，让您能够轻松打造出专业且美观的个人博客网站。</subtitle>
  <updated>2026-09-22T00:00:00.000Z</updated>
  <author><name>Devin Cheung</name></author>
  <link rel="alternate" href="https://devin.uk/"/>
  <link rel="self" href="https://devin.uk/atom.xml"/>
  <generator uri="https://github.com/CuteLeaf/Firefly">Firefly v6.16.8</generator>
    <entry>
      <id>https://devin.uk/posts/free-website/</id>
      <title type="text">What a Free Website Actually Costs</title>
      <published>2026-09-22T00:00:00.000Z</published>
      <updated>2026-09-22T00:00:00.000Z</updated>
      <author><name>Devin Cheung</name></author>
      <link rel="alternate" href="https://devin.uk/posts/free-website/"/>
      <summary type="text">Free website builders can be perfectly useful, but the price is usually paid in time, limitations, or maintenance rather than money.</summary>
      <content type="html"><![CDATA[<p>I understand the appeal of building a website for free.</p>
<p>I write code for a living and still find it satisfying to start with an empty page, move a few things around, and end up with something that works. Website builders make that possible without first learning HTML, CSS, hosting, or why a perfectly ordinary image has somehow moved the rest of the page six pixels to the left.</p>
<p>For a small personal site or an idea that may not survive the weekend, a free website can be exactly the right choice.</p>
<p>The awkward part is that a free website still costs something, just not always money.</p>
<section><h2>The Cost Usually Moves Somewhere Else<a href="#the-cost-usually-moves-somewhere-else"><span>#</span></a></h2><p>A website builder replaces money with a mixture of time and constraints.</p><p>There is time spent choosing a theme, resizing images, working around the editor, connecting a domain, and discovering which useful feature belongs to the next pricing tier. None of these jobs is especially difficult on its own. Together, they have a habit of filling an afternoon.</p><p>That may be a perfectly good use of an afternoon. I have spent longer on less useful things. But it is still worth noticing, particularly when the site belongs to a business and the person building it has other work to do.</p><p>The relevant question is not simply, “Can I make this myself?” It is whether making it yourself is how you want to spend the time.</p></section>
<section><h2>The Limits Usually Appear Later<a href="#the-limits-usually-appear-later"><span>#</span></a></h2><p>No-code tools are convenient because they make a large number of decisions on your behalf. Hosting, templates, content editing, forms, and deployment all arrive in one box.</p><p>That box has edges.</p><p>You may eventually want a layout the editor does not quite support, a faster page, cleaner markup, a particular integration, or a way to move the content somewhere else. The feature might be possible with a plugin or an upgrade. It might also be impossible without rebuilding the site.</p><p>This is not a flaw unique to website builders. Every technical choice creates constraints. A custom site has plenty of its own, including the rather important question of who maintains it. The difference is that the constraints of a free platform tend to appear later, after the convenient beginning.</p></section>
<section><h2>Maintenance Does Not Disappear<a href="#maintenance-does-not-disappear"><span>#</span></a></h2><p>It is easy to think of a website as something that gets finished. Most of them are closer to small, quiet pieces of software.</p><p>Links break. Business details change. Dependencies need updates. Contact forms attract spam. Domains expire with impressive punctuality. If the site uses a content management system and several plugins, those parts also need attention.</p><p>A hosted builder handles some of this work, which is one of its genuine advantages. A self-hosted system gives you more control but leaves more of the upkeep with you. A custom static site can have fewer moving parts, although someone still needs to understand how it is built and deployed.</p><p>There is no maintenance-free option. There are only different places for the maintenance to live.</p></section>
<section><h2>Sometimes Free Is Still the Sensible Answer<a href="#sometimes-free-is-still-the-sensible-answer"><span>#</span></a></h2><p>None of this means every website needs a developer.</p><p>If you are testing an idea, making a simple event page, or putting together a small personal site, starting with a free tool is sensible. You can learn what the site actually needs before spending much money on it. In many cases, the platform’s limits will never matter.</p><p>The trade-offs start to matter more when the website becomes part of how a business operates. If it needs to be fast, accessible, easy to find, connected to other systems, or dependable enough that nobody wants to think about it on a Monday morning, the cheapest starting price becomes less useful as a measure.</p><p>At that point, paying for a suitable platform or for someone to build and maintain the site is not automatically better. Sometimes you are simply paying to save time, get more flexibility, or make the problem someone else’s responsibility.</p></section>
<section><h2>A More Useful Question<a href="#a-more-useful-question"><span>#</span></a></h2><p>I no longer think “Should a website be free?” is a particularly helpful question.</p><p>I would ask what the website is for, how long it is likely to exist, what happens if it stops working, and who wants to look after it. Those answers usually make it much easier to decide what is worth spending.</p><p>A free website is not secretly bad, and an expensive one is not automatically good. The price is only part of it.</p></section>]]></content>
    </entry>
    <entry>
      <id>https://devin.uk/posts/tracking-upstream/</id>
      <title type="text">Git Setup for Tracking Upstream</title>
      <published>2026-09-21T00:00:00.000Z</published>
      <updated>2026-09-21T00:00:00.000Z</updated>
      <author><name>Devin Cheung</name></author>
      <link rel="alternate" href="https://devin.uk/posts/tracking-upstream/"/>
      <summary type="text">Practical Git notes for keeping a clean upstream branch while doing all site customisation on main.</summary>
      <content type="html"><![CDATA[<p>I started this site from an existing template and expect to change quite a lot of it over time. I also want to keep a reasonable way to pull in useful changes from the original repository.</p>
<p>Those two goals get less compatible with every local edit.</p>
<p>The setup I am using is deliberately small:</p>
<ul>
<li><code>template</code> is a clean copy of the upstream branch.</li>
<li><code>main</code> contains the actual site and all of my changes.</li>
<li>Upstream updates go to <code>template</code> first, then get merged into <code>main</code>.</li>
</ul>
<p>This gives me a stable reference point without requiring a separate public fork.</p>
<p>These are practical notes for that setup, mostly so I do not have to reconstruct it later.</p>
<section><h2>Starting from an Empty Repository<a href="#starting-from-an-empty-repository"><span>#</span></a></h2><p>I first created an empty repository on GitHub, then cloned it locally:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>clone</span><span> </span><span>https://github.com/YOU/YOUR-BLOG.git</span></div></div><div><div><div>2</div></div><div><span>cd</span><span> </span><span>YOUR-BLOG</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Because the repository was empty, there was no <code>main</code> history to preserve. I created the clean template branch first:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>switch</span><span> </span><span>-c</span><span> </span><span>template</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Then I added the source repository as <code>upstream</code>:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>remote</span><span> </span><span>add</span><span> </span><span>upstream</span><span> </span><span>https://github.com/AUTHOR/REPO.git</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>I only need to fetch from that remote. Disabling pushes adds a small guard against sending anything there by mistake:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>remote</span><span> </span><span>set-url</span><span> </span><span>--push</span><span> </span><span>upstream</span><span> </span><span>DISABLE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Now <code>git remote -v</code> should show something like this:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>origin    https://github.com/YOU/YOUR-BLOG.git (fetch)</span></div></div><div><div><div>2</div></div><div><span>origin    https://github.com/YOU/YOUR-BLOG.git (push)</span></div></div><div><div><div>3</div></div><div><span>upstream  https://github.com/AUTHOR/REPO.git (fetch)</span></div></div><div><div><div>4</div></div><div><span>upstream  DISABLE (push)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Next, I fetched the upstream history and made <code>template</code> point to its default branch:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>fetch</span><span> </span><span>upstream</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>reset</span><span> </span><span>--hard</span><span> </span><span>upstream/master</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>The upstream repository in this example uses <code>master</code>. If it uses <code>main</code>, the last command should be <code>git reset --hard upstream/main</code> instead.</p><p>There is no merge here. The local repository started empty, so <code>template</code> can simply begin at the same commit as upstream.</p></section>
<section><h2>Creating the Working Branch<a href="#creating-the-working-branch"><span>#</span></a></h2><p>With <code>template</code> in place, I created <code>main</code> from it:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>switch</span><span> </span><span>-c</span><span> </span><span>main</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>All personal changes belong on this branch.</p><p>I then pushed both branches to my own repository:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>push</span><span> </span><span>-u</span><span> </span><span>origin</span><span> </span><span>main</span></div></div><div><div><div>2</div></div><div><span>git</span><span> </span><span>push</span><span> </span><span>-u</span><span> </span><span>origin</span><span> </span><span>template</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>At this point, the branch roles are clear: <code>template</code> is the clean reference, while <code>main</code> is allowed to diverge.</p></section>
<section><h2>Pulling Upstream Changes Later<a href="#pulling-upstream-changes-later"><span>#</span></a></h2><p>The update routine is:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>fetch</span><span> </span><span>upstream</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>git</span><span> </span><span>switch</span><span> </span><span>template</span></div></div><div><div><div>4</div></div><div><span>git</span><span> </span><span>reset</span><span> </span><span>--hard</span><span> </span><span>upstream/master</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>git</span><span> </span><span>switch</span><span> </span><span>main</span></div></div><div><div><div>7</div></div><div><span>git</span><span> </span><span>merge</span><span> </span><span>template</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>git</span><span> </span><span>push</span><span> </span><span>origin</span><span> </span><span>main</span></div></div><div><div><div>10</div></div><div><span>git</span><span> </span><span>push</span><span> </span><span>origin</span><span> </span><span>template</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Using <code>reset --hard</code> on <code>template</code> is intentional. That branch should contain no personal work, so its job is to match upstream exactly.</p><p>It is still worth checking the current branch before running the reset:</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>git</span><span> </span><span>status</span><span> </span><span>--short</span><span> </span><span>--branch</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>If upstream has changed files that I also customised, the conflict happens when <code>template</code> is merged into <code>main</code>. That is where it belongs: the clean branch remains clean, and the decisions about my version stay on the working branch.</p></section>
<section><h2>Why Keep the Extra Branch?<a href="#why-keep-the-extra-branch"><span>#</span></a></h2><p>It would be simpler to modify the template once and forget about upstream. For a small site, that may be entirely reasonable.</p><p>I kept the extra branch because it answers two useful questions:</p><ul>
<li>What did the original project change?</li>
<li>What did I change on top of it?</li>
</ul><p>The branch does not remove merge conflicts, but it makes their source much easier to understand.</p><p>A little structure now is cheaper than trying to remember the history six months later.</p></section>]]></content>
    </entry>
    <entry>
      <id>https://devin.uk/posts/hello-world/</id>
      <title type="text">Hello World! I Rebuilt My Blog Again</title>
      <published>2026-09-20T00:00:00.000Z</published>
      <updated>2026-09-20T00:00:00.000Z</updated>
      <author><name>Devin Cheung</name></author>
      <link rel="alternate" href="https://devin.uk/posts/hello-world/"/>
      <summary type="text">A fresh start for my personal site, and a small attempt to make it somewhere I will actually return to.</summary>
      <content type="html"><![CDATA[<p>I’ve rebuilt my personal website more times than I’d like to admit.</p>
<p>Most versions started with roughly the same plan: make a clean portfolio, add a few projects, write some posts, and keep improving it later.</p>
<p>The “later” part usually didn’t happen.</p>
<p>This time, I wanted something a little different. Less like a landing page that happens to have a blog attached, and more like a place I would actually enjoy coming back to.</p>
<p>So here we are.</p>
<section><h2>A Personal Site, Not a Product Page<a href="#a-personal-site-not-a-product-page"><span>#</span></a></h2><p>The old versions of my site were always trying to explain me quickly.</p><p>There would be a headline, a list of technologies, a few carefully arranged projects, and some variation of the usual full-stack developer introduction. None of it was necessarily wrong, but it made the site feel finished before I had written anything on it.</p><p>That is not what I want from this version.</p><p>I want a small corner of the internet where I can keep notes, write about things I am building, and occasionally follow an idea that has nothing to do with software. It does not need a detailed content strategy. It just needs to be somewhere I am happy to publish.</p><p>The rough description is simple:</p><blockquote><p>A developer’s personal corner of the internet — mostly software, occasionally everything else.</p></blockquote><p>That leaves enough room for the site to change without requiring another identity crisis every six months.</p></section>
<section><h2>Why Astro?<a href="#why-astro"><span>#</span></a></h2><p>I spend most of my working time building web applications, and I have worked with Angular for several years.</p><p>For a personal blog, though, I didn’t really want an application.</p><p>I wanted pages.</p><p><a href="https://astro.build/" target="_blank">Astro</a> fits that idea quite well. Most of this site is content, so static HTML is a sensible default. If a page needs something interactive later, I can add it without turning the whole site into a client-side application.</p><p>The basic model stays pleasantly small:</p><p>content goes in, HTML comes out.</p><p>There are plenty of good ways to build a blog. I chose Astro mostly because its defaults match what I want this site to be: simple, fast, and fairly boring.</p><p>I mean that as a compliment.</p></section>
<section><h2>What I Plan to Write<a href="#what-i-plan-to-write"><span>#</span></a></h2><p>I do not have a publishing schedule or a long list of topics ready to go.</p><p>I will mostly write about software, things I am building, problems I have run into, and ideas that stayed in my head long enough to be worth writing down. Some posts will be technical. Some may not be.</p></section>
<section><h2>A Small Beginning<a href="#a-small-beginning"><span>#</span></a></h2><p>This is not a launch announcement or a promise that I will suddenly become consistent at blogging.</p><p>It is just the first note on a rebuilt site, and a reminder of what I wanted the site to be before I started adding too much to it.</p><p>For now, I am mostly happy to have a personal website that feels personal again.</p><p>Let’s see how long it takes before I rebuild it.</p></section>]]></content>
    </entry>
</feed>
