Ever wanted to manage all those ~/.conf
files with Git? Probably not but if you know anything about Git, the advantages are obvious. Is it even possible though you may ask!?! To do so would mean separating the working tree from the actual git repository. Fortunately Git allows for just that.
By default, when you create a non-bare repository, you end up with the actual repository, a .git
directory being created in the directory you want to track. The directory you want to track is actually called the working tree. The repository itself is a load of files (objects really) that maps and tracks the state of a working tree. That’s what a non-bare repository is in fact – a git repository with a checked-out working tree included. Fortunately the working tree and the git repository do not actually need to be in the same location. You can set these with the git variables, $GIT_DIR
for the repository location and $GIT_WORK_TREE
for the working tree.
Best of all however is that you don’t even need to get your hands dirty with this kind of thing as a nice chap called Richard Hartmann has taken all the potential pain out of it with vcsh! All you need is a basic/working knowledge of Git.
Contents
The Plan
In this example I want to track configuration changes to two applications, the i3 Window Manager and Bash. I’ll walk you through how to use vcsh
for this, and then demonstrate how a program called mr
, available with the myrepos
package, can make your life even simpler.
You’ll need to setup a separate repository for each application configuration you want to track. Here I have setup one for i3wm
and bash
.
https://github.com/crazzyfool/config-i3.git
https://github.com/crazzyfool/config-bash.git
Later you’ll also need one for mr
.
https://github.com/crazzyfool/config-mr.git
vcsh
Using vcsh
allows one to have multiple working trees in the same directory by storing the actual repository data in a separate location.
Installation
I run Manjaro so to install its:
$ yaourt -Sy vcsh
Add an Application Configuration
So I want to use vcsh
to manage the configuration changes to the i3 Windows Manager, located ~/.i3/config
.
vcsh init config-i3 vcsh config-i3 add ~/.i3/ vcsh config-i3 commit -m "My initial i3 config" vcsh config-i3 remote add origin https://github.com/crazzyfool/config-i3.git vcsh config-i3 push -u origin master
You may also want to create a gitignore file too.
vcsh write-gitignore config-i3
See below for more about that.
Add a Second Application Configuration
vcsh init config-bash vcsh config-bash add ~/.bashrc vcsh config-bash commit -m "My initial bash config" vcsh config-bash remote add origin https://github.com/crazzyfool/config-bash.git vcsh config-bash push -u origin master
Maybe you want to add a second file to the bash
configuration.
vcsh config-bash add ~/.bash_profile vcsh config-bash commit -m "Added .bash_profile" vcsh config-bash push
What Just Happened?
All the actual local repositories are stored in ~/.config/vcsh/repo.d
while the working trees are located in the ~/
directory.
/home/andy/.config/vcsh/ └── repo.d ├── config-bash.git └── config-i3.git
Using vcsh to Manage your Configuration
You can get a full list of options from the help
menu.
$ vcsh help usage: vcsh<options> <command> options: -c <file> Source file -d Enable debug mode -v Enable verbose mode commands: clone [-b <branch>] \ <remote> \ [<repo>] Clone from an existing repository commit Commit in all repositories delete <repo> Delete an existing repository enter <repo> Enter repository; spawn new instance of $SHELL foreach [<-g>] <git command> Execute a command for every repository help Display this help text init <repo> Initialize a new repository list List all repositories list-tracked \ [<repo>] List all files tracked all or one repositories list-untracked \ [<-a>] [<-r>] [<repo>] List all files not tracked by all or one repositories pull Pull from all vcsh remotes push Push to vcsh remotes rename <repo> \ <newname> Rename repository run <repo> \ <command> Use this repository status \ [--terse] [<repo>] Show statuses of all/one vcsh repositories upgrade <repo> Upgrade repository to currently recommended settings version Print version information which <substring> Find substring in name of any tracked file write-gitignore \ <repo> Write .gitignore.d/<repo> via git ls-files <repo> <git command> Shortcut to run git commands directly <repo> Shortcut to enter repository
Using vcsh to List
You can list all repositories with vcsh list
.
$ vcsh list config-bash config-i3
To list all the currently tracked files.
$ vcsh list-tracked /home/andy/.bash_profile /home/andy/.bashrc /home/andy/.i3/config
If you just want to see what files one particular repository, such as config-bash
is tracking, you can use the following.
$ vcsh list-tracked config-bash /home/andy/.bash_profile /home/andy/.bashrc
Editing Configuration
Once you’ve edited a file, say .bashrc
, you will need to add and commit those changes. Running the below command will show you that file has been modified.
$ vcsh config-bash status On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .bashrc no changes added to commit (use "git add" and/or "git commit -a")
If you haven’t already created a .gitignore
file, your output might look more verbose.
[andy@home-pc ~]$ vcsh config-bash status On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .bashrc Untracked files: (use "git add <file>..." to include in what will be committed) .Xauthority .Xclients .Xresources .bash_history .bash_logout .cache/ .config/ .dir_colors .dmenurc .dmrc .gimp-2.8/ .gitconfig .gksu.lock .gtkrc-2.0 .i3/ .icons/ .local/ .moc/ .moonchild productions/ .profile .screenlayout/ .ssh/ .viminfo .xinitrc .xsession-errors .xsession-errors.old Projects/ configure.sh test-file.txt no changes added to commit (use "git add" and/or "git commit -a")
If this is the case, you can get vcsh
to create one for you.
$ vcsh write-gitignore config-bash
Now the ~/.gitignore.d/config-bash
file will exist with the following content:
$ cat ~/.gitignore.d/config-bash * !/.bash_profile !/.bashrc
To add that change commit.
$ vcsh config-bash add .bashrc $ vcsh config-bash commit -m "Added ll alias to .bashrc" $ vcsh config-bash push
Status
You can set the status of a repository with.
$ vcsh config-bash status
Or the status of all repositories with.
$ vcsh status
Pull Changes
To pull changes from Github.
$ vcsh pull
…or for just one repository.
$ vcsh config-i3 pull
Push Changes
To push your changes back up to Github.
$ vcsh push
Or for a given repository.
$ vcsh config-i3 push
Running Git Commands
You can also just run normal Git command appended onto vcsh repo-name
. For example, git log
.
$ vcsh config-bash log commit bd775543cbaeca89c20b5dad421f15b1cb02da45 (HEAD -> master, origin/master) Author: Andrew Pike <[email protected]> Date: Sat Apr 28 20:35:44 2018 +0100 Added ll alias to .bashrc commit 5c9f459ed14de5e677e02f9eff7d3c749ddb07c8 Author: Andrew Pike <[email protected]> Date: Sat Apr 28 20:09:29 2018 +0100 Added .bash_profile commit 08acbe7e6d7b483e9dc0a4b748dada50f195cc09 Author: Andrew Pike <[email protected]> Date: Sat Apr 28 19:22:36 2018 +0100 My initial bash config
Or git diff
.
$ vcsh config-bash diff diff --git a/.bashrc b/.bashrc index 7b8ab85..e8252f1 100644 --- a/.bashrc +++ b/.bashrc @@ -96,6 +96,7 @@ alias free='free -m' # show sizes in MB alias np='nano -w PKGBUILD' alias more=less alias ll='ls -la' +alias ls='ls -l' xhost +local:root > /dev/null 2>&1
Limitations
vcsh
works great but what happens when you want to migrate to or pull in the configuration to another machine? Enter mr
and myrepos
.
myrepos
A command called mr
, included in the myrepos
package is used to simultaneously managed repositories. You can also use it to quickly enable or disable any repositories too. As mr
knows about all the repositories you are interested in, you can save your mr
configuration to Git and then proceed to pull in all your other configurations from their repositories in one go.
Installation
On Manjaro this would be:
$ yaourt -Sy myrepos
Some useful dependencies to consider when installing myrepos. Note you can use myrepos to manage repositories using many different revision control systems including Subversion and CVS!
Optional dependencies for myrepos bzr: support for bzr repositories cvs: support for cvs repositories darcs: support for darcs repositories git-annex: support for git-annex clones gitk: support for visualizing git repository history git: support for git repositories [installed] mercurial: support for mercurial repositories perl-html-parser: support for webcheckout perl-libwww: support for webcheckout perl-uri: support for webcheckout heuristically guessing partial URLs [installed] repo: support for repo repositories svn: support for subversion repositories [installed] unison: support for unison as a vcs vcsh: support for vcsh
Configure Mr
You need to create the file structure yourself. I’m using the recommended layout.
[andy@home-pc ~]$ mkdir -pv .config/mr/{available.d,config.d} mkdir: created directory '.config/mr' mkdir: created directory '.config/mr/available.d' mkdir: created directory '.config/mr/config.d
And create the configuration file.
$ vim ~/.mrconfig
The content should look like the below.
[DEFAULT] git_gc = git gc "$@" jobs = 5 include = cat ~/.config/mr/config.d/*
Add Repositories to mr
Now we need to add our repositories to mr
. To add i3
, create a config file in the available.d
directory>
$ vim ~/.config/mr/available.d/i3.vcsh
Create a configuration file like so.
[$HOME/.config/vcsh/repo.d/config-i3.git] checkout = vcsh clone https://github.com/crazzyfool/config-i3.git config-i3 update = vcsh config-i3 pull push = vcsh config-i3 push status = vcsh config-i3 status gc = vcsh config-i3 gc
The first line is the path to the Git directory. Now lets add one for bash
.
$ vim ~/.config/mr/available.d/bash.vcsh
And this one looks very similar.
[$HOME/.config/vcsh/repo.d/config-bash.git] checkout = vcsh clone https://github.com/crazzyfool/config-bash.git config-bash update = vcsh config-bash pull push = vcsh config-bash push status = vcsh config-bash status gc = vcsh config-bash gc
These repositories are now available to us but they are not enabled yet. To do so we need to create a symlink.
[andy@home-pc ~]$ cd ~/.config/mr/config.d/ [andy@home-pc config.d]$ ls -l total 0 [andy@home-pc config.d]$ ln -s ../available.d/i3.vcsh . && ln -s ../available.d/bash.vcsh . [andy@home-pc config.d]$ [andy@home-pc config.d]$ ls -l total 0 lrwxrwxrwx 1 andy andy 24 Apr 29 18:58 bash.vcsh -> ../available.d/bash.vcsh lrwxrwxrwx 1 andy andy 22 Apr 29 18:58 i3.vcsh -> ../available.d/i3.vcsh
Add a non-vcsh Repository
Now you can use vcsh to update and manage other repositories you use. For example, to configure Vim, I use The Ultimate Vim configuration.
To update you need to do a rebase:
cd ~/.vim_runtime git pull --rebase
Lets try to accomplish this using mr…
$ cp -v ~/.config/mr/available.d/{bash,vim}.vcsh $ vim ~/.config/mr/available.d/vim.vcsh
My one looks like the following.
[.vim_runtime] checkout = git clone --depth=1 https://github.com/amix/vimrc.git --separate-git-dir ~/.config/vcsh/repo.d/config-vim.git ~/.vim_runtime sh ~/.vim_runtime/install_awesome_vimrc.sh update = cd ~/.vim_runtime git pull --rebase
Don’t forget to enable it!
[andy@home-pc ~]$ cd ~/.config/mr/config.d/ [andy@home-pc config.d]$ ln -s ../available.d/vim.vcsh . [andy@home-pc config.d]$ ls -la vim.vcsh lrwxrwxrwx 1 andy andy 23 Apr 29 22:54 vim.vcsh -> ../available.d/vim.vcsh
Now when you do a mr update
for the first time, mr
should automatically checkout and install the Ultimate Vim configuration.
$ mr update mr update: /home/andy/.config/vcsh/repo.d/config-i3.git Already up to date. mr update: /home/andy/.config/vcsh/repo.d/config-bash.git Already up to date. mr checkout: /home/andy/.config/vcsh/repo.d/config-vim.git Cloning into '/home/andy/.vim_runtime'... Installed the Ultimate Vim configuration successfully! Enjoy :-) mr update: finished (3 ok)
If already checked-out and installed, it should check for updates and do a rebase if any are found.
[andy@home-pc ~]$ mr update mr update: /home/andy/.config/vcsh/repo.d/config-i3.git Already up to date. mr update: /home/andy/.config/vcsh/repo.d/config-bash.git Already up to date. mr update: /home/andy/.config/vcsh/repo.d/config-vim.git Already up to date. Current branch master is up to date. mr update: finished (3 ok)
Add any other Repositories
You can use mr
to manage any other repositories you administer.
$ vim ~/.config/mr/available.d/scripts.vcsh
My one looks like:
[Scripts] checkout = git clone https://github.com/crazzyfool/scripts.git ~/Scripts update = cd ~/Scripts git pull push = cd ~/Scripts git push status = cd ~/Scripts git status
Enable it.
$ cd ~/.config/mr/config.d/ $ ln -s ../available.d/scripts.vcsh . $ cd $ mr update
Add Mr to Git
For reasons that will become clear in the next and final section, it is a good idea to add your mr
configuration to Github.
$ vcsh init config-mr $ vcsh config-mr add .config/mr ~/.mrconfig $ vcsh config-mr commit -m "Added initial mr commit" vcsh config-mr remote add origin https://github.com/crazzyfool/config-mr.git vcsh config-mr push -u origin master
Create mr
configuration.
$ vim ~/.config/mr/available.d/mr.vcsh
Such as.
[$HOME/.config/vcsh/repo.d/config-mr.git] checkout = vcsh clone https://github.com/crazzyfool/config-mr.git config-mr update = vcsh config-mr pull push = vcsh config-mr push status = vcsh config-mr status gc = vcsh config-mr gc
Enable it.
$ cd ~/.config/mr/config.d/ $ ln -s ../available.d/mr.vcsh . $ cd
You’ll also need to create a gitignores file. My one looks like this.
$ cat ~/.gitignore.d/config-mr * !/.gitignore.d !/.gitignore.d/config-mr !/.config !/.config/mr !/.config/mr/available.d !/.config/mr/available.d/* !/.config/mr/config.d !/.config/mr/config.d/* !/.mrconfig
Add those files to the repository.
vcsh config-mr add ~/.config/mr/available.d/mr.vcsh ~/.config/mr/config.d/mr.vcsh ~/.gitignore.d/config-mr vcsh config-mr commit -m "Added more files" $ vcsh config-mr push
Pull Configuration to a New Host
This is ultimately why the vcsh
/mr
combination is so useful. Assuming you have installed vcsh
and mr
, getting setup should just be a simple case of.
$ vcsh clone https://github.com/crazzyfool/config-mr.git $ mr update
However, as I’m not actually on a new host, I need to delete a load of files first.
$ rm -Rvf ~/.config/vcsh/repo.d/config-* ~/.config/mr/ ~/.mrconfig ~/.gitignore.d/ ~/.vim_runtime/ ~/.vimrc ~/Scripts/ ~/.bashrc ~/.bash_profile ~/.i3/config
The end result should be that all five repositories are pulled it.
$ vcsh clone https://github.com/crazzyfool/config-mr.git Initialized empty shared Git repository in /home/andy/.config/vcsh/repo.d/config-mr.git/ Switched to a new branch 'master' remote: Counting objects: 31, done. remote: Compressing objects: 100% (18/18), done. remote: Total 31 (delta 4), reused 31 (delta 4), pack-reused 0 Unpacking objects: 100% (31/31), done. From https://github.com/crazzyfool/config-mr * branch master -> FETCH_HEAD * [new branch] master -> origin/master [andy@home-pc ~]$ [andy@home-pc ~]$ vcsh list config-mr [andy@home-pc ~]$ mr update mr update: /home/andy/.config/vcsh/repo.d/config-mr.git Already up to date. mr checkout: /home/andy/Scripts Cloning into '/home/andy/Scripts'... mr checkout: /home/andy/.config/vcsh/repo.d/config-bash.git Initialized empty shared Git repository in /home/andy/.config/vcsh/repo.d/config-bash.git/ Switched to a new branch 'master' From https://github.com/crazzyfool/config-bash * branch master -> FETCH_HEAD * [new branch] master -> origin/master mr checkout: /home/andy/.config/vcsh/repo.d/config-i3.git Initialized empty shared Git repository in /home/andy/.config/vcsh/repo.d/config-i3.git/ Switched to a new branch 'master' From https://github.com/crazzyfool/config-i3 * branch master -> FETCH_HEAD * [new branch] master -> origin/master mr checkout: /home/andy/.vim_runtime Cloning into '/home/andy/.vim_runtime'... Installed the Ultimate Vim configuration successfully! Enjoy :-) mr update: finished (5 ok)
Conclusion
As demonstrated, the combination of both vcsh
and myrepos
not only gives you a powerful way to manage and track the .conf
files in your $HOME
directory but also a very convenient way of managing all repositories you may use. It also means that reinstalling your OS or working on a new machine is not so much of a pain. 🙂
Be the first to comment