Mercurial cat命令使用--include

时间:2017-05-27 22:31:21

标签: version-control mercurial

使用Mercurial的4.1.1版本,我想提供一个文件,将一堆文件指定为hg cat命令的args,以便将每个文件输出到不同的文件。我认为以下内容可行:

hg cat -o 'catOut-%s' --include listfile:files.lst 

其中files.lst看起来像这样

foo01.txt
foo02.txt

但它会产生一条错误消息,说“无效参数”加上一条用法消息。

这是一个MWE,它使用所需的结构设置代码存储库,然后尝试运行上面显示的cat命令。

hg init mwe
cd mwe
echo abc > foo01.txt
echo def > foo02.txt
echo PQR > baz.txt
echo files.lst > .hgignore
hg add .hgignore
hg add foo*.txt
hg add baz.txt
echo foo01.txt >> files.lst
echo foo02.txt >> files.lst
hg ci -m "Adding all files"
hg cat -o 'catOut-%s' baz.txt
cat catOut-baz.txt
rm catOut*
hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt
cat catOut-baz.txt
hg cat -o 'catOut-%s' --include listfile:files.lst 

以下是这些命令的跟踪及其在shell中输入的结果:

~/tmp $ hg init mwe
~/tmp $ cd mwe
~/tmp/mwe $ echo abc > foo01.txt
~/tmp/mwe $ echo def > foo02.txt
~/tmp/mwe $ echo PQR > baz.txt
~/tmp/mwe $ echo files.lst > .hgignore
~/tmp/mwe $ hg add .hgignore
~/tmp/mwe $ hg add foo*.txt
~/tmp/mwe $ hg add baz.txt
~/tmp/mwe $ echo foo01.txt >> files.lst
~/tmp/mwe $ echo foo02.txt >> files.lst
~/tmp/mwe $ hg ci -m "Adding all files"
~/tmp/mwe $ hg cat -o 'catOut-%s' baz.txt
~/tmp/mwe $ cat catOut-baz.txt
cat catOut-baz.txt
PQR
~/tmp/mwe $ rm catOut*
rm catOut*
~/tmp/mwe $ hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt
~/tmp/mwe $ cat catOut-baz.txt
cat: catOut-baz.txt: No such file or directory
~/tmp/mwe $ hg cat -o 'catOut-%s' --include listfile:files.lst 
hg cat -o 'catOut-%s' --include listfile:files.lst 
hg cat: invalid arguments
hg cat [OPTION]... FILE...

output the current or given revision of files

options ([+] can be repeated):

 -o --output FORMAT       print output to file with formatted name
 -r --rev REV             print the given revision
--decode              apply any matching decode filter
 -I --include PATTERN [+] include names matching the given patterns
 -X --exclude PATTERN [+] exclude names matching the given patterns

(use 'hg cat -h' to show more help)
~/tmp/mwe $ 

您必须提供文件参数以避免出现错误消息。但如果提供了--include和-o,那么该参数将被忽略。

我怀疑之前没有人使用过--include cat参数,因为关于如何处理--include参数的解释很少。无论是那个还是我忽略了一些明显的东西。

1 个答案:

答案 0 :(得分:1)

  

您必须提供文件参数以避免出现错误消息。但如果提供--include-o,则会忽略该参数。

字面意思忽略。问题是--include意味着奇怪的事情。

  

...因为关于如何处理--include参数的解释很少。

情况确实如此! hg help patterns中有一个描述,但它相当不足(至少在我看来)。 --include的含义是仅使用与文件中的模式匹配的 文件。将此视为“仅包括”,而不是“也包括”。

因此,如果您的列表文件中包含这两个文件名,您可以运行,例如:

hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt foo01.txt

和Mercurial将提取foo01.txt,因为它在列表中。

您可能认为可以使用:

hg cat -o 'catOut-%s' --include listfile:files.lst '*'

但你不能(嗯,你可以在Windows上,因为hg在那里进行glob样式匹配,但这是错误的方法)。正确的诀窍是指示hg cat读取目录,即存储库的顶级目录:

hg cat .

(虽然有类似的方法,例如使用set:*;请参阅hg help filesets)。然后,由--include生成的过滤将您删除到您想要包含的文件。

正如他们在某些圈子中所说的那样,更多“颜色” - 无需阅读此内容!

(这只是我在研究这个答案时发现的一些问题。我想知道如何让hg cat扫描修订版中的每个文件,所以我投入了源代码。)

供参考,以下是实现hg cat

的Python代码片段
@command('cat',
    [('o', 'output', '',
     _('print output to file with formatted name'), _('FORMAT')),
    ('r', 'rev', '', _('print the given revision'), _('REV')),
    ('', 'decode', None, _('apply any matching decode filter')),
    ] + walkopts,
    _('[OPTION]... FILE...'),
    inferrepo=True)
def cat(ui, repo, file1, *pats, **opts):
    """output the current or given revision of files

    Print the specified files as they were at the given revision. If
    no revision is given, the parent of the working directory is used.

    Output may be to a file, in which case the name of the file is
    given using a format string. The formatting rules as follows:

    :``%%``: literal "%" character
    :``%s``: basename of file being printed
    :``%d``: dirname of file being printed, or '.' if in repository root
    :``%p``: root-relative path name of file being printed
    :``%H``: changeset hash (40 hexadecimal digits)
    :``%R``: changeset revision number
    :``%h``: short-form changeset hash (12 hexadecimal digits)
    :``%r``: zero-padded changeset revision number
    :``%b``: basename of the exporting repository

    Returns 0 on success.
    """
    ctx = scmutil.revsingle(repo, opts.get('rev'))
    m = scmutil.match(ctx, (file1,) + pats, opts)

    ui.pager('cat')
    return cmdutil.cat(ui, repo, ctx, m, '', **opts)

最关键的一行是:

def cat(ui, repo, file1, *pats, **opts):

这意味着非选项FILE...参数(如def之前的描述)与第一个file1绑定,其余参数{{1} (作为Python元组)。这会强制您传递一个或多个文件名或文件集参数。

将这些文件名参数(*pats或其他)传递给baz.txt,这就是在清单中找到指定版本的文件 - 现在{{1}中的文件由前一行调用scmutil.match得到的,它获取ctx选项中的最后一个修订版,默认为当前版本(工作目录的第一个父版本)。

处理scmutil.revsingle选项的--rev。不幸的是,这段代码非常难以理解:

scmutil.match

--include是作为命令行参数传入的非空文件名),它在m = ctx.match(pats, opts.get('include'), opts.get('exclude'), default, listsubrepos=opts.get('subrepos'), badfn=badfn) 中调用此代码:

pats

将我们带入context.py的{​​{1}}对象,这是实现def match(self, pats=None, include=None, exclude=None, default='glob', listsubrepos=False, badfn=None): if pats is None: pats = [] r = self._repo return matchmod.match(r.root, r.getcwd(), pats, include, exclude, default, auditor=r.nofsauditor, ctx=self, listsubrepos=listsubrepos, badfn=badfn) 部分的对象。这里有一点:

match.py

class match最终读取作为listfile:参数给出的文件,这就是 matchfns = [] if include: kindpats = self._normalize(include, 'glob', root, cwd, auditor) self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)', listsubrepos, root) roots, dirs = _rootsanddirs(kindpats) self._includeroots.update(roots) self._includedirs.update(dirs) matchfns.append(im) 中的内容。 (传递给self._normalize的字符串文字是正则表达式glob后缀模式,即包含文件中的文件名后跟隐含的尾部斜杠或字符串结尾。)