将$ HOME放入git而不是符号链接点文件有陷阱吗?


38

我已经将整个$HOME目录签入Subversion 多年了。其中包括我的所有dotfile和应用程序配置文件,许多脚本,工具和黑客工具,我偏爱的基本主目录结构,一些怪异项目以及大量随机数据仓库。这是一件好事。虽然持续了。

但这已经失控了。在许多系统上,基本的结帐方法是相同的,但并不是所有的东西都适合我的所有机器。在不同的发行版中,它甚至都不能很好地发挥作用。

我正在清理房子-将数据分离出来,将一些脚本拆分为单独的项目,修复一些应该自动化的东西中的损坏链接,等等。

我的意图是将替换为,subversiongit进行的顶级检出$HOME,但我想将其简化为我想在所有系统上拥有的东西,包括点文件,一些目录和一些基本的自定义脚本。

在线阅读时,很多人似乎正在使用symlink方法进行此操作:克隆到子目录中,然后从$HOME存储库中创建符号链接。$HOME完全版本控制下的十多年中,我不喜欢这种方法的想法,而且我无法弄清为什么人们似乎不喜欢直接签出方法。我需要了解特定于git顶级结帐的陷阱$HOME吗?

PS部分是作为良好编码的练习,我还计划在github上公开我的root checkout。令人震惊的是,我允许在不经考虑就共享的文件中收集了多少安全敏感信息!WiFi密码,未口令的RSA密钥等。


5
奇怪是什么导致人们认为$ HOME应该可以共享而无需三思而行‽即使加密的RSA私钥也不应共享。
derobert

3
如果您实际上是在谈论将主目录的内容放入git,请注意:很难(但并非没有可能)深入git历史并仔细地永久删除敏感项(git旨在帮助防止丢失),并且还要记住,当您切换分支或签出时,较早的修订版git会将文件的权限更改为签出后的权限,644这对于诸如ssh私钥之类的事情是不利的。但是,这etckeeper是一种使用git对/ etc /权限的解决方案
cwd 2012年

@derobert:我很清楚。我并不是说要公开$ HOME,而只是谈论点文件和便利脚本。这些就是我一直在寻找不属于自己的东西的地方。是的,我应该能够分享我的.zshrc.vimrc和类似的事情,而不必首先它们进行消毒!
卡勒布(Caleb)2012年

4
如果您还没有看到它,请参阅vcs-home Wiki和邮件列表,这基本上是人们在讨论的话题-如何使您的$ HOME受版本控制。
吉姆·巴黎

我不知道您可以改变git的行为多少,但是至少它在debian-repository之外工作的方式在搜索已跟踪/未跟踪/已修改的文件时会非常贪婪,并且会自动对每个文件感到负责。mrb已经说明了这一点。有时,即使在相对较小的项目中,我也不想在自己的主目录中看到这种贪婪的行为,这使我很恼火。为什么要使用git?我还使用一个版本控制系统来跨主机同步我的配置文件,我对CVS感到非常满意,因为它是如此简单!Git是为了这个(太多!)强大
Bananguin

Answers:


17

是的,在考虑git管理无关的主目录时,至少有一个主要陷阱subversion

默认情况下,Git既贪婪又递归

Subversion会天真地忽略它不知道的任何内容,并且当结帐到达不知道的(或属于另一个存储库的)文件夹时,它会停止处理您签出的文件夹。另一方面,由于名称空间问题,Git会继续递归到所有子目录中,从而使嵌套检出变得非常复杂。由于您的主目录也可能是您签出并使用其他各种git存储库的地方,因此将主目录包含在git中几乎肯定会使您的生活变得一团糟。

事实证明,这是人们将他们的dotfile检出到隔离文件夹中,然后符号链接到其中的主要原因。在您的.NET的任何子目录中执行其他任何操作时,它都能避免git干扰$HOME。虽然这纯粹是一个优先考虑的问题,如果要检查您的房屋是否被颠覆,那么如果使用git则成为必需的问题。

但是,还有另一种解决方案。Git允许使用所谓的“假根”,其中所有存储库机器都隐藏在备用文件夹中,该文件夹可以与结帐工作目录物理隔离。结果是git工具包不会混淆:它甚至不会看到您的存储库,而只会看到工作副本。通过设置几个环境变量,您可以在管理主目录的那一刻提示git在哪里找到商品。没有设置环境变量,没有人会更明智,您的家看起来就像是经典的文件型自我。

为了使此技巧流程更流畅,这里有一些很棒的工具。该VCS家庭的邮件列表似乎是事实上的地方开始,和关于页面有一个方便的收官HOWTO和人的经验的。一路上有一些漂亮的小工具,例如vcshmr。如果要将主目录直接保存在git中,vcsh几乎是必备工具。如果最终将您的主目录拆分为多个后台存储,请vcsh与结合使用,mr以快速且不太脏的方式一次管理所有目录。


2
但是为什么不只是在您的.gitignore文件中添加“ *”呢?这样,git将忽略存储库中已存在的文件以外的所有文件,您可以使用添加新文件git add -f <file>
ALiX

@ALiX:因为git即使您位于某个项目的单独git repo的某个子目录中,这些工具仍会认为您正在使用主目录repo。该解决方案将使您的整个主目录不受其他所有git工作的限制。
卡勒布(Caleb)2012年

4
但是.gitignore中的'*'表示所有不在home-dir存储库中的文件都将被忽略。当您在某个子目录中签出新的git repo时,一切仍应按预期工作(我认为)。据我所知,git工具将在上移目录层次结构时查找第一个.git目录。因此,在子目录中工作时,将使用正确的git存储库。当然,如果您使用git的环境变量,我想事情可能会变得混乱。但是否则,我不明白为什么这行不通。
ALiX

@ALiX是正确的。只要您在父存储库中对它们进行gitignore,嵌套的git repos看起来就可以正常工作。我想知道除了git的环境变量可能存在的问题之外,这种非常简单的方法还有哪些弊端。
evanrmurphy 2013年

1
今天正在尝试这个。我认为/**它更好,因为它在默认情况下仍会忽略所有内容,但使添加目录更加容易。而不是git add -f我使用- 和- (。!gitignore 文件本身)这样的前缀模式来在回购协议中明确包含内容。!/.vimrc!/.gitignore
evanrmurphy

14

我不希望我的整个主目录都被检入版本控制,因为这意味着我进入的每个子目录都将具有主目录的版本控制上下文。git checkout在这种情况下,像这样的命令会采取实际行动,如果我不小心从错误的目录运行了某些内容,无论是git其本身还是调用git的脚本,都会引起问题。

它还使您更有可能在仓库中添加不需要的东西,当您将所有内容都签入时,这本来不是问题,但现在变成了问题。如果您不小心添加了一个私钥文件(也许是出于习惯)并将其推送到github,该怎么办?

话虽如此,我认为主要的缺点并不是真正的技术性问题,只是想让我自己摆脱困境。

至于符号链接:您可以将您的存储库克隆到一个子目录中,并具有一个脚本来更新需要更新的符号链接。但是,此脚本所需的维护量可能根本超过了拥有它的好处。符号链接可能会减少工作量。

使用符号链接,您还可以轻松地进行发行版特定(甚至主机特定)的添加,并将其添加到git中。您的symlink-update脚本将忽略旨在用于不兼容平台或不同主机的文件,而仅更新适当的文件。

就像是:

HOMEREPO=$HOME/homerepo
HOST=$(hostname)
UNAME=$(uname)

for dotfile in $HOMEREPO/shared/* $HOMEREPO/host-$HOST/* $HOMEREPO/uname-$UNAME/*
do
    target=$HOME/$(basename $dotfile)
    [ ! -r $target ] && ln -s $dotfile $target
done

就个人而言:我使用符号链接,但不使用符号链接目录。仅其中的文件。这给了我一些灵活性,可以在这些目录中进行站点本地更改(即添加/删除文件)。在新系统上设置帐户非常繁琐,因为我必须手工重新创建所有符号链接。


git我运行的任何命令要么用于主目录本身,要么将至少一个埋在NON committed目录中。使用svn此一个文件夹隔离非常有效,并且十年来没有给我造成任何麻烦。您的第一段表示其他内容。这实际上是git工作方式上的差异吗?
卡勒布(Caleb)2012年

另外,我的配置和脚本已经内置了适用于不同主机和平台的条件逻辑,因此使用脚本来设置不同的链接作为条件条件似乎并不会比git容易管理分支获得太多收益。还是我缺少的东西,或者这会归结为偏好吗?
Caleb 2012年

3
单文件夹隔离并没有真正隔离git-不确定svn-但例如,git init foo && mkdir -p foo/bar/baz/spam && cd foo/bar/baz/spam && git status(或其他git命令)表明您仍处于foo版本控制上下文中。
mrb

配置和脚本:并非所有的点文件都支持条件文件,这就是为什么我建议使用替代方法的原因。这些都是我认为人们不愿意使用版本控制的原因$HOME-而且版本控制对于点文件imo并不是很有价值-但最终它是您的主目录,因此,如果您更喜欢使用git,那么这对您来说就不是问题,去吧!
mrb

谢谢(你的)信息。实际上,您对git不允许隔离的评论是最有用的。您可能会在回答中做出突出的努力。在这一点上,Subversion的行为有很大不同,对于此用例而言,意义重大。
卡勒布(Caleb)2012年

5

换个角度来看:自从某个时候以来,我在git下有$ HOME,并且没有发现任何缺点。我显然不将此git repo同步到github; 我使用的是带有私人存储库的服务。我也不将任何媒体文件,下载或程序包置于git控制之下。

  • git status 是一种“要做的,要清理的”清单。

  • 我有一个~/tmp临时的东西,这是忽略不计的。

  • 我喜欢看到git status最近安装的软件敢于添加到我的$ HOME中的任何内容,并且经常删除这些文件,甚至卸载罪魁祸首。

  • 我将真正有用的本地文件和目录手动添加到中.gitignore,它具有“知道安装时的操作”的好处。

  • 如果我构建新的VM或安装新的PC,则只需将远程主目录克隆到$ HOME,并立即获得所需的一切。

  • 不再需要像vundle这样的vim插件。

我不喜欢复杂性。当我调整任何rcfile时,我都会执行,提交并推送。然后,作为反射,我隔两天git in $ HOME,并始终具有最新的配置。就这么简单。

当前使用此方案的计算机:家用笔记本电脑,工作PC,工作VM,以及3或4个远程服务器。


您在家中是否还有其他git checkout嵌套?
Caleb 2012年

不,我将其他东西放在/ work目录中,并且不克隆像vim pugins这样的小工具。
gb。

1
我在〜/ Sites内部工作,也执行此方法,嵌套git repos没有问题
philfreo 2012年

1
我已经使用了一段时间了。我有一个'alias sq = git status -uno',并且对.gitignore不太在意(每隔一段时间,我会查看所有残留物,然后说“ meh”)。我从来没有嵌套git repos的问题。我有一个专用服务器,在该服务器上我git init --bare通过ssh推送到了该服务器(尽管我没有在仓库中输入密码,但我的笔记文件确实在那儿)。
unhammer '16

5

我已经尝试过这两种方法,最后都倾向于使用symlink方法

  • 签到任何地方
  • make install
  • 注销并再次登录以加载X设置

缺点:

  • 在添加文件之前必须将文件移动到仓库
  • 必须维护Makefile 中的符号链接列表

好处:

  • 不需要大量文件.gitignore~我谦虚的Ubuntu盒子中有133个点文件)
  • 能否保持维护脚本和其他~产权相关的东西(如Makefilecleanup.sh的方式进行
  • 可以分别控制个人和公共设置的版本

限制条件:

  • 与@mrb不同,我仅在中创建符号链接~。这样可以使符号链接保持简单,并使得例如~/.vim以很少的.gitignore维护为代价来注意新文件变得不容易。

最后的两个优势使我的工作规模大打折扣-我不想使主目录杂乱无章,而且我想使私有和公开内容明确分开。

我知道的唯一在处理符号链接方面有(或至少有)问题的应用程序是Pidgin-它不断用普通文件覆盖我的符号链接。


感谢您对每种方法的优缺点的投入。在我的后续研究中,我发现如果您可以设置额外的接线以开始使用,那么还有第三种方法可以兼顾两个方面。
卡勒布(Caleb)2012年

3

这是一个:如果您尝试执行此操作,git rebase -i --root并且已在.gitconfig存储库中的第一次提交中签入,则git将暂时删除该.gitconfig文件,这又将使其无法完成变基操作,因为它需要您的姓名和电子邮件才能执行该文件存储在该文件中。

您可以再次配置它们并执行操作git rebase --continue,但是在完成并完成了变基操作之后,我的git存储库获得了一个空的提交,而之前没有提交消息,而该提交以前是存储库中的第一次提交,我不知道如何摆脱。

我不知道如果您改git rebase -i <commit>而会发生什么情况,并且.gitconfig在之后进行任何提交都会被检入<commit>

也许最简单的解决方案是避免添加.gitconfig到存储库中,而是将其列出.gitignore


2

这是我的方法:

  1. 安装一个干净的Linux(不是必需的,但是在第4步中使生活更愉快)
  2. 安装etckeeper
  3. git init在家里跑
  4. 创建.gitignore并添加所有您不感兴趣或可能会发生很大变化的内容。一定要添加的东西一样*.cache*.lock等我不建议加/*因为当您在家里添加新物品时,不会自动收到通知。这是黑名单方法与白名单方法,在这里我基本上要保留所有软件的配置,除了易失性内容和一些我不在乎的软件。以后合并,迁移或比较系统时,能够区分所有内容非常方便。与仅存储.bashrc和其他一些dotfiles相比,您可以更快地设置新系统。这样,您将保留可能通过GUI进行设置的配置,并且不知道哪些点文件存储设置。(如果事实证明您已经提交了易失性文件,则仍然可以告诉git假定未更改)
  5. etckeeper init -d /home/username
  6. git commit -d /home/username
  7. 在您的shell中设置别名以使命令行更好,例如 homekeeper checkout

使用etckeeper的原因是它将存储诸如文件许可权之类的元数据(对于某些事物(如ssh密钥)尤为重要)。现在,您应该有一个预提交挂钩,它将自动保存元数据。我不确定结帐后的服务。您可能应该使用,etckeeper checkout xxx -d /home/user我将对其进行更多研究并详细说明此答案。


-1

我在主目录上使用Git的主要问题是Git不存储文件属性,例如文件许可权和时间戳。对我来说,重要的是要知道何时创建某些文件,这对您而言可能是,也可能不是。此外,丢失对文件和目录的权限.ssh是有问题的。我了解您计划.ssh不使用Git,但在其他地方,权限可能很重要(例如未压缩的网站备份)。


即使不是事实错误,这也会产生误导。默认情况下,Git会保留许多文件属性,包括权限。我已经.ssh在git中保持一段时间了,没有任何问题,保留了适当的安全权限。在基本配置中不执行的操作是保留所有权或时间戳。但是,如果这两个问题对于特定用例来说都是一个问题,那么有一些插件可以使处理这些其他属性成为常规工作流程的一部分(请参阅metastore或git-cache-meta)。
Caleb 2013年

即使它不存储它们,与仅在VCS中没有主目录相比,还有什么比这更糟的呢?除非您要求git更改文件,否则git不会主动覆盖mtimes。
poolie 2014年

-1

如果您需要将文件部署到其他计算机上,则基于git的解决方案特别有用,如果您拥有所有计算机都通用的部分以及某些计算机特定的部分,则基于git的解决方案尤其有用。您可以制作多个存储库,并使用诸如multigitvcsh之类的工具将它们克隆到同一目录(在本例中为您的主目录)。


谢谢,但是也许您错过了这个问题。我很清楚此用法(因此为什么我想首先这样做),这个问题是关于有人不熟悉git的任何陷阱(就像我问的那样) 。这似乎根本无法回答这个问题。
Caleb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.