mirror of
https://github.com/danielepintore/dotfiles.git
synced 2026-06-15 20:25:13 +02:00
178 lines
7.4 KiB
Markdown
178 lines
7.4 KiB
Markdown
# Dotfiles: Best way to store in a bare git repository
|
|
|
|
_Disclaimer: the title is slightly hyperbolic, there are other proven solutions to the problem. I do think the technique below is very elegant though._
|
|
|
|
Recently I read about this amazing technique in an [Hacker News thread](https://news.ycombinator.com/item?id=11070797) on people's solutions to store their [dotfiles](https://en.wikipedia.org/wiki/Dot-file). User `StreakyCobra` [showed his elegant setup](https://news.ycombinator.com/item?id=11071754) and ... It made so much sense! I am in the process of switching my own system to the same technique. The only pre-requisite is to install [Git](https://www.atlassian.com/git).
|
|
|
|
In his words the technique below requires:
|
|
|
|
No extra tooling, no symlinks, files are tracked on a version control system, you can use different branches for different computers, you can replicate you configuration easily on new installation.
|
|
|
|
The technique consists in storing a [Git bare repository](http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/) in a "_side_" folder (like `$HOME/.cfg` or `$HOME/.myconfig`) using a specially crafted alias so that commands are run against that repository and not the usual `.git` local folder, which would interfere with any other Git repositories around.
|
|
|
|
----------
|
|
|
|
## Starting from scratch
|
|
|
|
----------
|
|
|
|
If you haven't been tracking your configurations in a Git repository before, you can start using this technique easily with these lines:
|
|
|
|
```bash
|
|
git init --bare $HOME/.cfg
|
|
alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'
|
|
config config --local status.showUntrackedFiles no
|
|
echo "alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'" >> $HOME/.bashrc
|
|
```
|
|
|
|
- The first line creates a folder `~/.cfg` which is a [Git bare repository](http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/) that will track our files.
|
|
- Then we create an alias `config` which we will use instead of the regular `git` when we want to interact with our configuration repository.
|
|
- We set a flag - local to the repository - to hide files we are not explicitly tracking yet. This is so that when you type `config status` and other commands later, files you are not interested in tracking will not show up as `untracked`.
|
|
- Also you can add the alias definition by hand to your `.bashrc` or use the the fourth line provided for convenience.
|
|
|
|
I packaged the above lines into a [snippet](https://bitbucket.org/snippets/nicolapaolucci/ergX9) up on Bitbucket and linked it from a short-url. So that you can set things up with:
|
|
|
|
```bash
|
|
curl -Lks http://bit.do/cfg-init | /bin/bash
|
|
```
|
|
|
|
After you've executed the setup any file within the `$HOME` folder can be versioned with normal commands, replacing `git` with your newly created `config` alias, like:
|
|
|
|
```bash
|
|
config status
|
|
config add .vimrc
|
|
config commit -m "Add vimrc"
|
|
config add .bashrc
|
|
config commit -m "Add bashrc"
|
|
config push
|
|
```
|
|
|
|
## Merge or Rebase?
|
|
|
|
If you have more than one pc and you want to store their dotfile you can have a main repo for the common configs and then a machine specific repo. When you make some changes in the main repo you have to do a merge or a rebase to main.
|
|
I suggest you to do a merge because is a not destructive opertion, but there is a disadvantage: you'll have a extra commit (the merge one). If you prefer to do a rebase you instead won't get a merge commit but you have to do a full rewrite of the commits, this can cause some problem if you like to change your machine config from another pc and then do a git pull because after you do a rebase the history is totally different, so you have do another git clone or something else to pull that changes (rebase).
|
|
|
|
### Performing a merge after changes in the main repo
|
|
|
|
After you've made some changes in the main repo the machine specific repositories need to be merged with main:
|
|
```bash
|
|
config checkout machine-repo
|
|
config merge main
|
|
config push origin machine-repo
|
|
```
|
|
Now you have merged the changes. (In the process you may have to resolve conflicts)
|
|
|
|
### Performing a rebase after changes in the main repo
|
|
|
|
After you've made some changes in the main repo the machine specific repositories need to be rebased on top of main:
|
|
|
|
```bash
|
|
config checkout machine-repo
|
|
config rebase main
|
|
config log --all # check if everything is ok because we need a force push after
|
|
config push -f origin machine-repo
|
|
```
|
|
|
|
## Installing your dotfiles onto a new system (or migrate to this setup)
|
|
|
|
----------
|
|
|
|
If you already store your configuration/dotfiles in a [Git repository](https://www.atlassian.com/git), on a new system you can migrate to this setup with the following steps:
|
|
|
|
- Prior to the installation make sure you have committed the alias to your `.bashrc` or `.zsh`:
|
|
|
|
```bash
|
|
alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'
|
|
```
|
|
|
|
- And that your source repository ignores the folder where you'll clone it, so that you don't create weird recursion problems:
|
|
|
|
```bash
|
|
echo ".cfg" >> .gitignore
|
|
```
|
|
|
|
- Now clone your dotfiles into a [bare](http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/) repository in a "_dot_" folder of your `$HOME`:
|
|
|
|
```bash
|
|
git clone --bare <git-repo-url> $HOME/.cfg
|
|
```
|
|
|
|
- Define the alias in the current shell scope:
|
|
|
|
```bash
|
|
alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'
|
|
```
|
|
|
|
- Checkout the actual content from the bare repository to your `$HOME`:
|
|
|
|
```undefined
|
|
config checkout
|
|
```
|
|
|
|
- The step above might fail with a message like:
|
|
|
|
```js
|
|
error: The following untracked working tree files would be overwritten by checkout:
|
|
.bashrc
|
|
.gitignore
|
|
Please move or remove them before you can switch branches.
|
|
Aborting
|
|
```
|
|
|
|
This is because your `$HOME` folder might already have some stock configuration files which would be overwritten by Git. The solution is simple: back up the files if you care about them, remove them if you don't care. I provide you with a possible rough shortcut to move all the offending files automatically to a backup folder:
|
|
|
|
```bash
|
|
mkdir -p .config-backup && \
|
|
config checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \
|
|
xargs -I{} mv {} .config-backup/{}
|
|
```
|
|
|
|
- Re-run the check out if you had problems:
|
|
|
|
```undefined
|
|
config checkout
|
|
```
|
|
|
|
- Set the flag `showUntrackedFiles` to `no` on this specific (local) repository:
|
|
|
|
```bash
|
|
config config --local status.showUntrackedFiles no
|
|
```
|
|
|
|
- You're done, from now on you can now type `config` commands to add and update your dotfiles:
|
|
|
|
```bash
|
|
config status
|
|
config add .vimrc
|
|
config commit -m "Add vimrc"
|
|
config add .bashrc
|
|
config commit -m "Add bashrc"
|
|
config push
|
|
```
|
|
|
|
Again as a shortcut not to have to remember all these steps on any new machine you want to setup, you can create a simple script, [store it as Bitbucket snippet](https://bitbucket.org/snippets/nicolapaolucci/7rE9K) like I did, [create a short url](http://bit.do/) for it and call it like this:
|
|
|
|
```bash
|
|
curl -Lks http://bit.do/cfg-install | /bin/bash
|
|
```
|
|
|
|
For completeness this is what I ended up with (tested on many freshly minted [Alpine Linux](http://www.alpinelinux.org/) containers to test it out):
|
|
|
|
```bash
|
|
git clone --bare https://bitbucket.org/durdn/cfg.git $HOME/.cfg
|
|
function config {
|
|
/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME $@
|
|
}
|
|
mkdir -p .config-backup
|
|
config checkout
|
|
if [ $? = 0 ]; then
|
|
echo "Checked out config.";
|
|
else
|
|
echo "Backing up pre-existing dot files.";
|
|
config checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | xargs -I{} mv {} .config-backup/{}
|
|
fi;
|
|
config checkout
|
|
config config status.showUntrackedFiles no
|
|
```
|
|
|