lodato created this revision.
lodato added reviewers: djasper, klimek, Alexander-Shukaev.

This new mode, which requires --diff, operates very similarly to the two 
<commit> mode, except that the stage is formatted instead of the second commit.

The main intent of this feature is to use in pre-commit hooks so that you can 
ensure that all commits are properly formatted. Without this, the commit hook 
would have to format the working directory which is not necessarily what will 
be committed.

This mode requires --diff because otherwise there would be no place for the 
update to be written to: writing to the index would blow away changes, and 
writing to the working directory would be incorrect in case the working 
directory differs from the index.

Note: this patch was forked from https://reviews.llvm.org/D15465.

Testing of all three modes:

  # setup
  $ mkdir tmp
  $ cd tmp
  $ git init
  $ cat > foo.cc
  int main() {
    int x =  1;
    return 0;
  }
  EOF
  $ git add foo.cc
  $ git commit -m 'initial commit'
  $ rm foo.cc
  $ cat > foo.cc
  int main() {
    int x =  1;
    int y =  2;
    int z =  3;
    return 0;
  }
  EOF
  $ git add foo.cc
  $ git commit -m 'commit 2'
  $ sed -i -e 's/1;/10;/' foo.cc
  $ git add foo.cc
  $ sed -i -e 's/10;/1;/' foo.cc
  $ sed -i -e 's/3;/30;/' foo.cc
  
  $ git-clang-format --diff
  diff --git a/foo.cc b/foo.cc
  index cb2dbc9..2e1b0e1 100644
  --- a/foo.cc
  +++ b/foo.cc
  @@ -1,6 +1,6 @@
   int main() {
     int x =  1;
     int y =  2;
  -  int z =  30;
  +  int z = 30;
     return 0;
   }
  $ git-clang-format --diff --staged
  diff --git a/foo.cc b/foo.cc
  index 3ea8c6c..7da0033 100644
  --- a/foo.cc
  +++ b/foo.cc
  @@ -1,5 +1,5 @@
   int main() {
  -  int x =  10;
  +  int x = 10;
     int y =  2;
     int z =  3;
     return 0;
  $ git-clang-format --diff HEAD~ HEAD
  diff --git a/foo.cc b/foo.cc
  index 7bfdb83..ce6f65e 100644
  --- a/foo.cc
  +++ b/foo.cc
  @@ -1,6 +1,6 @@
   int main() {
     int x =  1;
  -  int y =  2;
  -  int z =  3;
  +  int y = 2;
  +  int z = 3;
     return 0;
   }




https://reviews.llvm.org/D41147

Files:
  google3/third_party/llvm/llvm/tools/clang/tools/clang-format/git-clang-format

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] [<commit>] [<commit>] [--] [<file>...]'
+usage = ('git clang-format [OPTIONS] [<commit>] [<commit>|--staged] '
+         '[--] [<file>...]')
 
 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 <commit2> that differ from <commit1>.
         Requires --diff.
 
+    git clang-format [<commit>] --staged --diff
+        Run clang-format on all lines in the git stage/index that differ from
+        <commit>, which defaults to HEAD. Requires --diff.
+
 In all of the forms above, <file>... 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
@@ -250,7 +260,11 @@
 
   assert len(commits) != 0
   if 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
 
@@ -281,7 +295,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."""
 
@@ -437,6 +451,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 <tag> 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."""
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to