如何跟踪修订历史记录的修订历史记录? [英] How to track revision history of revision history?

查看:139
本文介绍了如何跟踪修订历史记录的修订历史记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个编程教程项目,并且我希望该教程的示例源代码具有有意义的修订历史,与教程的进度有关.不可避免地,我不会在第一次就获得所有正确的教程提交,而且我不希望修订历史因提交而混乱,而我却以元方式修改了教程的提交.我认为这意味着我想要两个版本的版本控制:一个与本教程的用户相关的内部版本控制,另一个是跟踪我如何重写内部版本历史的外部版本.

I am working on a programming tutorial project, and I want the sample source code for this tutorial to have a meaningful revision history, relevant to the tutorial's progress. Inevitably, I won't get all the tutorial commits perfectly right the first time, and I don't want that revision history cluttered with commits where I modify the tutorial's commits in a meta way. I think this means that I want two levels of version control: an inner one that is relevant to users of the tutorial, and an outer one that tracks how I rewrite the history of the inner one.

我从其他SO问题(例如'

I see from other SO questions (such as 'Is it possible to have a git repo inside another git repo') that Git ignores .git within subdirectories. That would seem to preclude git for at least one of my levels of version control.

任何人都可以推荐一种既可以跟踪内容的更改又可以跟踪该历史记录的策略吗?

Can anyone recommend a strategy for tracking both the changes to content, and rewrites of that history?

推荐答案

我可以想到两种方法,这两种方法都使用一些管道,而现有瓷器在建造时会考虑其他因素.

I can think of two ways to do it, both of them using some plumbing where the existing porcelain's built with other things in mind.

第一种方法最简单,但我直到最近才知道甚至有可能 1 ,并且怀疑一些有经验的git用户会将其视为怪兽.问题是,这是一个非常有用的怪物,在过去两个特征之间的辩论中,有用"有时被证明更有用.所以:

The first way's easiest but I only recently learned it was even possible1 and suspect some experienced git users will regard it as a monstrosity. The thing is, here it's a very useful monstrosity, and in past debates between the two characterizations "useful" has sometimes proved more ... useful. So:

第一种方法:

您可以直接跟踪在嵌套存储库中也可以跟踪的内容.一旦git跟踪目录中的任何内容,它将完全 2 忽略您随后在该目录中创建的任何存储库.

You can directly track content that is also tracked in nested repositories. Once git is tracking any content within a directory it will completely2 ignore any repository you subsequently create there.

从您的问题中可以看出,您可以整洁地分割各个部分,因此,从顶部开始:

It appears from your question that you've got neatly severable sections, so, from the top:

使用存根(或当前)初始内容创建一个完全普通的回购

# from the top:

# create and commit the empty skeleton
git init book
cd !$
mkdir -p sect{1,2,3}
touch {.,!$}/.gitignore
# copy in any initial content here
git add .
git ls-files -s # to see exactly what you've done so far
git commit -m 'initial skeleton'

创建子存储库以独立跟踪各个部分

# now git is directly tracking content in each section, and commands in the 
# parent will _ignore_ the existence of any nested repositories you subsequently 
# create, but not there worktrees (because of the existing tracked content). viz.:

( cd sect1
  git init 
  git add . 
  git commit -m 'initial skeleton'
  git branch publishing-history
)
^1^2
^2^3

独立,自由地处理每个部分

您现在可以在多个存储库中跟踪这些部分,并且可以完全独立地处理每个部分:

You now have the sections tracked in multiple repositories, and can work on each section entirely independently:

cd sect1
# work work commit commit lalala
# ... do whatever in the other repos

发布所有部分的合并当前内容

,该在每个子目录中发布当前内容了.清除所有内容以进行发布,然后从其中任何一个执行一次

and it's time to publish the current content in each subdirectory. Get their content all cleaned up for publication, and from any of them, just once, do

cd ..
git add -A .
git commit
published=`git rev-parse HEAD`

您完成了.如何记录行为:

You're done. How to record the act:

在每个部分记录行为,以供参考

for section in sect*; do
    cd $section
    git update-ref refs/heads/publishing-history $(
        # log where the checked-out commit was published
        git commit-tree \
                  -p publishing-history \
                  -p `git rev-parse HEAD` \
                  -m "## published in main repository commit $published ##" \
                HEAD^{tree}  # just `HEAD:` will work too
    )
    cd ..
done

对您选择发布的提交或以什么顺序进行的发布没有任何限制.这就是Linus将git称为愚蠢的内容跟踪器"的原因:核心没有抽象.该分支正确记录了这些提交的顺序,内容和祖先.

There are no constraints on the commits you choose to publish or in what sequence. This is why Linus calls git a "stupid content tracker": no abstractions at the core. The branch correctly records the sequence and content and ancestry of those commits.

commit-tree 更新参考.

建立重写的,独立的发布历史记录

git symbolic-ref HEAD refs/heads/newmaster

并如上所述发布任何您喜欢的已检出提交序列. publish-history分支将忠实记录您发布的内容以及发布的时间.

and publish, as above, any sequence of checked-out commits you like. The publish-history branch will faithfully record exactly what you publish and when.

您可以看到前进的方向,对吗?您可以使用commit-treeupdate-ref从提交的内容构造任意历史记录.如果父仓库中的提交序列不是您想要的,请通过直接提交正确的树序列,将其替换为您想要的完全不同的历史记录.要在父存储库中记录单独的注释,也可以在其上使用发布历史结构.

You can see where this is going, right? You can construct arbitrary histories from committed content with commit-tree and update-ref. If the commit sequence in the parent repo isn't what you want, replace it with an entirely different history that you do want by directly committing the correct sequence of trees. To record separate notes in the parent repository, use the publishing-history construct on it too.

仅需注意:如果您开始进行大量的历史记录重写,而构建新序列所涉及的结帐工作似乎很繁琐,那么git可以满足您的要求.从 gitcore-tutorial 开始准备好了.

Just a note: if you start doing extensive history rewrites and the checkouts involved in constructing a new sequence start to seem burdensome, git's got you covered. Start from the gitcore-tutorial when you're ready.

另一种方法

这种方式通过从完全独立的存储库中获取和操作树来代替发布合并的当前内容"步骤,而不是使用上面的覆盖存储库方法.然后是发布步骤

This way replaces the "Publish combined current content" step by fetching and manipulating trees from entirely separate repositories rather than using the overlaid-repositories method above. The publish step is then

cd ../main
git read-tree --empty
for repo in sect{1,2,3}; do
    ( cd ../$repo
      tag -f fetchme HEAD^{tree}
    )
    git fetch ../sect1 fetchme
    git read-tree -m --prefix=sect1 FETCH_HEAD
done
git commit

但这有一个缺点,即您不仅必须显式同步重复的工作树,而且还必须显式地同步工作树的更多副本,以启用任何整个项目的测试,而不必发布(如上所述)要发布的每个版本测试.

but this has the disadvantage that you'll have to explicitly synchronize not just the duplicate worktrees but also more copies of the worktrees to enable any whole-project tests without having to publish (as above) every version you're going to test.

也许这只是一种精神状态的事情,但是这种方式显得笨拙得难以管理,我认为这不值得追求.

Maybe it's just a mental-state thing, but this way looks enough clunkier to administer that I don't think it's worth pursuing.

随机注释:

  • git clean -dfx不会清除嵌套存储库的工作树,当它有用时,git显然只会忽略嵌套的.git.唔.这可能会以有用的方式被滥用.

  • git clean -dfx doesn't clean out the worktrees of the nested repos, git apparently only ignores the nested .gits when it's useful. Hmm. This could be abused in useful ways.

如果要保护嵌入式存储库免受随机rm -rf sect3的侵害,可以使用git submodule所使用的方法

If you want to protect your embedded repositories from random rm -rf sect3's you can use the method git submodule uses,

mv .git /someplace/safer
echo gitdir: /someplace/safer >.git

和核弹之后的重建是mkdir -pecho

and reconstruction after the nuke is mkdir -p and echo

  • 有人可能会找到一种更优雅的方式来进行此操作,如果这样,我希望至少可以很快看到它的草图;我在上面没有看到任何内容,但是我确实倾向于过度设计地狱,然后将其全部煮沸.

1 在这里查看有关教会我这是可能的问题

2 事实证明,git clean确实可以识别嵌套存储库,并且不会对其进行清理.因此git clean -dfx仍然是安全的. 更多有用的行为:-)

2 It turns out that git clean does recognize the nested repositories, and doesn't clean them. So git clean -dfx is still safe. More useful behavior :-)

这篇关于如何跟踪修订历史记录的修订历史记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆