在未清理的工作树($HOME/.dotfiles)中进行非破坏性的Git检出

3
在设计另一个Git .dotfiles管理系统时,出现了这个问题。我想使用$HOME作为我的工作树,并将存储库存储在其他位置(不是在.git下,因为那会导致其他存储库混淆)。
在旧机器上,之前复制并可能调整过的dotfiles上,我现在想克隆我的新dotfiles存储库并以某种方式到达一种状态,以便我可以将$HOME/.* dotfiles的(预)现有状态视为对新克隆存储库的主分支的修改。这主要是背景,在Git中,我只想小心地检出脏目录而不覆盖。
(在普通情况下,我可以从新目录开始,然后复制我的更改,但当工作树是我的$HOME时,这似乎很难做。)
我发现了一对命令,它似乎可以让我到达正确的位置,但我不确定这种方法是否存在任何陷阱或更简单的方法来实现同样的事情:
git read-tree -v HEAD # load HEAD into the index
git checkout-index -a # cautiously check out all files without overwriting

这两个命令是否达到了与复制我的主目录,执行常规检出,然后将文件复制回来的状态相同,以便 git diff 只显示我在本机上所做的更改而不会删除任何文件?

还有其他应该应用的选项吗?

背景是我(Alpha)的引导脚本:

git clone --bare -n git://github.com/$(git config github.user)/.dotfiles.git ~/.dotfiles/repo.git
git config -f .dotfiles/repo.git/config core.bare false
git config -f .dotfiles/repo.git/config core.logallrefupdates true
git config -f .dotfiles/repo.git/config core.worktree $HOME
export GIT_DIR=~/.dotfiles/repo.git ;  export GIT_WORK_TREE=~
git read-tree -v HEAD 
git checkout-index -a # all files without overwriting
ln -sf $HOME/.dotfiles/gitignore-dots $HOME/.dotfiles/repo.git/info/exclude
2个回答

0

更新于2012年08月19日

我已经使用这个方案在新的和现有的账户上设置我的dotfiles一段时间了,到目前为止以上命令还没有破坏任何东西。 另一方面,没有git专家对这种安排表示赞成,有些人以含糊不清的“你疯了吗?”的方式表示反对。

现在我有了别名doton/dotoff和源文件,可以调整GIT_DIR和GIT_WORK_TREE, 所以我在工作中进行微调,尝试它,在github上推送,然后在家里更新我的其他机器。 大多数情况下,这是一个简单的快进或rebase,但偶尔需要一个脏的更新。

脏更新

我把这个添加在这里,因为它是问题草图中提到的方法的另一半。

比如我git add我的~/.XCompose并推送它。当我想要将其拉到已经有.XCompose文件的机器上时, 我想要获取更改,查看与我的本地(未添加)副本的差异,然后从那里合并。 Git会检查这个并退出,这通常是适当的。

我再次使用管道命令来执行大部分高级命令,但是为了与脏工作副本一起使用,省略了一些烦人的安全检查。这些管道命令在文档中没有很好的覆盖,但似乎可以工作(不保证)。

这些说明假定您没有新的本地更改,即它不会进行变基。

请注意,这可能会损坏文件,包括未跟踪的文件。我不知道这是否安全,我怀疑如果出现问题,您可能会留下相当混乱的局面。)

git fetch # download FETCH_HEAD

# Check HEAD is an ancestor of FETCH_HEAD
cmp <( git rev-parse HEAD ) <( git merge-base HEAD FETCH_HEAD ) \
    || echo "merge-base is not HEAD, not fast forward"

# merge FETCH_HEAD into HEAD in index (2 tree merge is ff, no local changes)
# (no -u means the work tree is not updated)
git read-tree -v -m  HEAD FETCH_HEAD # --trivial ?
# index now merged with FETCH_HEAD

# set HEAD to be FETCH_HEAD with dereferencing
git update-ref HEAD FETCH_HEAD

# update work tree without overwriting existing files (not forced)
# (existing un-added isn't overwritten)
git checkout-index -a

# can now check diffs for conflicts add either commit/edit/checkout
git diff --stat

git pull -vn # should be a no-op

这里是我用来检查事物状态的一些命令:

git rev-parse HEAD FETCH_HEAD   # what do they point to
git diff --stat HEAD FETCH_HEAD # differences
git merge-base HEAD FETCH_HEAD  # common ancestor
for r in HEAD FETCH_HEAD; do echo $r ; git log --oneline $r | head -1; done
git name-rev $( git merge-base HEAD FETCH_HEAD )

# peek at index
git ls-files --directory --exclude-standard --stage

git diff-index --cached FETCH_HEAD # see "local changes" carried forward

0
我想要将$HOME作为我的工作树,并将代码库存储在其他地方(不是在.git下,因为那会引起其他代码库的混淆)。
请不要这样做。我的建议是将你的工作树放在这里。
/opt/dotfiles

请在此处放置您的代码库。
/opt/dotfiles/.git

然后你可以运行以下命令将工作树引导到$HOME

. /opt/dotfiles/bootstrap.sh

著名的例子,以及我的例子在这里

mathiasbynens bootstrap.sh

svnpenn bootstrap.sh


你能澄清一下“不要这样做”吗?我的方法是否存在潜在的风险需要警惕?将repo→$HOME同步的优点是什么?谢谢。 - bsb
1
$HOME 是一个经常使用的目录,不应该成为 git 工作目录的位置;几乎可以确定工作目录会被污染。 - Zombo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接