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