Skip to content

Commit 49f6bff

Browse files
committed
Import Unix & Linux SE blog post
Fixes #136
1 parent 2e16fb5 commit 49f6bff

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
---
2+
title: "Getting started with version-controlled configurations"
3+
time:
4+
epoch: 1397584800
5+
utcoffset: "UTC-7"
6+
author: "AJ Jordan"
7+
categories:
8+
- development
9+
- tips
10+
- tutorials
11+
canonical: https://web.archive.org/web/20150911232841/http://unix.blogoverflow.com/2014/04/getting-started-with-version-controlled-configurations/
12+
---
13+
14+
Hey everyone, welcome to the inaugural [Unix & Linux](https://unix.stackexchange.com/) community blog post. Let’s get started.
15+
16+
# Introduction
17+
18+
If you’re like me, you work on many different kinds of computers. I have two [Darwin](https://en.wikipedia.org/wiki/Darwin_(operating_system)) machines that I regularly work on; I have about four different installs of [Arch GNU/Linux](https://archlinux.org/), and I am planning to add even more esoteric distributions to one of my boxes. I work in Cygwin. And I have a Debian Sid box, which needs to be converted to something else.
19+
20+
My point is not that I like distribution-hopping. My point is that many of us use very diverse environments, and even if we don’t use very diverse environments, we all have a _lot_ of environments that we work in. I’m also guessing that most of us here have at least some basic configurations accumulated, and many of us have extremely tricked-out shells. Wouldn’t it be nice if there was a coherent way to manage all of your configurations?
21+
22+
Enter version control. Not only can you use version control to synchronize your configurations between computers, but you’ll also inherit all the other benefits of (hosted) version control:
23+
24+
* A nice history of everything you’ve ever done to your configurations – and if you write good, proper commit messages, a nice history of why you made those changes!
25+
* The ability to link to your configuration when you’re [asking for help](https://unix.stackexchange.com/questions/ask), so that people can see the overall context of the snippets that you post
26+
* Nice ways to track subprojects (e.g. frameworks like [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh))
27+
* Show off your stuff way more easily
28+
29+
In this post, I’ll show you how to recreate the [exact setup](https://github.com/strugee/dots) that I use to control my configurations. I prefer to use git, but you should be able to adapt most (if not all) of this guide to your preferred VCS. The only reason you might run into trouble is if your VCS has no equivalent of git submodules.
30+
31+
# The initial import
32+
33+
First, create your repository online. The details will, of course, vary depending on what VCS host you use. Personally, I use GitHub, but again, anything will work.
34+
35+
Next, we need to import all our stuff to the repository. First create a local clone.
36+
37+
git clone [email protected]:strugee/dots.git
38+
39+
If you don’t like whatever name you chose for the repository, you should rename it now, before you do anything else.
40+
41+
mv dots configs
42+
43+
Now, copy all the configs that you like into the repository.
44+
45+
cp .z* configs/ # copies all the zsh stuff
46+
47+
Take care to ensure that you create the directory structure properly and safely. For example, the following is a terrible idea:
48+
49+
cp -r .gnupg configs/
50+
51+
If you do this, you may accidentally commit `.gnupg/secring.gpg` into git! This is obviously something that you don’t want to do. Instead, do this:
52+
53+
mkdir configs/.gnupg
54+
cp .gnupg/gpg.conf configs/.gnupg/
55+
56+
Another thing that you should definitely watch out for is the `.ssh` directory, but you may have other tools that store secret data next to config files. Just be smart.
57+
58+
That’s it! We’re done importing. Now let’s commit.
59+
60+
cd configs
61+
git status # double-check what you're commiting
62+
git commit -m "Initial commit"
63+
git push
64+
65+
We’re done. Your configuration is live on the internet. There’s just one problem…
66+
67+
# Hooking up your configurations
68+
69+
…and that is that all of your _real_ configurations are separate from your version controlled configurations! If you make changes in one, it won’t do anything to the other.
70+
71+
When I was originally setting all this up for myself, I put my configurations straight into `~`. This is a horrible idea for two reasons:
72+
73+
* Every directory that’s a child of your home, indirect or direct, will be considered a part of a git repository, because a parent of that directory (said parent being `~`) has a `.git` directory.
74+
* You either risk accidentally introducing tons of crap from your home directory into your repository, or you have to maintain a [large and ugly `.gitignore`](https://github.com/strugee/dots/blob/e8d7a133bd852794d8147fdeeab9651145f79409/.gitignore).
75+
76+
The solution that I now use is simply symlinking all my configurations into `~` (or wherever). If you find that this approach incurs too much overhead, you may want to look into a framework to do this for you, as I mention in the “taking it further” section. That being said, I’d encourage you to try simply symlinking, at least at first. It’s surprisingly robust.
77+
78+
Anyway, creating your symlinks is dead-simple. Watch out for things that fail (you’ll want to remember them; if you’re feeling especially forgetful, redirect `stderr` to a file or something).
79+
80+
cd ~
81+
ln -s configs/.* configs/* .
82+
83+
This will symlink _everything_ that’s in `configs/` into your home directory. This is probably not exactly what you want, so let’s do some cleanup:
84+
85+
# pwd is still ~
86+
rm .git # if you don't remove this, git will think that ~ is a repository!
87+
rm COPYING # license information that doesn't need to be in your home directory
88+
89+
Notice that we haven’t removed `.ssh` and `.gnupg`. Why? These (probably) didn’t get symlinked when you ran `ln` because they’re (probably) already there. You’ll have to fix these manually, along with anything else that failed when you ran `ln`.
90+
91+
ln -s configs/.gnupg/gpg.conf .gnupg/
92+
ln -s configs/.ssh/config .ssh/
93+
# you'll have a fair amount of stuff in .config; anything that respects XDG_CONFIG_HOME puts stuff there
94+
ln -s configs/.config/awesome/ .config/awesome
95+
96+
All done! You’re now managing your configurations with git.
97+
98+
# Adding a framework
99+
100+
If you’re like me, you use a framework, like the excellent [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh), or something like [liquidprompt](https://github.com/nojhan/liquidprompt), or whatever other whizzbang what-have-you project you have a preference for. What you’ve probably done right now is simply copied the directory of your framework straight into your repository. This means that whenever your framework updates, you have to commit all the new stuff into your repo. Not only that, but when you clone to a new computer, you have to do some black magic to restore the “repository state” on the new computer, because git automatically ignores any `.git` directory that isn’t a direct child of the root of your current repository. (It all gets very confusing to talk about at this point.)
101+
102+
The solution is to use git submodules. If you’ve never used git submodules before, I’d encourage you to read up on them, either by invoking `man git-submodule` or by reading [the relevant page of Pro Git](https://git-scm.com/book/en/v2/Git-Tools-Submodules). I won’t go into details here, since it would just be duplicating information, but the tl;dr is that git submodules let you embed another git repository into your main repository, but in the Right Way(tm).
103+
104+
Let’s take my old `.oh-my-zsh` setup and fix it to use git submodules.
105+
106+
First, we simply get rid of the old stuff.
107+
108+
# pwd is ~
109+
cd configs/
110+
rm -r .oh-my-zsh
111+
112+
Then we add it back as a git submodule:
113+
114+
git submodule add git://github.com/robbyrussell/oh-my-zsh.git .oh-my-zsh
115+
116+
And then we commit the result into the repository:
117+
118+
git add .gitmodules .oh-my-zsh
119+
git commit
120+
121+
And you’re done! Just push.
122+
123+
Oh your other computers, you’ll have to initialize the submodule after you pull. This is also super easy. Just run:
124+
125+
git submodule init # only needs to be run the first time
126+
git submodule update
127+
128+
# Taking it further
129+
130+
There are a number of things that you can do (one of which you _should_ do) to take your version-controlled configurations to the next level.
131+
132+
## License your stuff (this is the thing that you _should_ do)
133+
134+
Your configurations are now public and usable by other people. That means that you should add a license, otherwise people aren’t legally allowed ot reuse your stuff. At risk of starting a flame war, I’ll state that my personal preference for small projects like this is the [WTFPL](http://www.wtfpl.net/).
135+
136+
_Please, **please**_ do this. The public thanks you.
137+
138+
## Getting something to manage it for you
139+
140+
There’s a bunch of stuff in our new setup that you need to run manually. You need to pull. If there are new files, you need to link them. If there are submodule updates, you need to run `git submodule update`. Wouldn’t it be nice if something could do all this for you?
141+
142+
There are a bunch of solutions to this problem. Some people write makefiles. Some people write shell scripts. Some people use a real framework. It’s all up to you.
143+
144+
Personally, I used this problem as an excuse to learn to use `make`. With the [Makefile](https://github.com/strugee/dots/blob/cd3d2c5b3f54538d87478f2ed56a5bf6ad53fe62/Makefile) that I’m in the process of writing, I can pull, update my submodules, and reinstall all my symlinks, all with a simple invocation of
145+
146+
cd configs/
147+
make
148+
149+
However, like I said, it’s all up to you. If you prefer to use a framework, you should check out [Zach Holman’s dotfiles](https://github.com/holman/dotfiles) (he has a `Rakefile` that helps you manage this stuff), [Homesick](https://github.com/technicalpickles/homesick) (which is an even more organized framework), [Ben Alman’s dotfiles](https://github.com/cowboy/dotfiles) (which has a more casual, loose organization), [Eduardo Lundgren’s dotfiles](https://github.com/eduardolundgren/dotfiles) (which has a Grunt-powered configuration tool), [ghar](https://github.com/philips/ghar), and [vcsh](https://github.com/RichiH/vcsh) (this may be especially interesting if you just _hate_ the fact that you have to have a separate directory for your config repo). [fresh](https://github.com/freshshell/fresh) is also pretty neat – it’s like a package manager for dotfiles.
150+
151+
While I haven’t used any of these myself, they’re all excellent projects.
152+
153+
## Further reading
154+
155+
[dotfiles.github.io](https://dotfiles.github.io/) is an excellent resource for all this stuff (and, in fact, it’s where I pulled the above list of frameworks from). You may also be interested in a [list of all dotfiles repositories on GitHub](https://github.com/search?q=dots+OR+dotfiles&type=Repositories&ref=advsearch&l=), sorted by popularity. [dotfiles.org](https://web.archive.org/web/20150601022443/http://www.dotfiles.org/) is also a place where people share dotfiles, albeit in a much less organized fashion. I’ve never used it myself, but I’d encourage you to try it out.
156+
157+
# Conclusion
158+
159+
git is awesome. Configurations are awesome. Sketchy `rsync` scripts aren’t the best when you could have organization (and history!) instead.
160+
161+
Good luck and have fun! Let me know in the comments if you run into problems, find new resources, or have anything else to say. (Flames to `/dev/null`, but constructive criticism welcomed.)
162+
163+
Thanks to [@terdon](https://unix.stackexchange.com/users/22222/terdon) for editing this post prior to publication.

0 commit comments

Comments
 (0)