I commonly work on multiple computers. I have various configuration files, eg, .bashrc, .gitconfig, .irbrc, .vimrc and configuration folders, eg, .vim/ that contain valuable customizations.
Sometimes I want small variations in configuration between the different computers.
I want to use version control to manage these different files.
do others use version control to manage their configuration files?
what are some hints that might make this easier?
what's the most elegant way of dealing with variations between the computers?
I'm comfortable with git; any other suggestions?
I keep a folder at ~/config/ which is a bzr repository. I push/pull the repository between my various computers to sync it up. I have an install script which I use to make symlinks to my home directory:
#! /bin/sh
# link all files to the home directory, asking about overwrites
cd `dirname $0`
SCRIPT_DIR=`pwd`
SCRIPT_NAME=`basename $0`
FILES=`bzr ls --versioned --non-recursive`
cd $HOME
for FILE in $FILES; do
ln --symbolic --interactive $SCRIPT_DIR/$FILE
done
rm $TARGET_DIR/$SCRIPT_NAME
If you want to use git instead of bzr, you can instead use:
FILES=`git ls-tree --name-only HEAD`
(I had to ask SO to figure that out)
EDIT: I don't actually do this anymore, now I have a dotfiles repo on github, with a nice rake install script that someone else wrote.
At the moment, I use a cloned git repo. To keep things simple, the only file that needs to vary between the different machines is .bashrc. It's nice if there can be just one version of this file that responds differently on different machines. Thus, in my .bashrc:
if [ $(hostname) == 'host1' ]; then
# things to do differently on host1.
elif [ $(hostname) == 'host2' ]; then
# things to do differently on host2.
fi
This obviously has some limitations (such as that a different technique would be required for .vimrc or other config files needing customization), but it works fairly well.
If you use git, you could define an "origin" repo to be the master; and then do a clone on each computer you work. you could use a branch for every computer to have your set of config files.
With CfEngine you can manage config files across machines and do also many more things!
The learning curve is maybe a bit high but worth it if you have to manage/update/maintain a pool of computers running linux regularly.
Easy. Use DropBox for that:
http://www.nixtutor.com/linux/sync-config-files-across-multiple-computers-with-dropbox/
I use slack for a similar situation. slack allows definition of roles/subroles so you can manage files with small variation either through a cloned file or patch. The slack directory is then managed by git in my deployment.
Here are some dotfile managers:
homesick: Based on Ruby
homeshick: Same as first one, but without ruby dependency
dfm: Written in Perl
git with branches for custom computers, with automated sync at login seems like a good solutions to me.
I've used etckeeper for versioning configurations, but I've never actually expanded to user configurations.
This kind of question comes up occasionally, and I've never seen a tool to handle this common use case, so I wrote a script that uses git and symlinks to manage these files.
See http://github.com/bstpierre/dotfiles
It is not perfect. There is currently a bug related to handling directories, and there is no support yet for variations across computers.
Before using any tool of this nature, make sure you have good backups!
I think what you want could be similar to what I've been doing...
Make a directory in home called .host_configs/ . This is version controlled. Or in my case it lives in a special folder on a central computer, I scp it down on any new machine. Inside it make a folder for every host that you want different configurations for. The folder for each host should be named after the short hostname for that machine. So in your git repo you have:
.host_configs/
homecomp1/
girlfriendcomp1/
workcomp1/
workcomp2/
In each host specific folder, put the .vimrc, .irbrc, etc., configuration files for that specific box.
And also, in each host folder make a file called .[SHORT_HOST]_rc. For instance, if your machine is name "sane" have a file named .sane_rc ... This file will contain the lines that would normally be in .bashrc that are unique to that host. For instance, if it's a mac and it needs alias ls='ls -GF' instead of alias ls='ls --color=auto' which works for most nix machines for ls with colors, put that line in the .[SHORT_HOST]_rc for that machine, along with whatever special functions, declarations, etc, that would normally go into the .bashrc or .profile etc. (or .zshrc, .tschrc, as the case may be). So the version controlled ~/.host_configs/ folder looks like:
.host_configs/
homecomp1/
.homecomp1_rc #special shell configs for this hostname
.vimrc #you know the rest
.irbrc
.Xresources
girlfriendcomp1/
.girlfriendcomp1_rc
.vimrc
.bubblebathrc
workcomp1/
.workcomp1_rc
.bashrc
.vimrc
workcomp2/
.workcomp2_rc
.bashrc
.vimrc
I use all the same barebones $HOME/.bashrc (or ~/.tshrc etc) on all of my machines. I just take the basic one that comes with the distro in question and move all of the host-specific configuration into the .host-configs/[SHORT_HOST]/.[SHORT_HOST]_rc file.
Put this at the bottom (of $HOME/.bashrc):
export SHORT_HOST="sane"
for file in `find ~/.host_configs/$SHORT_HOST -name ".*"`
do
ln -s $file `basename $file`
done
source ~/`.$SHORT_HOST`_rc
(Finds all of the dot-files for the host and makes a symlink in home to the~/.host_configs/foo_host folder).
Your dot files are in their normal location but they are symlinked to version control. The above also sources all of the lines in your [$SHORT_HOST]_rc file into .bashrc
You can commit back to git from the ~/.host_configs/ folder whenever you have changes.
That's what it looks like in shell, which is probably all you need, but if you need other features, I would write something that uses the same principles (sourcing an external .rc file into .bashrc and symlinking all the config files to the structured version control folder) in something more versatile/less ugly than shell. So instead of the above in your .bashrc, there could be:
export SHORT_HOST="sane"
ruby ~/import_conf.rb $SHORT_HOST
...and write your import_conf.rb to do more complex conf management, like placing a specific configuration file in some directory besides home, or handling a config folder like .ssh/, .subversion/ etc. That's what I do, it's pretty elegant for me, but there may be better solutions. Dropbox with some creative symlinks is also an excellent idea, though you're relying on a third party, and you need to be in a graphical environment. Also note there are inconsistencies between what you can do with symlinks + dropbox in Linux and shortcuts + dropbox in Windows if you implement something that wants to play with Windows.
Now there is also vcsh
From the README:
vcsh - manage config files in $HOME via fake bare git repositories
[...]
vcsh allows you to have several git repositories, all maintaining their working trees in $HOME without clobbering each other. That, in turn, means you can have one repository per config set (zsh, vim, ssh, etc), picking and choosing which configs you want to use on which machine.
Works perfectly, but may be a bit daunting if you are not an experienced git user.
Most of these answer address sync, but not how to tailor the files for the specific device. filetailor is an open-source Python program for this exact issue. Based on a YAML configuration file, it can make small changes to the files using device-specific variables or using device-specific comments in the files. Then, use another program such as Syncthing or Git to transfer the files.
For example, the following line would be commented out on every device except the one with hostname device1.
alias MYHOME='/home/dev1home/' #{filetailor device1}
Disclaimer: I had this same issue and made filetailor to solve it.
Related
I want to have all my configuration files versioned using Git in a remote repository at Github. I'm using Debian 7 testing, and all my configuration files are under the /home/user_name/ directory.
I created the usual .gitignore with all the files that I want to ignore and the files and directories that I want to allow versioning. My problem begins when I go to Documents, for example, and I see in zsh that folder is under the same versioning as the home directory.
I understand that Git works that way, but I need to know if it's possible to avoid that.
One classic way to version configuration files is to create a subdirectory like ~/etc/ and let your ~/.something files be symbolic links to ~/etc/something. Then, you can version ~/etc/ normally.
You can manage to ignore everything but your configuration files, but you'll always have little glitches like: the day you run git clean -fdx in the wrong place, you delete all your data.
Write */ in your .gitignore to ignore directories. Make exceptions with !foodir. Consider prefixing with slashes (see documentation for details).
There is server running under CentOS with php-fpm and nginx on aboard. Two projects are hosted, one of them is primary, the second contains half of the primary project as symlinks and part corresponding to itself. Both projects are in git repos. The primary project works correct under Linux and Windows machines after cloning the repo. But the second project contains symlinks and it doesn't work properly.
I don't know what to do. It's important to save the symlinks, but how should we work with the second project on Windows? Some hooks with git (replace symlinks with files before pull)?
git converts symlinks to text files on Windows, since symlinks are available only on *nix environments, and msysgit doesn't take care of them by default.
You can create a post-commit hook to workaround them.
Check answers on git symlinks in windows, specifically this one where a user has given steps to handle the scenario.
You are looking for git submodules: http://git-scm.com/docs/git-submodule
I am attempting to create a git repository to store all of my dotfiles and config files. My idea was to simply create hard links to all of the files I cared about and store those links in their own directory that I could turn into a repository.
I've hit a bit of a snag though with my ~/.gitconfig file. It seems that whenever I run the 'git config' command the link that I created no longer points to the right location e.g. the file in the repository no longer updates properly.
Here is an example using the shell and interactive ruby to determine the files linked state.
# Create the link
$ ln .gitconfig .conf_files/gitconfig # Create the link
# The files are in fact linked
[1] pry(main)> File.identical?('.gitconfig', '.conf_files/gitconfig')
=> true
# Update the gitconfig file by running a 'git config' command
$ git config --global alias.last 'log -1 HEAD'
# The files are no longer linked.
[2] pry(main)> File.identical?('.gitconfig', '.conf_files/gitconfig')
=> false
I assume this has something to do with the way that git is writing the .gitconfig file. Does anyone know why this would happen, or have any creative ideas for a workaround?
Try Eli Barzilay's solution in his comment at http://www.xxeo.com/archives/2010/02/16/dotfiles-in-git-finally-did-it.html:
So I’ve finally found a solution that takes the best of both: put the repo
in a subdirectory, and instead of symlinks, add a configuration option for
“core.worktree” to be your home directory. Now when you’re in your home
directory you’re not in a git repo (so the first problem is gone), and you
don’t need to deal with fragile symlinks as in the second case. You still
have the minor hassle of excluding paths that you don’t want versioned (eg,
the “*” in “.git/info/exclude” trick), but that’s not new.
This is completely normal, and is in fact the recommended way to overwrite config files. Git creates a temporary file, writes out the config, and then moves the new file over the old one. This way, you don't get an incomplete config file (data loss) if Git gets interrupted.
You can always write a script to copy or link your config files into your central repository.
Checkout this answer, perhaps it may be of help:
https://stackoverflow.com/a/3731139/1431696
In the meantime, have you considered doing the links in reverse? Create your repository full of config files, etc, and then in the place that you actually use your files, create a hard link to the 'real' file, which sits in the repository.
Thanks to Dietrich Epp's answer and advice I have decided to approach this problem from a different angle by creating the repository at the root of my filesystem, and using .gitignore to track only the files I am interested in.
My .gitignore file now looks like this:
/*
!/etc/
/etc/*
# etc files
!/etc/rc.conf
!/etc/asound.conf
!/etc/mercurial/
!/home/
!/home/matt/
/home/matt/*
# Home files
!/home/matt/.xinitrc
!/home/matt/.gitconfig
!/home/matt/.bashrc
# Vim files
!/home/matt/.vimrc
!/home/matt/.vim/
.netrwhist
In addition to not having to copy the files separately and keep them in two separate locations this has the benefit that should I need I can easily revert the changes without having to manually copy the files as well.
Thanks for the help guys!
I'm using following command to export my repository to a local path:
svn export --force svn://localhost/repo_name /share/Web/projects/project_name
Is there any, quite easy (Linux newbie here) way to do the same over FTP protocol, to export repository to a remote server?
Last parameter of svn export AFAIK have to be a local path and AFAIK this command does not support giving paths in form of URLs, like for example:
ftp://user:pass#server:path/
So, I thing there should be some script hired here to do the job.
I have asked some people about that, and was advised that the easiest way is to export repository to a local path, transfer it to an FTP server and then purge local path. Unfortunately I failed after first step (extract to local path! :) So, the support question is, if it can be done on-the-fly, or really have to be split into two steps: export + ftp transfer?
Someone also advised me to setup local SVN client on remote server and do simple checkout / update from my repository. But this is solution possible only if everything else fails. As I want to extract pure repository structure, without SVN files, which I would get, when go this way.
BTW: I'm using QNAP TS-210, a simple NAS device, with very limited Linux on board. So, many command-line commands as good as GUI are not available to me.
EDIT: This is second question in my "chain". Even, if you help me to succeed here, I won't be able to automate this job (as I'm willing to) without your help in question "SVN: Force svn daemon to run under different user". Can someone also take a look there, please? Thank you!
Well, if you're using Linux, you should be able to mount an ftpfs. I believe there was a module in the Linux kernel for this. Then I think you would also need FUSE.
Basically, if you can mount an ftpfs, you can write your svn export directly to the mounted folder.
not sure about FTP, but SSH would be a lot easier, and should have better compression. An example of sending your repo over SSH may look like:
svnadmin dump /path/to/repository |ssh -C username#servername 'svnadmin -q load /path/to/repository/on/server'
URL i found that info was on Martin Ankerl's site
[update]
based on the comment from #trejder on the question, to do an export over ssh, my recomendation would be as follows:
svn export to a folder locally, then use the following command:
cd && tar czv src | ssh example.com 'tar xz'
where src is the folder you exported to, and example.com is the server.
this will take the files in the source folder, tar and gzip them and send them over ssh, then on ssh, extract the files directly to the machine....
I wrote this a while back - maybe it would be of some use here: exup
Is there a simple command to add a directory and all files underneath it to svn?
I have tried svn add directory which makes sense to me but this doesn’t work as expected. I have googled it and there are solutions which all appear a bit long-winded for something so simple.
What would be the standard way of doing this?
svn add directory only works if the directory hasn't been added already. Adding all new files is not standard operation in svn world. Git does this but that's sidetracking.
You can often get by with svn add directory/* but it misses new files in existing subdirectory. So:
directory/newDirectory/file -> is added
directory/oldDirectory/file -> is NOT added
If you really need to add any file anywhere in the directory hierarchy this one liner will set-up an alias for you to do this:
alias svn_addall="svn st|grep ^?|sed 's/./svn add/'|sh"
Put it into your .profile and you'll have easy access to it any time. :-)
Funny. Which version of svn are you using. I`m on a mac and use svn 1.6. And it works for me.
When i look at my man pages for svn then it looks like the command is recursive by default. You can permit the behaviour with:
--depth ARG : limit operation by depth ARG ('empty', 'files',
'immediates', or 'infinity')
svn add folder will add the folder and its contents. How doesn't it work as you expect?