git-diffall — 一键输出完整工作区 diff

显示原文

git-diffall.rb

#!/USR/bin/env Ruby
# frozen_string_literal:真
# git-diffall - 一个列表中工作树的完整差异。
# 行为重复了bash版本;完整的帮助是持续的GitDiffAll::HELP。
要求“open3”
模块 GitDiffAll
帮助 = <<~文本
git-diffall 是工作树的完整差异,仅有一份列表:
* 跟踪文件变更(未分阶段:仅工作树 vs 索引)
* 未追踪统一差分文件内容
分阶段的变更不是输出。仓库的状态不会改变。
使用:git diffall [--stat] [-- ...]
--仅统计数据(按文件+/-)
...将输出限制在这些路径上
所有取款均通过ONE Pager(${PAGER:-less});重定向时
To file/pipe — 寻呼器不运行,只显示纯文本。
文本
# 求助 (-h/--求助)。
类帮助请求<标准错误;结束
# 不是git仓库。
class NotGitRepositoryError < StandardError;结束
# 解析命令行参数。
职业选项
attr_reader :p aths
def initialize(stat: false, paths: [])
@stat = 统计
@paths = 路径
结束
防御属性?
@stat
结束
def self.parse(argv)
统计 = 错误
路径 = []
args = argv.dup
直到 args.empty 为止?
case args.shift
当“--stat”时,stat = true。
当“-h”, “--help”时,则提出HelpRequested
当“——”
paths.concat(args)
args.clear(args.clear)
否则
路径<< args.first
结束
结束
新(属性:属性,路径:路径)
结束
结束
# 薄包装盖在git上:所有电话都没有自己的寻呼机,颜色都包含在内
# 强制,只有当输出通过 git 管道到达终端时才会被强制
# 关闭)。git命令的非零退出状态不是错误(diff 表示
# “存在差异”),因此不被检查,stderr 被转发到终端。
Git 类
def initialize(force_color:, stderr: $stderr)
@force_color = force_color
@stderr = stderr
结束
DEF 仓库?
system(*base_args,'rev-parse','--git-dir',输出:File::NULL,呃:File::NULL)
结束
# 跟踪文件的变更:工作树与索引(无分阶段)。
防御tracked_diff(路径)
run('diff', *selection(paths))
结束
def tracked_stat(路径)
run('diff', '--stat', *selection(paths))
结束
# 未追踪文件(忽略文件除外),NUL分隔符——
#适用于所有名字,包括换行。
def untracked_files(paths)
out, = Open3.capture3(*base_args, 'ls-files', '--others', '--exclusion-standard',
'-z', *selection(paths))
out.split(“\x0”).reject(&:empty?)
结束
# 一个未追踪文件的差异 vs. /dev/null(对于 git,它是“空文件”;
# Linux上的File::NULL与“/dev/null”相同)。
def untracked_diff(路径)
run('diff', '--no-index', File::NULL, path)
结束
私人
绝对base_args
args = ['git', '--no-pager']
如果 args.push('-c', 'color.diff=always') @force_color
args
结束
DEF 选择(路径)
paths.empty??[] : ['--', *路径]
结束
def run(*)
stdout, stderr, = Open3.capture3(*base_args, *)
@stderr.write(stderr) 除非 stderr.empty?
学生
结束
结束
# 输出的“正体”:跟踪文件部分 + 未跟踪文件部分。
# 子类指定各节的内容和分隔符(模板方法)。
车级体
def initialize(git:, paths:)
@git = git
@paths = 路径
结束
def渲染
([tracked_section] + untracked_sections).join(分隔符) + 终结符
结束
私人
def分隔符
''
结束
# 整个输出的尾串(DiffBody 为空)。
《终结者》
''
结束
绝对tracked_section
提高 NotImplementedError
结束
绝对untracked_sections
提高 NotImplementedError
结束
结束
# 全差值:git diff + 每个未追踪文件一个统一差值。
类 DiffBody < Body
私人
绝对tracked_section
@git.tracked_diff(@paths)
结束
绝对untracked_sections
@git.untracked_files(@paths).map { |file| @git.untracked_diff(file) }
结束
结束
# 统计:git diff --stat + 未追踪文件的行计数器。
# 段 — 无尾线线的字符串:分隔符和终止符
# 将“拼接”设置得完全像 bash(printf 加 \n + 回声)。
类别 StatBody < Body
私人
def分隔符
“\n”
结束
《终结者》
“\n”
结束
绝对tracked_section
@git.tracked_stat(@paths)
结束
绝对untracked_sections
@git.untracked_files(@paths).map do |file|
format(' %s | %d ++++', file: file, count: line_count(file))
结束
结束
def line_count(文件)
File.foreach(file).count
结束
结束
# 整个撤退时间只需一页;当重定向到文件/管道时,它不会启动。
模块寻呼器
延伸自我
绝对是互动式的吗?
$stdout.tty?
结束
防御指挥
寻呼机 = ENV['GIT_PAGER'] ||ENV['寻呼'] ||“更少”
寻呼机 == '更少'?“less -FRX”:寻呼机
结束
def write(output)
IO.popen(命令,'w') { |io| io.write(output) }
救援 Errno::EPIPE,Errno::ENOENT,Errno::EACCES
# 寻呼机提前关闭(q)或未找到——如bash '||“正确”,
# 这不是虫子。
结束
结束
# 编排:仓库验证、参数解析、输出收集、分页器。
类CLI
def initialize(argv,标准:$stdout,stderr:$stderr)
@argv = argv
@stdout = 学生
@stderr = stderr
结束
def run(防御奔跑)
git =Git.new(force_color:Pager.interactive?)
除非git.repository,否则会提出NotGitRepositoryError吗?
options = options.parse(@argv)
正文 = if options.stat?
StatBody.new(git:git,paths: options.paths)
否则
DiffBody.new(git:git,paths: options.paths)
结束
如果 Pager.interactive?
Pager.write(body.render)
否则
@stdout.write(body.render)
结束
0
救援请求帮助
@stdout.write(帮助)
0
rescue NotGitRepositoryError
@stderr.puts('git-diffall: не git-репозиторий')
1
结束
结束
结束
# 脚本在Rails应用之外,因此此处退出为合适。
退出 GitDiffAll::CLI.new(ARGV).run # rubocop:disable Rails/Exit
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论