惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
Security Latest
Security Latest
P
Privacy International News Feed
T
Threat Research - Cisco Blogs
H
Help Net Security
T
The Exploit Database - CXSecurity.com
Know Your Adversary
Know Your Adversary
博客园_首页
S
Securelist
S
Schneier on Security
G
GRAHAM CLULEY
Cisco Talos Blog
Cisco Talos Blog
V
Visual Studio Blog
博客园 - 叶小钗
C
Cybersecurity and Infrastructure Security Agency CISA
有赞技术团队
有赞技术团队
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
Stack Overflow Blog
Stack Overflow Blog
量子位
L
Lohrmann on Cybersecurity
Hugging Face - Blog
Hugging Face - Blog
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
A
Arctic Wolf
P
Privacy & Cybersecurity Law Blog
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
The Hacker News
The Hacker News
罗磊的独立博客
博客园 - 司徒正美
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 【当耐特】
Microsoft Security Blog
Microsoft Security Blog
K
Kaspersky official blog
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
L
LINUX DO - 热门话题
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
V2EX
V
Vulnerabilities – Threatpost
AWS News Blog
AWS News Blog
小众软件
小众软件
Project Zero
Project Zero

alexwlchan

Preventing line breaks in <code> elements Fixing a bug with byte order marks A Git hook to prevent committing directly to main Describing all my photos I don’t want to repeat repeat myself Rebuilding the computer room What can wonky APIs tell us about the web? Using the Screen Capture API to record a browser window Using Pytester to test my Playwright fixtures Rendering a chat thread in CSS and JavaScript Waiting for website changes in the browser Watching for file changes on macOS Using Playwright to test my static sites Building a basic cache with SQLite HTTP GET requests with the Python standard library Auditing my local Python packages Quietly quantum-resistant blogging Creating a personalised bin calendar Monki Gras 2026 “Prepping Craft” The selfish case for public libraries Dreaming of a ten-year computer Gumdrop, a silly app for messing with my webcam Creating Caddyfiles with Cog Swapping gems for tiles Parody posters for made-up movies The Good, the Bad, and the Gutters Using perceptual distance to create better headers The passwords I actually memorise Where I store my multi-factor recovery codes Quick-and-dirty print debugging in Go My favourite books from 2025 Drawing Truchet tiles in SVG Adding a README to S3 buckets with Terraform The palm tree that led to Palmyra
The bare minimum for syncing Git repos
2026-02-17 · via alexwlchan

I have some personal Git repos that I want to sync between my devices – my dotfiles, text expansion macros, terminal colour schemes, and so on.

For a long time, I used GitHub as my sync layer – it’s free, convenient, and I was already using it – but recently I’ve been looking at alternatives. I’m trying to reduce my dependency on cloud services, especially those based in the USA, and I don’t need most of GitHub’s features. I made these repos public, in case somebody else might find them useful, but in practice I think very few people ever looked at them.

There are plenty of GitHub-lookalikes, which are variously self-hosted or hosted outside the USA, like GitLab, Gitea, or Codeberg – but like GitHub, they all have more features than I need. I just care about keeping my files in sync. Maybe I could avoid introducing another service?

As I thought about how Git works, I thought of a much simpler way – and I’m almost embarrassed by how long it took me to figure this out.

A Git repo is just a collection of files

In Git repos, there’s a .git folder which holds the complete state of the repo. It includes the branches, the commits, and the contents of every file. If you copy that .git folder to a new location, you’d get another copy of the repo. You could copy a repo with basic utilities like cp or rsync – at least, as a one-off. I wouldn’t recommend using them for regular syncing; it would be easy to lose data, because they don’t know how to merge changes from different devices.

Git’s built-in push and pull commands are smarter: they can synchronise this state between locations, compare the history of different copies, and stitch the changes together safely. Within a repo, you can create a remote location, a pointer to another copy of the repo that lives somewhere else. When you push or pull, your local .git folder gets synchronised with that other copy.

We’ve become used to the idea that the remote location is a cloud service – but it can just as easily be a folder on your local disk – and that gives me everything I want.

Bare and non-bare repositories

Before I explain the steps, I need to explain the difference between bare and non-bare repositories.

In our day-to-day work, we use non-bare repositories. They have a “working directory” – the files you can see and edit. The .git folder lives under this directory, and stores the entire history of the repo. The working directory is a view into a particular point in that history.

By contrast, a bare repository is just the .git folder without the working directory. It’s the history without the view.

You can’t push changes to a non-bare repo – if you try, Git will reject your push. This is to avoid confusing situations where the working directory and the .git folder get out of sync. Imagine if you had the repo open in a text editor, and somebody else pushed new code to the repo – suddenly your files would no longer match the Git history.

Whenever we push, we’re normally pushing to a bare repository. Because nobody can “work” inside a bare repo, it’s always safe to receive pushes from other locations – there’s no working directory to get out of sync.

My new setup

I have a home desktop which is always running, and it’s connected to a large external drive. For each repo, there’s a bare repository on the external drive, and then all my devices have a checked-out copy that points to the path on that external drive as their remote location. The desktop connects to the drive directly; the other devices connect over SSH.

This only takes a few commands to set up:

  1. Create a bare repository on the external drive.

    $ cd /Volumes/Media/bare-repos
    $ git init --bare dotfiles
  2. Set the bare repository as a remote location.

    On the home desktop, which mounts the external drive directly:

    $ cd ~/repos/dotfiles
    $ git remote add origin /Volumes/Media/bare-repos/dotfiles

    On a machine, which can access the drive over SSH:

    $ cd ~/repos/dotfiles
    $ git remote add origin alexwlchan@desktop:/Volumes/Media/bare-repos/dotfiles

    This allows me to run git push and git pull commands as normal, which will copy my history to the bare repository.

  3. Clone the bare repository to a new location.

    When I set up a new computer:

    $ git clone /Volumes/Media/bare-repos/dotfiles ~/repos/dotfiles

This approach is very flexible, and you can store your bare repository in any location that’s accessible on your local filesystem or SSH. You could use an external drive, a web server, a NAS, whatever. I’m using Tailscale to get SSH access to my repos from other devices, but any mechanism for connecting devices over SSH will do. (Disclaimer: I work at Tailscale.)

Of course, this is missing many features of GitHub and the like – there’s no web interface, no issue tracking, no collaboration – but for my small, personal repos, that’s fine. There’s also no third-party hosting, no risk of outages, no services to manage. I’m just moving files about over the filesystem. It feels like the Git equivalent of static websites, in a good way.

Reflections

I used to throw every scrap of code onto GitHub in the vague hope of “sharing knowledge”, but most of it was digital clutter.

Nobody was reading my personal repos in the hope of learning something. They’re a grab bag of assorted snippets, with only a loose definition or purpose – it’s unlikely another person would know what they could find, or spend the time to go looking. Sharing knowledge requires more than just publishing code somewhere; you need to make it possible for somebody to find.

Extracting my ideas into standalone, searchable snippets makes them dramatically more useful and discoverable. There are single blog posts that have done more good than my entire corpus of code on GitHub – and I have hundreds of blog posts.

I still have plenty of public repos, but it’s specific libraries or tools with a clear purpose. It’s more obvious whether you might want to read it, and better documented if you do. It’s an intentional selection, not a random set of things I want to keep in sync.

For years, I’ve been using a social media site as a glorified file-syncing service, but I don’t need pull requests, an issue tracker, or a CI/CD pipeline to move a few macros between my machines – just a place to put my code. As with so many digital things, files and folders are all I need.