Bzr 技巧与窍门:diff -p

我不知道你怎么样,但我喜欢 diff -p [1]。 我已经使用它多年,可以像阅读文本一样阅读这些 diff,而没有 -p 的 diff 通常需要将原始文件并排打开,才能获得足够的上下文。

非常喜欢 diff -p,我想让它无处不在(邪恶的笑声)。唉,在 bzr 中只有 diff 命令可以轻松使用 -p,只需运行 bzr diff --diff-options=-p 或将其存储为 ~/.bazaar/bazaar.conf 中的别名即可。

实际上,对于别名来说,有一个更好、虽然更冗长的替代方案

[ALIASES]
diff = "diff --diff-options='-F ^[[:alpha:]$_].*[^:]$'"

与简单的 -p 不同,它不会认为以分号结尾的单词(例如标签,或者像 public:private: 这样的词)是一个“C 函数名”。

但问题是——只有 bzr diff 可以这样调整。Bzr email 插件仍然发送没有函数名的 diff。并且 bzr gdiff 也不显示它们。当然,所有其他 bzr 命令——例如 bzr commitbzr shelvebzr unshelve --previewbzr log --show-diff 等等——它们仍然和以前一样不友好。

我一直在逐个解决这个问题——给 bzr-email 插件添加了 post_commit_diffoptions 配置选项,然后给 bzr gdiff 添加了命令行选项。但后来我想到,我可以从根本上解决这个问题!

这就是解决方法:获取这段 python 代码 [2],将其保存为文件 ~/.bazaar/plugins/diffoptions/__init__.py。然后你可以添加,例如,

diff_options = -u -F ^[[:alpha:]$_].*[^:]$

到你的 bazaar.conf 文件中,它将神奇地改变一切。所有生成 diff 的 bzr 命令、bzr 插件——都会使用这些选项,你可以在所有的 diff 块上看到漂亮的 C 函数名,无论它们是由哪个插件或核心 bzr 命令生成的。

尽情享受吧!

我想知道 bzr 的开发者是否愿意将其作为一个核心功能。他们可以做得更好,不需要像我这样不得不求助于技巧。


1) 如果你之前没有听说过它,**-p** 选项会为每个 **diff** 块添加 C 函数名

=== modified file 'sql-common/my_time.c'
--- sql-common/my_time.c        2010-08-27 14:12:44 +0000
+++ sql-common/my_time.c        2011-02-28 21:24:19 +0000
@@ -727,6 +727,9 @@ void my_init_time(void)
   my_time.hour=                (uint) l_time->tm_hour;
   my_time.minute=      (uint) l_time->tm_min;
   my_time.second=      (uint) l_time->tm_sec;
+  my_time.neg=          0;
+  my_time.second_part=  0;
+  my_time.time_type=    MYSQL_TIMESTAMP_DATETIME;
   my_system_gmt_sec(&my_time, &my_time_zone, &not_used);
 }

2) 这是 **bzr diffoptions** 插件的完整代码。它在 **bzr 2.2.4** 上对我有效,但我没有在其他 bzr 版本上试过。

#!/usr/bin/env python

"""global bzr diff options"""

version_info = (0, 0, 1)

from bzrlib import branch
from bzrlib import diff
from bzrlib import errors

def get_differ(tree):
  try:
    root = tree.id2path(tree.get_root_id())
    br = branch.Branch.open_containing(root)[0]
    diff_options = br.get_config().get_user_option('diff_options')
    if diff_options is not None:
      opts = diff_options.split()
      def diff_file(olab, olines, nlab, nlines, to_file, path_encoding=None):
          diff.external_diff(olab, olines, nlab, nlines, to_file, opts)
      return diff_file
  except (errors.NoSuchId, NotImplementedError):
    pass
  return None

old_init = diff.DiffText.__init__

def new_init(self, old_tree, new_tree, to_file, path_encoding='utf-8',
    old_label='', new_label='', differ=diff.internal_diff):

  if differ == diff.internal_diff:
    differ = get_differ(old_tree) or get_differ(new_tree) or diff.internal_diff

  old_init(self, old_tree, new_tree, to_file, path_encoding,
      old_label, new_label, differ)

diff.DiffText.__init__ = new_init