<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/feeds/rss-style.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Afdal Sebi</title>
        <link>https://asebi.dev</link>
        <description>Minimal blog built by Astro</description>
        <lastBuildDate>Fri, 05 Jun 2026 00:44:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Astro Chiri Feed Generator</generator>
        <language>en-US</language>
        <copyright>Copyright © 2026 Afdal Sebi</copyright>
        <atom:link href="https://asebi.dev/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[The road to a blog]]></title>
            <link>https://asebi.dev/the-road-to-a-blog</link>
            <guid isPermaLink="false">https://asebi.dev/the-road-to-a-blog</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[This post documents my near two year journey of deciding on and off to host a personal website. The long time frame includes periods of: Figuring what I wanted it to be about. Deciding whether or not ...]]></description>
            <content:encoded><![CDATA[<p>This post documents my near two year journey of deciding on and off to host a personal website. The long time frame includes periods of:</p>
<ul>
<li>Figuring what I wanted it to be about.</li>
<li>Deciding whether or not it would be worth doing, or if I’d even have any content worth posting.</li>
<li>Deciding how it should look.</li>
<li>Deciding what it should include.</li>
<li>Deciding how it should be hosted.</li>
<li>Testing and execution.</li>
</ul>
<h1>Initial Plans</h1>
<p>My initial plans were to setup a blog to practice writing, and have a place to share my notes and thoughts in a more meaningful way that was under my control and not just by posting on Instagram into the ether. An added benefit would be to learn a bit more about software development, and to implement some basic CI/CD practices.</p>
<p>My first steps included:</p>
<ol>
<li>Setting the site up functionally.</li>
<li>Creating a CI/CD pipeline for server updates after code changes are tested.</li>
<li>Integrating my org-mode notes directly into the website.</li>
</ol>
<p>For the last point, I wanted a system in which I could write something in org-mode (where I use the <a href="https://protesilaos.com/emacs/denote">denote</a> packages), and then be able to press a few keybinds to export the note or post into an appropriate format (in this case, a Markdown file), into the directory that my site is hosted. This would minimise any friction between my preferred writing environment, and the update of the blog.</p>
<h1>Settling on the Astro Framework</h1>
<p>After doing a bit of research on other static blogs, it seemed like the Astro framework was a good place to start. Particularly as I saw that there were some examples of others using Astro integrated with Emacs <code>ox-hugo</code> exports.</p>
<p>Some of the benefits with Astro that I noticed are that it:</p>
<ul>
<li>Generates static websites, so a backend is not needed;</li>
<li>Takes Markdown files as inputs and outputs HTML;</li>
<li>Uses JavaScript, so I can take libraries from the <code>npm</code> ecosystem.</li>
</ul>
<h2>Steps to run Astro Website in NixOS</h2>
<p>NixOS has been my Linux distro of choice, so I started with the below.</p>
<ol>
<li>
<p>Run <code>nix develop</code> with the following <code>flake.nix</code> to enable NodeJS.</p>
<pre><code class="language-nix">{
  description = "A Nix-flake-based Node.js development environment";

  inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz";

  outputs = { self, nixpkgs }:
    let
      overlays = [
        (final: prev: rec {
          nodejs = prev.nodejs_latest;
          pnpm = prev.nodePackages.pnpm;
          yarn = (prev.yarn.override { inherit nodejs; });
        })
      ];
      supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
      forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
        pkgs = import nixpkgs { inherit overlays system; };
      });
    in
    {
      devShells = forEachSupportedSystem ({ pkgs }: {
        default = pkgs.mkShell {
          packages = with pkgs; [ node2nix nodejs pnpm yarn ];
        };
      });
    };
}
</code></pre>
</li>
<li>
<p>Create a directory for your project and run <code>npm create astro@latest</code>.</p>
</li>
<li>
<p>Enter the directory of the initialised Astro project, and run <code>npm run dev</code>.</p>
</li>
</ol>
<h2>Initial Thoughts with Astropaper Theme</h2>
<p>My first test was with the <a href="https://astro-paper.pages.dev/">Astropaper</a> theme. I ported over some of my early tests with Markdown files with images of a few of my bonsai trees but overall the theme felt rather… heavy.</p>
<p>I found that the theme offered a lot of features, and lot’s of different configuration elements but I none of them felt really necessary for me. Another gripe was that converting from my org-mode files to Markdown presented a lot of friction, in that I needed to figure out a special way to generate the required header file in the Astropaper template, and finally, have to shift all of my headings down one level as Astropaper used level 1 headings for titles.</p>
<p>This ended up as an ~2 hour experiment, and I then moved on to trying out a Hugo website with <code>ox-hugo</code>, an Org to Hugo exporter.</p>
<h1>Detour with Emacs + Org Mode + Ox-Hugo</h1>
<p>At first, it seemed like <code>ox-hugo</code> in conjunction with Nix would be a nice combination to move forward based on this website example <a href="https://shom.srht.site/">https://shom.srht.site/</a> .</p>
<p>There were various good references that I found using Hugo including:</p>
<ul>
<li><a href="https://jiewawa.me/2024/03/blogging-with-denote-and-hugo/">One with the use</a> of <code>denote</code> and <code>hugo</code>.</li>
<li><a href="https://zzamboni.org/post/my-blogging-setup-with-emacs-org-mode-ox-hugo-hugo-gitlab-and-netlify/">A reference for ox-hugo, gitlab and netlify</a>.</li>
<li><a href="https://shom.dev/">One with a photo gallery that would have been useful to implement for my photography</a>.</li>
</ul>
<h2>Hugo Test</h2>
<p>I ran some tests, and enjoyed the workflow with Hugo, but eventually lost interest as the site and theme didn’t speak to me on an aesthetic level and it also didn’t seem like a good fit for implementing photography.</p>
<ol>
<li>
<p>Install <code>hugo</code>, which can be done temporarily in <code>nix</code> with <code>nix-shell -p hugo</code>.</p>
</li>
<li>
<p>Create a new Hugo site with the <a href="https://github.com/adityatelange/hugo-PaperMod">PaperMod</a> theme.</p>
<pre><code class="language-sh">hugo new site quickstart
cd quickstart
git init
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
echo "theme = 'PaperMod'" &gt;&gt; hugo.toml
hugo server
</code></pre>
</li>
<li>
<p>New content can be created using the <code>hugo</code> CLI command, or by simply adding files into the relevant directory.</p>
</li>
</ol>
<pre><code class="language-sh">hugo new content content/posts/my-first-post.md
</code></pre>
<p>By default, the front matter will have a <code>draft</code> value of <code>true</code>. By default Hugo does not publish draft content when building the site so take note of this.</p>
<p>Draft content can be built by running <code>hugo server --buildDrafts</code> or with <code>hugo server -d</code>.</p>
<h1>astro-chiri</h1>
<p>I’m not sure where I stumbled upon<a href="https://github.com/the3ash/astro-chiri"> astro-chiri</a> a few months ago, but recently I opened up my blog working folders with a newfound inspiration and have decided that this feels right. With a bit of help from Claude Code I sorted out minor issues I had with the theme, and have also implemented a workflow as planned from Emacs org-mode.</p>
<p>The current setup will be outlined in the next post.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Emacs Tramp]]></title>
            <link>https://asebi.dev/emacs-tramp</link>
            <guid isPermaLink="false">https://asebi.dev/emacs-tramp</guid>
            <pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Table of Contents SSH to Edit Remote File Emacs Sudo Issues and SSH Privileges Issues accessing remote machine with fancy prompt SSH to Edit Remote File Use the find file function with SPC f . and ent...]]></description>
            <content:encoded><![CDATA[<h1>Table of Contents</h1>
<ol>
<li><a href="#orgd4349ef">SSH to Edit Remote File</a>
<ol>
<li><a href="#orga083fa5">Emacs Sudo Issues and SSH Privileges</a></li>
<li><a href="#orgc42c21e">Issues accessing remote machine with fancy prompt</a></li>
</ol>
</li>
</ol>
<p><a id="orgd4349ef"></a></p>
<h1>SSH to Edit Remote File</h1>
<p>Use the find file function with <code>SPC f .</code> and enter the following pattern:</p>
<pre><code>/ssh:&lt;username&gt;@&lt;remotehost&gt;:/&lt;path&gt;/&lt;to&gt;/&lt;file&gt;
</code></pre>
<p><a id="orga083fa5"></a></p>
<h2>Emacs Sudo Issues and SSH Privileges</h2>
<p>Your Tramp session inherits whatever privileges belong to the user you logged in as. If you log in as the root user, you have complete access to your server.</p>
<p>Otherwise, you would need to pass sudo privileges into your session:</p>
<pre><code>/sudo::/path/to/file
</code></pre>
<p><a id="orgc42c21e"></a></p>
<h2>Issues accessing remote machine with fancy prompt</h2>
<p>I’m using ZSH, with some custom config and it appears that this is what is causing my issues logging into machines using tramp, as logging in via root works fine.</p>
<p>This is explained further in sources below:
<a href="https://stackoverflow.com/questions/6954479/emacs-tramp-doesnt-work">https://stackoverflow.com/questions/6954479/emacs-tramp-doesnt-work</a>
<a href="https://www.bounga.org/tips/2017/11/30/fix-emacs-tramp-lag-and-timeout/">https://www.bounga.org/tips/2017/11/30/fix-emacs-tramp-lag-and-timeout/</a></p>
<p>The most simple fix is to include the following in <code>.zshrc</code> on the remote machine.</p>
<pre><code>if [[ $TERM == "dumb" ]]; then
    export PS1="$ "
fi
</code></pre>
<p>There is another <a href="https://fluca1978.github.io/2024/02/15/EmacsTrampZsh.html">source which mentions issues</a> with something called <code>ZLE</code> as reported in the <a href="https://www.gnu.org/software/emacs/manual/html_node/tramp/Remote-shell-setup.html#Other-remote-shell-setup-hints">Tramp manual</a>. This suggests adding the following:</p>
<pre><code>[ $TERM == "tramp" ]] &amp;&amp; unsetopt zle &amp;&amp; PS1='$ ' &amp;&amp; return
</code></pre>
<p>When Tramp connects to a remote host it sets the <code>TERM</code> environment variable as <code>dumb</code> so you know you’re in the situation were you want a really simple prompt. What to do then is to set the prompt to a simple <code>“$ “</code> string.</p>
<p><a href="https://www.emacswiki.org/emacs/TrampMode">EmacsWiki describes the problem as follows:</a></p>
<blockquote>
<p>If you are using zsh, the zle option can cause this behaviour. The Tramp manual does actually note this in 4.16 Remote shell setup hints, and provides a possible workaround there (namely, if you tell TRAMP you’re using zsh, it will automatically supply some extra flags to configure things appropriately; you can see the flags it uses in tramp-sh-extra-args).</p>
<p>Additionally, with the default settings, using sshx rather than ssh will likely work because it will tell the remote host to run /bin/sh instead of zsh.</p>
</blockquote>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Surly Midnight Special Build]]></title>
            <link>https://asebi.dev/surly-midnight-special-build</link>
            <guid isPermaLink="false">https://asebi.dev/surly-midnight-special-build</guid>
            <pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[What started as an exploration into a sale of Surly on the Off Course website has ended in a custom Midnight Special build. The main reason for this decision was wanting a steel bike that could ‘do-it...]]></description>
            <content:encoded><![CDATA[<p>What started as an exploration into a sale of Surly on the Off Course website has ended in a custom Midnight Special build. The main reason for this decision was wanting a steel bike that could ‘do-it-all’ for commuting and maybe bikepacking in future. My goal was to explore more, which led me to test-ride the stock Midnight Special that was on sale, I felt like I wanted something that could be my own rather than just an off-the-shelf bike. Build and photos courtesy of <a href="https://offcourse.bike/">Off Course</a>!</p>
<p><img src="https://asebi.dev/_astro/midnight_special.CxXUHOi4_ZUTPNV.webp" alt="_midnight_special.png" /></p>
<h1>Build</h1>
<h2>Frame</h2>
<p>50cm Midnight Special in Fool’s Gold - pretty rare to see.
I chose the Midnight Special because it’s a steel bike with the look of an old school race bike, but with clearance for wide tyres, 700c x 42mm and 650b x 60mm.
It has a great smooth ride that is pretty responsive when putting down the power and I don’t feel like it lacks much in that department compared to my Focus Paralane. 54cm felt a bit too large, and based off Reddit comments it seems like people my height went for the 50cm. Turns out this is a more aggressive geometry, even in the smaller size compared to my 54cm Focus Paralane.
After some time on the bike, I’m getting used to the riding position. Eventually I might try getting a bike fit but after some tweaks I’m riding pain-free on 2+ hour rides.</p>
<h2>Groupset</h2>
<p><img src="https://asebi.dev/_astro/groupset.DeVzRxgA_qws79.webp" alt="_groupset.jpg" />
<img src="https://asebi.dev/_astro/groupset2.BOey9aNq_ZFVPVd.webp" alt="_groupset2.jpg" /></p>
<p>Scored a full GRX820 groupset that came off a Cannondale SuperX Carbon bike that was getting SRAM put on it for a cyclocross race. This meant I got a great deal on a high-level groupset that had been installed on a bike but never ridden. This included:</p>
<ul>
<li>Shimano GRX820 - 2x12</li>
<li>48-31T, 170mm cranks</li>
<li>11-34T Ultegra cassette</li>
<li>RT-CL800 160mm C/Lock rotors</li>
<li>SMR60 bottom bracket</li>
</ul>
<p>This setup is an upgrade over the stock Surly Midnight Special 2x12 105 groupset which would have been more road-oriented. The GRX adds a clutch which adds tension to the chain reducing the chance of the chain coming off on bumpy terrain, and easier gearing for hills.</p>
<h2>Saddle, Seatpost and Cockpit</h2>
<p><img src="https://asebi.dev/_astro/seatpost.DRHBKFFm_JXlpn.webp" alt="_seatpost.jpg" /></p>
<p>The seatpost and cockpit are all from the Ritchey comp lineup, which matches the theme with light grey branding logos against matte black. These are good value, don’t weigh too much and look great.
The saddle is by Fabric and one I took from my old bike. It came with the prior purchase and works well for me.</p>
<h2>Bartape</h2>
<p><img src="https://asebi.dev/_astro/bartape.CnqhBZc7_Z8Rb8b.webp" alt="_bartape.jpg" /></p>
<p>Grepp bartape in Ultimate Grey. This is a cloth bartape that is washable and re-usable. It doesn’t have as much padding as regular rubber/cork bartape but adds a nice point of difference and suits an all-road and gravel bike well. The grey is a super light in colour and adds a nice pop of contrast to the bike.</p>
<h2>Pedals</h2>
<p><img src="https://asebi.dev/_astro/pedals.DcABeF0i_qDXOf.webp" alt="_pedals.jpg" /></p>
<p>Simworks Tiny Bubbly flat pedals for my day-to-day commute. I was looking for pedals on the smaller side, that had a more modern and refined look. These spin great, feel great and look great although the one downside is things can get a bit slippery when there’s any moisture involved. They’re perfect for everyday riding but now I’ve done some more longer distance rides, and bumpier ride on gravel and single track, I can see the benefit in a clipless system.</p>
<h2>Tyres</h2>
<p><img src="https://asebi.dev/_astro/tyres.BQ7suQY8_Z2st4G8.webp" alt="_tyres.jpg" /></p>
<p>Rene Herse Barlow Pass 38mm. Tossed up between this and Panaracer Gravelking Semi Slicks.
Rene Herse tyres are known for their fast rolling performance and suppleness, making them suitable for of different kinds of terrain.
Initially thought I’d be doing 80/20 road/gravel riding split but that is more like a 50/50 split at the moment so the Gravelkings may have been the better choice!
In future I could get a pair of 650b wheels and put on some proper wide and knobbly tyres if my gravel adventures continued to get a bit more serious. That’s another benefit of the frame.</p>
<h2>Bottle Cages</h2>
<p>Minoura bottle cages in silver that match up with the bartape and Ritchey branding. This is a well-priced option. I could upgrade these to something fancier, but $50+ for a titanium bottle cage seems a bit much!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Itoigawa]]></title>
            <link>https://asebi.dev/itoigawa</link>
            <guid isPermaLink="false">https://asebi.dev/itoigawa</guid>
            <pubDate>Sun, 20 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Itoigawa Juniper Acquired on: 2024-05-25 Overview Itoigawa Junipers are a native variety in Japan that are known to be quite hardy, with bright green dense foliage. It grows quickly and is also often ...]]></description>
            <content:encoded><![CDATA[<h1>Itoigawa Juniper</h1>
<p><strong>Acquired on:</strong> 2024-05-25</p>
<h2>Overview</h2>
<p>Itoigawa Junipers are a native variety in Japan that are known to be quite hardy, with bright green dense foliage. It grows quickly and is also often grafted on to old Shimpaku stock.</p>
<p>This tree was purchased from a Yarra Valley Bonsai Society sale from Shibui Bonsai. Itoigawa’s are quite rare to see in Australia, and bonsai enthusiasts such as Shibui and Bonsai Sensation have only recently started to put stock up for sale after many years cultivating and developing them.</p>
<h2>Progress Updates</h2>
<h3>2024-05-25</h3>
<ul>
<li>Acquired the tree from Yarra Valley Bonsai Society sale.
<img src="https://asebi.dev/_astro/20240525_itoigawa_1.BNcRAEmw_1staUC.webp" alt="_20240525_itoigawa_1" /></li>
</ul>
<h3>2024-06-01</h3>
<ul>
<li><strong>Repotting</strong>: Repotted into a larger container.</li>
</ul>
<h3>2024-06-23</h3>
<ul>
<li><strong>Wiring and Style</strong>: Initial wiring and style applied to accentuate and set movement in the branches. A significant amount of foliage was removed. I am slightly concerned about the removal, as it’s often advised not to defoliate evergreen trees as much as deciduous trees since the energy of the tree is in its foliage.</li>
<li>Monitor tree response in spring to ensure it bounces back well.</li>
</ul>
<p><img src="https://asebi.dev/_astro/20240623_itoigawa_1.B5_2z7yy_XAJF3.webp" alt="_20240623_itoigawa_1" /></p>
<h3>2025-08-28</h3>
<ul>
<li>The tree responded well and grew throughout the year. It is not about to enter spring and I will leave it’s foliage to strengthen and grow vigorously. Next cut back might happen at the end of spring coming into summer. If it has too much foliage in summer, it might take up too much water and leave the pot dry which would be dangerous for the tree.</li>
<li>Have refreshed the fertiliser. Prior fertiliser was placed last spring and left for the year to get used up.</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[FLAC to MP3 beets Importer]]></title>
            <link>https://asebi.dev/flac-to-mp3-beets-importer</link>
            <guid isPermaLink="false">https://asebi.dev/flac-to-mp3-beets-importer</guid>
            <pubDate>Wed, 04 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[This bash script was created to: Convert FLAC files in a folder to 320kbps MP3 files recursively. Import music albums represented as folders in a given folder into my music library using beets. Bash S...]]></description>
            <content:encoded><![CDATA[<p>This bash script was created to:</p>
<ol>
<li>Convert FLAC files in a folder to 320kbps MP3 files recursively.</li>
<li>Import music albums represented as folders in a given folder into my music library using <code>beets</code>.</li>
</ol>
<h1>Bash Script</h1>
<pre><code class="language-sh">#!/bin/bash
# Script to convert FLAC files from a given directory, and then import using beets
# This environment is run from WSL, where beets is running on the host Windows machine (legacy reasons)

default_win_folder="C:\Users\username\Music"
default_wsl_folder="/mnt/c/Users/username/Music"
arr=()

# Function to convert FLAC files to MP3
convert_flac_to_mp3() {
    for item in "${arr[@]}"; do
        flac_file="$item"
        mp3_file="${flac_file%.flac}.mp3"
        echo "Converting: $flac_file -&gt; $mp3_file"
        # ffmpeg conversion command for 320kbps and to keep metadata
        ffmpeg -i "$flac_file" -ab 320k -map_metadata 0 -id3v2_version 3 "$mp3_file"
    done
}

# Clean up FLAC files after converting
delete_old_flac() {
    rm "${arr[@]}"
}

# Function to iterate through subfolders recursively
iterate_subfolders() {
    folder="$1"

    echo "Found Album or Folder: $folder"

    # Iterate through all files and folders in the given folder
    for item in "$folder"/*; do
        if [ -d "$item" ]; then
            # If it's a subfolder, call the function recursively
            iterate_subfolders "$item"
        elif [ -f "$item" ] &amp;&amp; [[ "$item" == *.flac ]]; then
            # Add to list of identified FLAC files
            arr+=("$item")
        fi

    done

    if [ -n "$arr" ]; then
        echo "Found the following FLAC files in folder:"
        printf "%s\n" "${arr[@]}"
        read -p "Convert files in folder? (y/n): " choice
        case "$choice" in
            y|Y ) convert_flac_to_mp3; echo "Conversion of files completed for $folder.";;
            * ) echo "Skipping folder: $folder";;
        esac
        read -p "Delete FLAC files in $folder? (y/n): " choice
        case "$choice" in
            y|Y ) delete_old_flac;;
            * ) echo "Skipping folder: $folder";;
        esac

        # Clear array
        arr=()
    else
        echo "No FLAC files found in this folder, skipping."
    fi
}

# Main script

# Ask for the folder path
read -p "Enter directory (1) or use default (0) '$default_wsl_folder'?" choice
case "$choice" in
    0 ) folder_path=$default_wsl_folder;;
    1 ) read -p "Enter the folder path to search for FLAC files: " folder_path;;
    * ) echo "No valid input.";;
esac

# Check if the folder exists
if [ ! -d "$folder_path" ]; then
    echo "Folder not found!"
    exit 1
fi

# Call the function to iterate through subfolders
iterate_subfolders "$folder_path"

# Run beet import
echo "Running beet import $default_win_folder now. You may need to provide some inputs."
powershell.exe "beet import $default_win_folder"
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[btrfs]]></title>
            <link>https://asebi.dev/btrfs</link>
            <guid isPermaLink="false">https://asebi.dev/btrfs</guid>
            <pubDate>Tue, 04 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Btrfs is a filesystem and the one that I’m currently using on my T480 laptop. It has modern features but also has some features that were unstable as of time of writing (2022). Btrfs is a modern copy ...]]></description>
            <content:encoded><![CDATA[<p><code>Btrfs</code> is a filesystem and the one that I’m currently using on my T480 laptop. It has modern features but also has some features that were unstable as of time of writing (2022).</p>
<blockquote>
<p>Btrfs is a modern copy on write (CoW) filesystem for Linux aimed at implementing advanced features while also focusing on fault tolerance, repair and easy administration.</p>
</blockquote>
<p>As usual, head to the Arch Wiki for a good summary of working with <code>btrfs</code>.
<a href="https://wiki.archlinux.org/title/Btrfs">Btrfs - ArchWiki</a></p>
<h1>Subvolumes</h1>
<h2>Commands</h2>
<h3>Creating a subvolume</h3>
<p>To create a subvolume:</p>
<pre><code class="language-shell">btrfs subvolume create /path/to/subvolume
</code></pre>
<h3>Listing subvolumes</h3>
<p>To see a list of current subvolumes and their ids under path:</p>
<pre><code class="language-shell">btrfs subvolume list -p path
</code></pre>
<h3>Deleting a subvolume</h3>
<p>To delete a subvolume:</p>
<pre><code class="language-shell">btrfs subvolume delete /path/to/subvolume
</code></pre>
<p>Since Linux 4.18, one can also delete a subvolume like a regular directory (rm -r, rmdir).
Mounting subvolumes</p>
<h3>Mounting a subvolume</h3>
<p>Subvolumes can be mounted like file system partitions using the <code>subvol=/path/to/subvolume</code></p>
<h3>Displaying filesystem used/free space</h3>
<p>General linux userspace tools such as df(1) will inaccurately report free space on a Btrfs partition. It is recommended to use btrfs filesystem usage to query Btrfs partitions. For example, for a full breakdown of device allocation and usage stats:</p>
<pre><code class="language-shell">btrfs filesystem usage /
</code></pre>
<h1>Snapshots</h1>
<p>“A snapshot is simply a subvolume that shares its data (and metadata) with some other subvolume, using btrfs’s COW capabilities.”</p>
<p>To create a snapshot:</p>
<pre><code class="language-shell">btrfs subvolume snapshot source [dest/]name
</code></pre>
<p>To create a readonly snapshot add the -r flag. To create writable version of a readonly snapshot, simply create a snapshot of it.</p>
<p>Note:
It is possible for a snapshot to be converted in-place from readonly to writeable. However, this is not recommended because it causes issues with any future incremental send/receive. Making a new writeable snapshot prevents such issues.
Snapshots are not recursive. Every nested subvolume will be an empty directory inside the snapshot.</p>
<h2>Snapper</h2>
<p><a href="http://snapper.io/">Snapper</a> is a tool created by openSUSE’s Arvin Schnell that helps with managing snapshots of Btrfs subvolumes and thin-provisioned LVM volumes. It can create and compare snapshots, revert between snapshots, and supports automatic snapshots timelines.
<a href="https://wiki.archlinux.org/title/Snapper">Snapper - ArchWiki</a></p>
<h2>Booting into Snapshots</h2>
<p>In order to boot into a snapshot, the same procedure applies as for mounting a subvolume as your root partition, as given in section mounting a subvolume as your root partition, because snapshots can be mounted like subvolumes.</p>
<p>If using GRUB you can automatically populate your boot menu with btrfs snapshots when regenerating the configuration file with the help of grub-btrfs or grub-btrfs-gitAUR.
If using rEFInd you can automatically populate your boot menu with btrfs snapshots with the help of refind-btrfsAUR, after enabling refind-btrfs.service.</p>
]]></content:encoded>
        </item>
    </channel>
</rss>