如何将“点文件”纳入版本控制?

Etckeeper是一个很好的工具,用于跟踪你在/etc目录下的配置文件的更改。它有几个关键的特点非常突出。它可以与各种版本控制系统一起使用:git、mercurial、darcs或bzr。它还会自动进行每日提交,并在安装、删除或升级软件包时进行提交。它还会跟踪文件权限和用户/组所有权元数据。
我还想将我的“点文件”(dot files)也放在我的主目录下进行版本控制,最好是使用bazaar。有人知道是否存在类似etckeeper的工具来实现这个目的吗?
最坏的情况下,我想可以通过设置一个简单的cron任务,每天运行bzr add && bzr ci,并将~/Documents~/Music等添加到.bzrignore中。有人已经用脚本做过类似的事情吗?
虽然我更喜欢bazaar,但其他选项也可能很有趣。

4Unix Stack Exchange上的相关讨论:将~纳入源代码控制的技巧。虽然它并没有回答你的问题,但仍然可能提供有用的信息。 - Gilles 'SO- stop being evil'
1现在有很多工具可以做到这一点。请查看 https://dotfiles.github.io/ ,在“通用的 dotfile 实用程序”章节中找到相关内容。 - Robin Green
@RobinGreen 如果你能把这个内容转化成一个恰当的答案,我会接受它。在2015年,bzr绝对不是正确的选择。 - andrewsomething
8个回答

我不知道是否有任何东西可以做到这一点,所以我写了一些代码来实现你想要的功能,你可以在我的存储库http://github.com/robertmassaioli/config-files中找到。
我有一个文件,里面记录了所有文件应该放在哪里,generate_links程序会将它们全部放在那里。如果你知道自己在做什么,并且能够编译一些Haskell代码,那么这个过程非常简单和容易。不过请注意,它确实是为了我个人使用而制作的。

3+1 支持 Haskell!-1 反对 Haskell!哈哈。不过说真的。 - Derek
我明白你的意思。我选择Haskell是因为我正在学习它,它可能是最适合这项工作的语言,也可能不是。 :) - Robert Massaioli

嗯,我已经手动完成了这个任务,直到找到更好的解决方案。所以我也可以解释一下我做了什么。
首先,我执行了bzr init ~,但接下来我做的是bzr ignore "*"。我决定不想将整个东西都放在版本控制下。这真的不值得,特别是考虑到其中有一些东西你真的不应该保留在版本控制中,比如你的密钥。所以我接着必须bzr add我想要的特定文件。你还可以在.bzrignore中添加例外情况。Python正则表达式在那里也很有用。目前我只保留了一些基本的内容。如果一切顺利,我可能会添加~/.config~/.gconf的所有内容。
我还编写了一个快速脚本,作为cron作业运行。它检查文件是否发生了变化,如果是,则自动提交:
#! /bin/bash

set -e

TIME=$(date)
STATUS=$(bzr status)

if [ -n "$STATUS" ]; then
    if [ -n "$1" ]; then
         bzr ci ~ -m "$1"
    else
        bzr ci ~ -m "Automatic commit on $TIME"
    fi
fi

exit

我在最初发布这个问题时选择了自己的答案,但后来决定撤销。对于2015年的这个问题来说,这显然不是最好的答案。 - andrewsomething

我把整个~目录都变成了一个 Bazaar 仓库。对于家目录中的文件来说,存储元数据并不是一个问题:一切都归属于同一个账户和组,并且 bzr 已经存储了执行权限位。
我手动将“有趣”的文件添加到仓库中(例如,我不想让我的音乐收藏或火狐缓存受版本控制),但如果你想用脚本自动化这个过程,我认为在所选目录上执行 "bzr add && bzr ci" 或者使用 "find" 命令的输出作为输入来执行这个任务会很简单。

我将我的zsh和vim文件存储在git中,上传至GitHub,在不同的代码库中:

例如,对于zsh,我创建了一个名为".zsh"的文件夹,并将zshrc和zshenv放入其中,还有一个脚本用于将zshrc链接到~/.zshrc,将zshenv链接到~/.zshenv,类似于这样。

while true
do
read -p "do you want to link zshenv to ~/.zshenv (Y/N)" yn
case $yn in
    [Yy]*) ln -s ~/.zsh/zshenv ~/.zshenv; break;;
    [Nn]*) break;;
    *) echo "please answer yes or no";;
esac
done

while true
do
read -p "do you want to link zshrc to ~/.zshrc (Y/N)" yn
case $yn in
    [Yy]*) ln -s ~/.zsh/zshrc ~/.zshrc; break;;
    [Nn]*) break;;
    *) echo "please answer yes or no";;
esac
done

所以我会这样做
git clone git://git@github.com:tshirtman/.zsh
cd .zsh
./init.sh

对于.vim来说,基本上是一样的,只是我使用子模块来管理插件,配合pathogen使用,所以我在init.sh中添加了这个。
git submodule init
git submodule update

当我想要添加一个Vim插件时,我会这样做
git submodule add git://github.com/nathanaelkane/vim-indent-guides.git bundle/vim-indent-guides

举个例子。
好的,如果你有多个点目录需要管理,那可能需要花费不少功夫。但并没有什么妨碍你将它们都放在同一个目录下,或者按照活动(例如所有图形编辑器放在一个目录中,网络活动放在另一个目录中)进行分隔等等。总之,这就是我所做的,只是我的建议而已。

我使用的解决方案不像etckeeper那样自动化(我需要手动提交),但对我来说效果很好。它的发展还不够完善,但它能正常工作。
我编写了一个类似于GNU Stow的实用程序,因为stow没有满足我所有的需求。我称之为Stow in Home。运行时,它会查找名为"HOME"的目录。然后,它会将该目录下的所有内容符号链接到$HOME中相应的位置,并在必要时创建目录。它还会翻译文件名——如果文件以'_'开头,就会被替换为'.'。我这样做是因为当我的点文件不隐藏时(默认情况下在目录列表中可见),更容易编辑它们。然后,它会将它们放在应用程序所期望的位置。
所以,我有几个用于配置的git仓库。我只将我个人编辑的点文件放在其中。这样做的好处是我可以有一个点文件的仓库,可以与他人共享(比如我的Emacs配置),还可以有一个私密的仓库(比如我的ssh配置,包含工作中的主机名等)。使用stow-in-home进行符号链接可以将所有文件放在正确的位置,但每个仓库的源代码控制可以是独立的。
这种方式对我来说效果很好。实际上,我完全可以设置自动提交的功能,或者将所有点文件移动到相应的仓库中,仍然可以使用stow in home。但这就是我一直以来的做法。


你不能把点文件添加到Etckeeper使用的存储库中吗?

1我该怎么做呢?将它们全部建立符号链接到/etc目录下的某个位置吗? - andrewsomething
嗯...那是一个选择 - txwikinger

我通过将我喜欢保留在源代码控制下的所有dotfiles复制到一个名为"dotfiles"的文件夹中,完成了这个任务。当然,这意味着需要保留副本并在必要时进行复制,但我发现这对我来说是最简单的解决方案。

1不用管理重复的文件,你可以创建符号链接来管理你的dotfiles。 - Ryan
我认为你肯定可以! - Derek