Index: google3/third_party/llvm/llvm/tools/clang/tools/clang-format/git-clang-format =================================================================== --- google3/third_party/llvm/llvm/tools/clang/tools/clang-format/git-clang-format +++ google3/third_party/llvm/llvm/tools/clang/tools/clang-format/git-clang-format @@ -33,11 +33,12 @@ import subprocess import sys -usage = 'git clang-format [OPTIONS] [] [] [--] [...]' +usage = ('git clang-format [OPTIONS] [] [|--staged] ' + '[--] [...]') desc = ''' -Run clang-format on all modified lines in the working directory or in a given -commit. +Run clang-format on all modified lines in the working directory, in a given +commit, or in the stage/index. Forms: @@ -57,6 +58,10 @@ Run clang-format on all lines in that differ from . Requires --diff. + git clang-format [] --staged --diff + Run clang-format on all lines in the git stage/index that differ from + , which defaults to HEAD. Requires --diff. + In all of the forms above, ... can be used to limit what files are affected, using the same syntax as `git diff`. Use `--` to disambiguate between files and commits. @@ -126,6 +131,8 @@ help='select hunks interactively') p.add_argument('-q', '--quiet', action='count', default=0, help='print less information') + p.add_argument('--staged', '--cached', action='store_true', + help='format lines in the stage instead of the working dir') p.add_argument('--style', default=config.get('clangformat.style', None), help='passed to clang-format'), @@ -144,7 +151,10 @@ del opts.quiet source, dest, files = interpret_args(opts.args, dash_dash, - default_commit=opts.commit) + default_commit=opts.commit, + staged=opts.staged) + if isinstance(dest, Stage) and not opts.diff: + die('--diff is required when --staged is used') if isinstance(dest, Revision) and not opts.diff: die('--diff is required when two commits are given') changed_lines = dest.compute_diff_from(source, files) @@ -207,7 +217,7 @@ return out -def interpret_args(args, dash_dash, default_commit): +def interpret_args(args, dash_dash, default_commit, staged): """Interpret `args` as "[commits] [--] [files]" and return (src, dest, files). It is assumed that "--" and everything that follows has been removed from @@ -252,7 +262,11 @@ if len(commits) > 2: die('at most two commits allowed; %d given' % len(commits)) elif len(commits) == 2: + if staged: + die('--staged is not allowed when two commits are given') return Revision(commits[0]), Revision(commits[1]), files + elif staged: + return Revision(commits[0]), Stage(), files else: return Revision(commits[0]), Workdir(), files @@ -283,7 +297,7 @@ class TreeLocation (object): - """Represents either a commit or the working directory. + """Represents either a commit, the stage, or the working directory. Do not use this directly. Instead, use one of the subclasses.""" @@ -439,6 +453,24 @@ is_workdir = True +class Stage (TreeLocation): + """Represents the git stage, a.k.a. the index.""" + + def create_tree(self, unused_filenames): + return run('git', 'write-tree') + + def _file_mode(self, filename): + stdout = run('git', 'ls-files', '--stage', filename) + # note: there is an optional as the first element. + return int(stdout.split()[-4], 8) + + def _compute_diff_from_base_command(self, source): + return ['git', 'diff-index', '-p', '-U0', '--cached', source.revision] + + def _blob_name(self, filename): + return ':%s' % filename + + class Revision (TreeLocation): """Represents a specific revision, a.k.a. a commit."""