在另一个mercurial repo中拥有.hg目录时的Git样式行为 - 可能吗?

时间:2015-06-26 21:44:05

标签: mercurial

我更喜欢Mercurial的一致命令行,但git有一个我非常想念的功能:

Mercurial可以忽略子目录中的.hg文件夹,以便跟踪其下的所有文件'通常'?

  

使用git可以 ,甚至不需要特殊的开关!

编辑:有点可悲,因为只是询问这个特征是否也存在于merc中而被人贬低。

详细说明:

当前行为

一旦在树中创建.hg目录,Mercurial就会停止跟踪其容器目录中的所有内容,默认情况下将其视为另一个独立管理的仓库:

/tmp$ mkdir -p a/b/c/ && touch a/b/c/foo && hg init a && cd a && hg status
? b/c/foo
/tmp/a$ mkdir b/.hg && hg status
/tmp/a$ 

Merc的。现在认为,./b文件夹的存在会导致.hg内的所有回复跟踪。 但我可以关掉它吗?即使我明确忽略b/.hg

/tmp/a$ echo -e "syntax: glob\nb/.hg*" > .hgignore
/tmp/a$ hg status
? .hgignore

主要仓库不再跟踪./b以下。

我希望在a内跟踪a/.hg以下的所有文件,无论是否有人在其中创建了.hg文件夹。

GIT中:

/tmp$ mkdir -p a/b/c/ && touch a/b/c/foo && \
        git init a && cd a && git add -A &&  git status
Initialized empty Git repository in /tmp/a/.git/
#   new file:   b/c/foo
/tmp/a$ git init b
Initialized empty Git repository in /tmp/a/b/.git/
/tmp/a$ git status
#   new file:   b/c/foo   # <- still tracked.

```

两个潜在用例

声明: 评论表明仅仅在这些用例中提供的信息不足以证明我的问题所要求的特征:对于案例A和B,子目录 COULD 是正确的答案(绝对不在我的具体情况虽然)。 我仍然留下用例,以便演示目录结构,但我请。请注意这篇文章的主要问题。

A)一个大型项目中不同的提交目的,间隔,期限,政策,技能:

Juniors/Partners                      Seniors, Admins
 contribute to subdir(s)              overlook the whole project
  |                                   |
  |                                   |
  |             LargeProject/         |
  |             ├── .hg <------------ 'official' commits
  |             ├── conf              high quality, customer tracks,
  |             ├── lib               show up in release notes.
  |             ├── (...)
  |             └── frontend,contrib,...
  └-freq. commits-> └── .hg
    of frontend     └── js
    stuff           └── css
                    └── (...)
  • 该项目一般是成熟稳定的,但在某些时期,在不属于关键部分的工作发生在子目录中,只有在贡献者放弃之后,才会显示为正式提交。
  • 这样处理的部分会随着时间的推移而发生变化,而且事先并不知道。
  • 出于拓扑原因,所有工作都发生在DEV中的一台机器或客户的暂存区域。
  • 不时标记推送到中央仓库转移到(预)生产。

如果另一个VCS将用于合作伙伴的东西(在全局仓库中忽略其元文件),它将全部按预期工作 - 除了我想使用(并解释和训练)Mercurial仅适用于所有贡献。

B)仅使用hg 作为文件系统更改跟踪工具 - 在项目仓库中。

在我的hg项目目录中,我有一个子目录,包含对象数据库的转储文件作为项目的组成部分。

现在我希望在这个目录中使用hg ,用于它的一些跟踪功能(基本上用于跟踪OODB中的事务并能够将文件系统上的更改推回到它中,也许合并后)。我需要经常在这里提交 - 但是不要用那些来破解官方项目回购的历史。

问题在于:我在那里运行一个hg init,外面的主要仓库停止跟踪目录。

我不想提及subrepos,因为我真的没有在那里推或拉任何东西,因为它只是为了本地OODB变化跟踪。另外,我不想要caveats subrepos,因为我需要子目录中的跟踪功能,包括。自动提交。

我当前的工作是使用如图所示的git,这样主要的repo会显示OODB的任何更改,就像项目的任何其他文件一样:

my_project/
├── .hg   #  Main project repo, 'offical commits'
├── conf  # 'Normal' project repo folders
├── lib
└── zodb  # Containing OODB dumps
    ├── .git        # Repo to auto track transactions of the OODB,
    └── zodb_root   # frequently dumped within this directory, and
        └── tenant1 # often committed, for diffing / merging reasons.  

但是我真的很想使用.hg以及内部跟踪仅仅跟踪&#39;目录也是如此。

最简单的解决方案是,如果我可以配置mercurial来忽略OODB目录中的.hg。尝试使用非共享的bindmounts,但单独使用空的mountpoint目录就足以让hg拒绝查看该目录。

有什么想法吗?一个简单的解决方案是,如果Mercurial在全局.hgignore中尊重* .hg,就像它对* .git一样 - 但它没有。

3 个答案:

答案 0 :(得分:0)

我发现它是如何完成的:

对于subrepo,您​​可以在任意位置创建一个repo,并将符号链接y = expr ? true : y; // expr is always evaluated. 文件创建到您要进行独立跟踪的子目录中:

.hg

- &GT;现在可以独立跟踪/tmp$ mkdir -p a/b/c/ && touch a/b/c/foo && hg init a && cd a && hg status ? b/c/foo /tmp/a$ mkdir b/sub && hg init b/sub && ln -s /tmp/a/b/sub/.hg /tmp/a/b/.hg /tmp/a$ cd b && hg add * && hg commit -m subcommit && hg status adding c/foo committing files: c/foo (...) /tmp/a/b$ hg status /tmp/a/b$ cd .. /tmp/a$ hg status ? b/.hg ? b/c/foo 内的变化,同时仍然可以在#{1}}范围内进行更改。 a/b中的主要回购: - )

答案 1 :(得分:0)

独立是否跟踪数据库是一个好主意:您在示例A)中显示的结构,但OODB也要求正确使用子存储库,而不是需要提交整个.hg目录。父存储库记录子存储库的状态,因此父级的提交也可以更新到子存储库的新(呃)版本。

通过父目录中的任何方式跟踪.hg目录绝对是一个非常糟糕的主意。

答案 2 :(得分:0)

使用.hg符号链接愚弄mercurial的解决方案,指向实际的merc目录有一个缺点: 人们意外地将.hg符号链接检查到主回购中,然后发生多维混乱。嵌套的.hg永远不应该变成变更集!

仍然我个人不能接受训练所有人在mercurial(抛弃git爱好者,默认情况下给你这个特定功能)然后切换到git自己,因为嵌套的本地目录状态mgmt不起作用。

所以我决定修补mercurial本身的路径。 对于处于相同情况的每个人,如果设置了环境变量$ HG_OVERWRITE_SKIP,那么在修补程序明显缺点的情况下,这是一个笨拙但有效的覆盖默认值。

注意:当设置了environ var时,这很可能不再允许使用subrepos,这与我无关。

HG版本:3.4.1。

7.oodblogd.DEV.NB01:/agent/lib/python2.7/site-packages/mercurial# hg diff .
diff -r 0548c0ff6c76 lib/python2.7/site-packages/mercurial/dirstate.py
--- a/lib/python2.7/site-packages/mercurial/dirstate.py Mon Jul 27 00:05:50 2015 +0000
+++ b/lib/python2.7/site-packages/mercurial/dirstate.py Thu Jul 30 22:16:39 2015 +0000
@@ -16,6 +16,12 @@

 dirstatetuple = parsers.dirstatetuple

+# AX: making hg NOT ignore dirs with a nested .hg via this environ flag,
+# which you set when you want to track nested dirs:
+nested_hg_skip_match = '.hg'
+if os.environ.get('HG_OVERWRITE_SKIP'):
+    nested_hg_skip_match = '.no_match_hg'
+
 class repocache(filecache):
     """filecache for files in .hg/"""
     def join(self, obj, fname):
@@ -772,7 +778,7 @@
                 if nd == '.':
                     nd = ''
                 else:
-                    skip = '.hg'
+                    skip = nested_hg_skip_match
                 try:
                     entries = listdir(join(nd), stat=True, skip=skip)
                 except OSError, inst:
diff -r 0548c0ff6c76 lib/python2.7/site-packages/mercurial/pathutil.py
--- a/lib/python2.7/site-packages/mercurial/pathutil.py Mon Jul 27 00:05:50 2015 +0000
+++ b/lib/python2.7/site-packages/mercurial/pathutil.py Thu Jul 30 22:16:39 2015 +0000
@@ -4,6 +4,13 @@
 import util
 from i18n import _

+# AX: making hg NOT ignore dirs with a nested .hg via this environ flag,
+# which you set when you want to track nested dirs:
+nested_hg_skip_match = '.hg'
+if os.environ.get('HG_OVERWRITE_SKIP'):
+    nested_hg_skip_match = '.no_match_hg'
+
+
 def _lowerclean(s):
     return encoding.hfsignoreclean(s.lower())

@@ -43,7 +50,7 @@
             raise util.Abort(_("path ends in directory separator: %s") % path)
         parts = util.splitpath(path)
         if (os.path.splitdrive(path)[0]
-            or _lowerclean(parts[0]) in ('.hg', '.hg.', '')
+            or _lowerclean(parts[0]) in (nested_hg_skip_match, '.hg.', '')
             or os.pardir in parts):
             raise util.Abort(_("path contains illegal component: %s") % path)
         # Windows shortname aliases
@@ -55,7 +62,7 @@
                                      % path)
         if '.hg' in _lowerclean(path):
             lparts = [_lowerclean(p.lower()) for p in parts]
-            for p in '.hg', '.hg.':
+            for p in nested_hg_skip_match, '.hg.':
                 if p in lparts[1:]:
                     pos = lparts.index(p)
                     base = os.path.join(*parts[:pos])
@@ -87,7 +94,7 @@
                         _('path %r traverses symbolic link %r')
                         % (path, prefix))
                 elif (stat.S_ISDIR(st.st_mode) and
-                      os.path.isdir(os.path.join(curpath, '.hg'))):
+                      os.path.isdir(os.path.join(curpath, nested_hg_skip_match))):
                     if not self.callback or not self.callback(curpath):
                         raise util.Abort(_("path '%s' is inside nested "
                                            "repo %r")
(END)