What are dotfiles?
Dotfiles are files where the programs store their configuration. Dotfiles are named that way because most of them starts with a dot “.”, although, nowadays, it’s common to use this term to refer to any configuration file.
When you install a new program, you spend a lot of time reading documentation and trying and setting options, until fits you well. Some examples of programs that uses dotfiles are: bash, zsh, git, tmux, vim… In addition to these, I like to save another dotfiles (like .xprofile) and another configuration files (awesomewm, neovim, mplayer, yt-dlp, conky…).
Saving these dotfiles (or configuration files) will save you a lot of time, and will allow you to mantain a consistency between computers. And I love these two things.
Let’s say that you uninstalled some of these programs, or you are doing a fresh install of your operating system, or, maybe, you are installing some of these programs in another computer. After install these programs, you will only have to override their dotfiles (or config files) and everything will be to your liking and the same between systems/computers (if applicable).
I have many computers, all but one, using gnu/linux. I keep some configs of all of them, some scripts or batch files (yep, it’s very useful backup these too) and even the wallpaper.
Is true that we can do this with a simple backup in any hard drive, but let’s face it, we are programmers; and have the dotfiles backuped in a remote (and always available) git server (as github) is very comfortable.
The “all in one” approach
This was my first approach. This approach consists of having one repository with only one branch. Then we will structure everything in folders.
Once we had cloned our repository, we will delete our local dotfiles (or config files) and make symlinks to the files in the repository.
My choice is to do hard links for files and soft links for the folders, but as you like ;)
We will have something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
dotfiles
├── linux
│ ├── common
│ │ ├── configs
│ │ │ ├── aliases
│ │ │ ├── awesome
│ │ │ ├── nvim
│ │ │ ├── .tmux
│ │ │ ├── .vimrc
│ │ │ └── yt-dlp.conf
│ │ ├── .mplayer
│ │ └── scripts
│ │ └── script1
│ ├── desktop
│ │ ├── configs
│ │ │ ├── .bashrc
│ │ │ ├── conky.conf
│ │ │ ├── .gitconfig
│ │ │ ├── .xprofile
│ │ │ └── .zshrc
│ │ ├── scripts
│ │ │ ├── script1
│ │ │ └── script2
│ │ └── wallpaper
│ │ └── wallpaper.jpg
│ ├── laptop1
│ │ ├── configs
│ │ │ ├── .bashrc
│ │ │ ├── .gitconfig
│ │ │ ├── .xprofile
│ │ │ └── .zshrc
│ │ ├── scripts
│ │ │ ├── script1
│ │ └── wallpaper
│ │ └── wallpaper.jpg
│ └── laptop2
│ ├── configs
│ │ ├── .bashrc
│ │ ├── .gitconfig
│ │ ├── .xprofile
│ │ └── .zshrc
│ ├── scripts
│ │ ├── script1
│ │ └── script2
│ │ └── script3
│ └── wallpaper
│ └── wallpaper.jpg
└── windows
├── configs
│ ├── config1.cfg
│ └── config2.cfg
├── scripts
│ ├── batch1.bat
│ └── batch2.bat
└── wallpaper
└── wallpaper.jpg
Pros
Very easy to mantain.
One repository, one branch. It’s very easy to keep track of the changes. You have the same repository and the same branch in all of your machines.
Common files are easily synchronized
If we use a
common
directory to store the dotfiles that are the same in all the machines, we can keep our common configuration files easily synchronized.
Cons
Fragmentation
Over time we will have fragmented configurations (if we use the common folder). In the worst case, we will get rid of the
common
directory.Useless configurations
Wether we have it or not the
common
folder, we will have a lot of files (configurations, scripts, wallpapers…) from other computers that will be, mostly, useless for us in the current computer.
The “m-branches” approach
This is my current approach, it’s similar to the “all in one” approach. We will have one repository, but one branch per machine (that’s why the “m” in the name).
Each branch will contain only the dotfiles for one computer. We will have something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dotfiles/desktop
├── configs
│ ├── aliases
│ ├── awesome
│ ├── .bashrc
│ ├── conky.conf
│ ├── .gitconfig
│ ├── .mplayer
│ ├── nvim
│ ├── .tmux
│ ├── .vimrc
│ ├── .xprofile
│ ├── yt-dlp.conf
│ └── .zshrc
├── scripts
│ ├── script1
│ └── script2
└── wallpaper
└── wallpaper.jpg
Pros
- We will have only the files related to the current machine.
Cons
Management can get a little complicated
If we make a change to a file that we want to push to other machines, we will have to do it manually on the other branches.
If we create a file on one machine that we want to have on other machines, we will have to do it manually or propagate it with git to the other branches.
Branch switching
If you change branches, while your aren’t in the current computer branch, your links will break. So, If you need to switch branch, for whatever reason, it’s better to clone the repository (again) in another location.
The “StreakyCobra” approach
This is the better approach. Why? Look at this name, how can it not be the best with this name?
I saw this method in a Hacker news thread: Ask HN: What do you use to manage dotfiles?. This was the response given by the user StreakyCobra.
This is going to be by next system (as soon as I feel like reorganizing some machine). This method is similar to the “m-branches”, one repository and one branch per machine, with the difference that this method does not need extra tools or symlinks. So, we will end having something similar to the “m-branches”, but more comfortable to manage.
Creating the repository
If you don’t have the repository yet, you need to create it:
1
git init --bare $HOME/.myconf # Creates the new repository. Replace with your own path.
Cloning the repository
If you have the repository, you have to clone it.
If you have your home directory empty (is not the usual thing), you can clone the repository:
1
git clone --separate-git-dir=$HOME/.myconf /path/to/repo $HOME
–separate-git-dir=$HOME/.myconf: This option specifies that the Git repository configuration should be stored in the directory $HOME/.myconf instead of the usual .git subdirectory within the cloned repository.
/path/to/repo: The URL or path to the Git repository that you want to clone.
$HOME: This is the path where you want to clone the repository.
If you don’t have your $HOME directory empty, you will need to clone it in a temporary directory and then delete the temporary directory:
1
2
git clone --separate-git-dir=$HOME/.myconf /path/to/repo $HOME/myconf-tmp
rm -r $HOME/myconf-tmp/
Creating the “config” alias
1
alias config='/usr/bin/git --git-dir=$HOME/.myconf/ --work-tree=$HOME' # Defines an alias named "config" that executes git commands using the specified repository.
The creation of the alias
config
avoids interference when we use thegit
command in other repositories.
Hidding untracked files
We will hide the untracked files in the status output:
1
config config status.showUntrackedFiles not
Managing files
Any file can be versioned with normal commands, but you have to replace the git
command by the alias config
.
1
2
3
4
config status
config add .vimrc
config commit -m "Add vimrc"
config push
Cloning the repository in a new machine
The normal cloning will fail if the home directory is not empty. When we will clone the repository in a new machine, we will have to clone the repository into a temporary directory and then delete this temporary directory.
1
2
3
4
git clone --separate-git-dir=$HOME/.myconf /path/to/repo $HOME/myconf-tmp
cp $HOME/myconf-tmp/.gitmodules $HOME # If you use Git submodules
rm -r $HOME/myconf-tmp/
alias config='/usr/bin/git --git-dir=$HOME/.myconf/ --work-tree=$HOME'
Pros
- No need to create symlinks.
- We will have only the files related to the current machine.
Cons
- Needs an alias to do not interfere with the
git
command in other repositories. - We will have to delete a (temporary) directory. Is it really a con?
Enjoy! ;)