Version controlled configs
Disclaimer: I typed this is a hurry and haven’t proof-read it, or tried running any of the code (except the script at the end).
So a while ago I decided to use git to track all my dot-files and other assorted configuration stuff that each of my linux systems need. I’m going to try to outline how I did this:
First, I have some files that exist on all my machines. These I’m going to call common
files. Things like muttrc
, irssi config scripts, etc. These are also mostly configuration I don’t mind making public.
Second, I have some stuff that are common, but need to be private. I call these private
files.
Lastly, I have files that are specific to a machine, but I still want tracked. Things like .xinitrc
and .profile
are in here.
First thing we did is create some directories:
1 2 |
mkdir -p .config.git/common mkdir -p .config.git/private |
So, all the common configuration stuff will go in ../common
, the ssh/gpg/other private things will go in ../private
, and the machine specific stuff will just go in .config.git
.
Next we create some repos.
1 2 3 |
git init .config.git/common git init .config.git/private git init .config.git |
Excellent. Be careful with this next step, you’re about to not have any configuration.
1 2 3 4 5 6 7 |
cd $HOME mv .bashrc mv *rc .config.git/common mv .ssh .config.git/private mv .gnupg .config.git/private mv .profile .config.git/ mv .config.git/common/.xinitrc .config.git/ |
Now we want to link all the configurations together using submodules. Git allows you to add one repository as a kind of dependency of another. This is called a submodule. You do this as follows:
1 2 3 |
cd .config.git git submodule add $HOME/.config.git/common git submodule add $HOME/.config.git/private |
Alternatively, if you want to push these to your server first:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
cd $HOME/.config.git/common git add * git commit -a -m "Init" ssh user@myserver.com git init --bare ~/repos/config.common git remote add origin myserver.com:~/repos/config.common git push origin master cd $HOME/.config.git/private git add * git commit -a -m "init" ssh user@myserver.com git init --bare ~/repos/config.private git remote add origin myserver.com:~/repos/config.private git push origin master cd $HOME/.config.git/ git add .profile git add .xinitrc git submodule add user@myserver.com:~/repos/config.common git submodule add user@myserver.com:~/repos/config.private git commit -a -m "init" ssh user@myserver.com git init --bare ~/repos/config.machine-name git remote add origin myserver.com:~/repos/config.machine-name git push origin master |
Now, you need to link everything back into your home so you can actually use your version controlled configs. I use a script to do this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#/bin/bash # A script for creating symlinks to all the dot files stored in the # config.git repo. CONFIG_PATHS=${CONFIG_PATHS:-"~/.config.git/common/ ~/.config.git/private ~/.config.git/"} EXCLUDE=${EXCLUDE:-"$1 bin/lndot.sh common/? private/? .config.git/? .git"} # Make sure to exclude ., .., and any other files listed in $EXCLUDE FIND_CMD="find $CONFIG_PATHS -maxdepth 1 -iname \"*\" " for file in $EXCLUDE do FIND_CMD=$FIND_CMD"| egrep -v \"$file\$\" " done echo $FIND_CMD # Ensure we're in home, to make proper symlinks pushd ~/ >/dev/null for i in $(eval $FIND_CMD) do ln -f -s $i ~/ done popd >/dev/null |
Now, you have your configuration files version controlled, linked properly, and easily shareable! To add a new machine to this setup, all you need to do is:
1 2 3 4 5 6 7 8 9 10 |
git init .config.git
cd .config.git
git submodule add user@server.com:~/repos/config.common
git submodule add user@server.com:~/repos/config.private
ssh user@myserver.com git init --bare ~/repos/config.machine-name2
mv ~/.xinitrc .
mv ~/.profile .
git add .xinitrc
git add .profile
... etc
|
One important thing to note: whenever you change a file from a submodule, you should perform a commit/push of the parent module. Otherwise, when cloning the parent module, it will pull an older revision of the submodule.
The final piece of this setup, for me, was learning how to use bash configuration files so I could have both common and machine specific files coexist, and have settings that exist for all shells, or only interactive/login shells. I might make another post about this later.