Index: git-clang-format =================================================================== --- git-clang-format +++ git-clang-format @@ -101,6 +101,8 @@ help='allow changes to unstaged files') p.add_argument('-p', '--patch', action='store_true', help='select hunks interactively') + p.add_argument('-s', '--staged', action='store_true', + help='consider only staged lines') p.add_argument('-q', '--quiet', action='count', default=0, help='print less information') p.add_argument('--style', @@ -121,7 +123,7 @@ del opts.quiet commit, files = interpret_args(opts.args, dash_dash, opts.commit) - changed_lines = compute_diff_and_extract_lines(commit, files) + changed_lines = compute_diff_and_extract_lines(commit, files, opts.staged) if opts.verbose >= 1: ignored_files = set(changed_lines) filter_by_extension(changed_lines, opts.extensions.lower().split(',')) @@ -141,7 +143,10 @@ # The computed diff outputs absolute paths, so we must cd before accessing # those files. cd_to_toplevel() - old_tree = create_tree_from_workdir(changed_lines) + if opts.staged: + old_tree = run_git_ls_files_and_save_to_tree(changed_lines) + else: + old_tree = create_tree_from_workdir(changed_lines) new_tree = run_clang_format_and_save_to_tree(changed_lines, binary=opts.binary, style=opts.style) @@ -242,9 +247,9 @@ return stdout.strip() -def compute_diff_and_extract_lines(commit, files): +def compute_diff_and_extract_lines(commit, files, cached=False): """Calls compute_diff() followed by extract_lines().""" - diff_process = compute_diff(commit, files) + diff_process = compute_diff(commit, files, cached) changed_lines = extract_lines(diff_process.stdout) diff_process.stdout.close() diff_process.wait() @@ -254,13 +259,16 @@ return changed_lines -def compute_diff(commit, files): +def compute_diff(commit, files, cached=False): """Return a subprocess object producing the diff from `commit`. The return value's `stdin` file object will produce a patch with the differences between the working directory and `commit`, filtered on `files` (if non-empty). Zero context lines are used in the patch.""" - cmd = ['git', 'diff-index', '-p', '-U0', commit, '--'] + cmd = ['git', 'diff-index'] + if cached: + cmd.append('--cached') + cmd.extend(['-p', '-U0', commit, '--']) cmd.extend(files) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.stdin.close() @@ -317,6 +325,30 @@ return create_tree(filenames, '--stdin') +def run_git_ls_files_and_save_to_tree(changed_lines): + """Run git ls-files and save the result to a git tree. + + Returns the object ID (SHA-1) of the created tree.""" + index_path = os.environ.get('GIT_INDEX_FILE') + def index_info_generator(): + for filename, line_ranges in changed_lines.iteritems(): + old_index_path = os.environ.get('GIT_INDEX_FILE') + if index_path is None: + del os.environ['GIT_INDEX_FILE'] + else: + os.environ['GIT_INDEX_FILE'] = index_path + try: + mode, id, stage, filename = run('git', 'ls-files', '--stage', '--', + filename).split() + yield '%s %s\t%s' % (mode, id, filename) + finally: + if old_index_path is None: + del os.environ['GIT_INDEX_FILE'] + else: + os.environ['GIT_INDEX_FILE'] = old_index_path + return create_tree(index_info_generator(), '--index-info') + + def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format', style=None): """Run clang-format on each file and save the result to a git tree.