[PATCH] D90996: [clang-format] Add --staged/--cached option to git-clang-format

Erik Larsson via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 6 23:00:58 PST 2020


ortogonal created this revision.
ortogonal added reviewers: klimek, Alexander-Shukaev, djasper.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
ortogonal requested review of this revision.

When running git-clang-format in a pre-commit hook it's very useful to be able to tell git-clang-format to only look at the --staged/--cached files and not the working directory.

Note this patch is a rebase/fork from D41147 <https://reviews.llvm.org/D41147> which is a fork of D15465 <https://reviews.llvm.org/D15465>

This is tested with:

  mkdir /tmp/gcfs
  cd /tmp/gcfs
  
  git init
  
  cat <<EOF > foo.cc
  int main() {
    int x =  1;
    return 0;
  }
  EOF
  
  git add foo.cc
  git commit -m 'first commit'
  rm foo.cc
  
  cat <<EOF > foo.cc
  int main() {
    int x =  1;
    int y =  2;
    int z =  3;
    return 0;
  }
  EOF
  
  git add foo.cc
  git commit -m 'second commit'
  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;
   }


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D90996

Files:
  clang/tools/clang-format/git-clang-format


Index: clang/tools/clang-format/git-clang-format
===================================================================
--- clang/tools/clang-format/git-clang-format
+++ clang/tools/clang-format/git-clang-format
@@ -32,12 +32,13 @@
 import subprocess
 import sys
 
-usage = 'git clang-format [OPTIONS] [<commit>] [<commit>] [--] [<file>...]'
+usage = ('git clang-format [OPTIONS] [<commit>] [<commit>|--staged] '
+         '[--] [<file>...]')
 
 desc = '''
 If zero or one commits are given, run clang-format on all lines that differ
 between the working directory and <commit>, which defaults to HEAD.  Changes are
-only applied to the working directory.
+only applied to the working directory, or in the stage/index.
 
 If two commits are given (requires --diff), run clang-format on all lines in the
 second <commit> that differ from the first <commit>.
@@ -109,6 +110,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'),
@@ -128,12 +131,14 @@
 
   commits, files = interpret_args(opts.args, dash_dash, opts.commit)
   if len(commits) > 1:
+    if opts.staged:
+      die('--staged is not allowed when two commits are given')
     if not opts.diff:
       die('--diff is required when two commits are given')
   else:
     if len(commits) > 2:
       die('at most two commits allowed; %d given' % len(commits))
-  changed_lines = compute_diff_and_extract_lines(commits, files)
+  changed_lines = compute_diff_and_extract_lines(commits, files, opts.staged)
   if opts.verbose >= 1:
     ignored_files = set(changed_lines)
   filter_by_extension(changed_lines, opts.extensions.lower().split(','))
@@ -268,9 +273,9 @@
   return convert_string(stdout.strip())
 
 
-def compute_diff_and_extract_lines(commits, files):
+def compute_diff_and_extract_lines(commits, files, staged):
   """Calls compute_diff() followed by extract_lines()."""
-  diff_process = compute_diff(commits, files)
+  diff_process = compute_diff(commits, files, staged)
   changed_lines = extract_lines(diff_process.stdout)
   diff_process.stdout.close()
   diff_process.wait()
@@ -280,17 +285,20 @@
   return changed_lines
 
 
-def compute_diff(commits, files):
+def compute_diff(commits, files, staged):
   """Return a subprocess object producing the diff from `commits`.
 
   The return value's `stdin` file object will produce a patch with the
-  differences between the working directory and the first commit if a single
+  differences between the working/cached directory and the first commit if a single
   one was specified, or the difference between both specified commits, filtered
   on `files` (if non-empty).  Zero context lines are used in the patch."""
   git_tool = 'diff-index'
+  extra_args = []
   if len(commits) > 1:
     git_tool = 'diff-tree'
-  cmd = ['git', git_tool, '-p', '-U0'] + commits + ['--']
+  elif staged:
+    extra_args += ['--cached']
+  cmd = ['git', git_tool, '-p', '-U0'] + extra_args + commits + ['--']
   cmd.extend(files)
   p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
   p.stdin.close()


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D90996.303617.patch
Type: text/x-patch
Size: 3428 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20201107/50ef8409/attachment-0001.bin>


More information about the cfe-commits mailing list