Stow - symlink manager

Managing dot files is a task that needs some automation and version control. Using Stow makes some things better than just running a bare git repository.

Stow - symlink manager
Photo by Nick Fewings / Unsplash

Stow is a symlink manager. It generates symlinks to directories of data and makes them appear to be merged into the same directory. It is typically used for managing software packages installed from source, by letting you install them apart in distinct directories and then create symlinks to the files in a common directory, such as /usr/local.

Stow was inspired by Carnegie Mellon's "Depot" program, but is substantially simpler.

GNU Stow is a symlink farm manager which takes distinct sets of software and/or data located in separate directories on the filesystem, and makes them all appear to be installed in a single directory tree.

No extra tooling, no symlinks, files are tracked on a version control system, you can use different branches for different computers, you can replicate your configuration easily on new installation.

For example, /usr/local/bin could contain symlinks to files within /usr/local/stow/emacs/bin, /usr/local/stow/perl/bin etc., and likewise recursively for any other subdirectories such as .../share, .../man, and so on.

This is particularly useful for keeping track of system-wide and per-user installations of software built from source. It can also facilitate a more controlled approach to management of configuration files in the user's home directory, especially when coupled with version control systems, GIT.

Stow is implemented as a combination of a Perl script providing a CLI interface, and a backend Perl module which does most of the work. Stow is Free Software, licensed under the GNU General Public License.

Install and Setup

First you need to create a directory and install the package

  • using your packet manager (pacman, apt, nala), sudo nala install stow
    from GNU GIT git clone https://git.savannah.gnu.org/git/stow.git.
  • mkdir ${HOME}/cfg or .cfg or dotfiles, it's up to your imagination
  • It's recommended adding a Private GIT repository on GitLab/GitHub or something. You can also use a self-hosted git repository on your Proxmox.

Example β€” Files in ${HOME}/

cp .zshrc cfg && mv .zshrc .zsfrc.bak
cd cfg
stow .

Example β€” Subdirectories in ${HOME}/

mkdir -p /cfg/.config
cp -r ~/.config/alacritty cfg/.config 
mv /.config/alacritty ./config/alacritty.bak
cd cfg
stow .

Set up Git Version Control

After that, we can simply move mv the files and/or directories into cfg and do stow . to create all the needed symlinks. If anything goes sideways, use git to get back to a working setup.

Local Files for Bash/Fish/Zsh

Depending on your use case, you can either keep them in the ${HOME}/ or move them to the cfg. They can be very helpful if you want to restore from skell and keep your settings, but you might not want to share them.
If you use a Local git repository, it's best to move them to cfg.

Perform the following commands:

cd ~/cfg
stow bash
stow alacritty
stow nano
stow nvim
# stow all by stow .

Use GIT Locally

A benefit is to be able to roll back by using git version control.

cd cfg
git init
git add .zshrc # add one
#git add . # add all
git commit -m "Initial commit"
git log # Check progress 
#git git checkout <commit ID> # Restore to previuous

As you can, check in ~/.stow-global-ignore .git is ignored, so all is fine.

Local ignores

You can also create a local ignore, ~/.stow-local.ignore, for personal ignores. You may want to have one to ignore .git and a test directory. Use CLI or create and edit ~/.stow-local-ignore, link to manual.

echo ".git" > .stow-local-ignore
echo "test" >> .stow-local-ignore

Create a local ignore, ~/.stow-local-ignore file

Add a Remote Repository

The benefits are to be able to roll back, store on a remote device and the ease of clone them to a new system.

You can use any web-based git repository or self-host one. Please select a Private option if you prefer not to share, or you have sensitive information in the dot-files.

It is advisable to refrain from storing passwords and other sensitive data without implementing stringent security measures, or alternatively, refrain from doing so altogether.

Create a new repository, name it something like dotfiles, make it Private or Public, and link your directory cfg to it. Create a key using ed-25519, ssh-keygen -t ed25519 -C "My cfg/" -f cfg. Add your public key cfg.pub to GitHub and set any other settings to your liking.
Add that key to the ssh-agent, eval "$(ssh-agent -s)" and ssh-add ~/.ssh/cfg

git remote add origin [email protected]:<user name>/cfg.git
git push origin main

First time use git push --force origin main

Git is entirely local β€” your local Git repository isn't controlled by the server you use to store code on. It only connects to the remote repository when pushing or pulling updates. When it does this, it uses your Git account details.

Implementation of Stow

You should mimic the dot-file structure in your ${HOME}/ in the cfg directory

home/
    <user name>/
        .config/
            app/
                [...some files]
        .local/
            share/
                app/
                    [...some files]
        .vim/
            [...some files]
        .bashrc
        .bash_profile
        .bash_logout
        .vimrc

Example of a home directory

You would then create the cfg subdirectory and move the files there:

home/
    <user name>/
        .config/
        .local/
            .share/
        cfg/
            bash/
                .bashrc
                .bash_profile
                .bash_logout
            app/
                .config/
                    app/
                        [...some files]
                .local/
                    share/
                        app/
                            [...some files]
            vim/
                .vim/
                    [...some files]
                .vimrc

The Example with the cfg directory implemented

Using more than one Git Repository

To make Git use different keys for different accounts, you'll want to edit ~/.ssh/config and add a Host block for each account.

# Default config
Host github.com-base-app
  HostName github.com
  User <user>
  IdentityFile ~/.ssh/id_ed25519

# Account 2
Host github.com-cfg
  HostName github.com
  User <user>
  IdentityFile ~/.ssh/cfg

~/.ssh/config

Then git clone with this command:

git clone -c core.sshCommand="ssh -i ~/.ssh/cfg" [email protected]:<user>/cfg.git

A local .git/config Example

[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	sshCommand = ssh -i ~/.ssh/cfg
[remote "origin"]
	url = [email protected]:user-name/cfg.git
	fetch = +refs/heads/*:refs/remotes/origin/*

My configurations look like this because a have many GitLab and GitHub repositories

Install on a New Machine

Using git and stow, you easily get all your favorite stuff working in no time. Install git and stow on the new machine, along other stuff like starfish and fzf.

sudo nala install git stow
git clone [email protected]/<user name>/cfg.git
cd cfg
stow .
πŸ’‘
Note,It's not always a good idea to add GNU stuff to Linux.

 [FSF logo] 
β€œThe Free Software Foundation (FSF) is a nonprofit with a worldwide mission to promote computer user freedom. We defend the rights of all software users.”

References

GNU Stow [1] Git [2]


  1. GNU Stow homepage, documentation, man page, git page β†©οΈŽ

  2. Git documentation on GitHub Docs, Git homepage β†©οΈŽ