Skip to content

Commit

Permalink
Merge pull request #912 from asottile/intent_to_add
Browse files Browse the repository at this point in the history
Fix staged-files-only for `git add --intent-to-add` files
  • Loading branch information
asottile committed Jan 8, 2019
2 parents 2941a11 + e60579d commit 84c398d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 5 deletions.
14 changes: 14 additions & 0 deletions pre_commit/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ def get_staged_files():
)[1])


def intent_to_add_files():
_, stdout_binary, _ = cmd_output('git', 'status', '--porcelain', '-z')
parts = list(reversed(zsplit(stdout_binary)))
intent_to_add = []
while parts:
line = parts.pop()
status, filename = line[:3], line[3:]
if status[0] in {'C', 'R'}: # renames / moves have an additional arg
parts.pop()
if status[1] == 'A':
intent_to_add.append(filename)
return intent_to_add


def get_all_files():
return zsplit(cmd_output('git', 'ls-files', '-z')[1])

Expand Down
32 changes: 27 additions & 5 deletions pre_commit/staged_files_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import os.path
import time

from pre_commit import git
from pre_commit.util import CalledProcessError
from pre_commit.util import cmd_output
from pre_commit.util import mkdirp
from pre_commit.xargs import xargs


logger = logging.getLogger('pre_commit')
Expand All @@ -24,11 +26,22 @@ def _git_apply(patch):


@contextlib.contextmanager
def staged_files_only(patch_dir):
"""Clear any unstaged changes from the git working directory inside this
context.
"""
# Determine if there are unstaged files
def _intent_to_add_cleared():
intent_to_add = git.intent_to_add_files()
if intent_to_add:
logger.warning('Unstaged intent-to-add files detected.')

xargs(('git', 'rm', '--cached', '--'), intent_to_add)
try:
yield
finally:
xargs(('git', 'add', '--intent-to-add', '--'), intent_to_add)
else:
yield


@contextlib.contextmanager
def _unstaged_changes_cleared(patch_dir):
tree = cmd_output('git', 'write-tree')[1].strip()
retcode, diff_stdout_binary, _ = cmd_output(
'git', 'diff-index', '--ignore-submodules', '--binary',
Expand Down Expand Up @@ -71,3 +84,12 @@ def staged_files_only(patch_dir):
# There weren't any staged files so we don't need to do anything
# special
yield


@contextlib.contextmanager
def staged_files_only(patch_dir):
"""Clear any unstaged changes from the git working directory inside this
context.
"""
with _intent_to_add_cleared(), _unstaged_changes_cleared(patch_dir):
yield
18 changes: 18 additions & 0 deletions tests/git_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,21 @@ def test_get_conflicted_files_non_ascii(in_merge_conflict):
cmd_output('git', 'add', '.')
ret = git.get_conflicted_files()
assert ret == {'conflict_file', 'интервью'}


def test_intent_to_add(in_git_dir):
in_git_dir.join('a').ensure()
cmd_output('git', 'add', '--intent-to-add', 'a')

assert git.intent_to_add_files() == ['a']


def test_status_output_with_rename(in_git_dir):
in_git_dir.join('a').write('1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n')
cmd_output('git', 'add', 'a')
git_commit()
cmd_output('git', 'mv', 'a', 'b')
in_git_dir.join('c').ensure()
cmd_output('git', 'add', '--intent-to-add', 'c')

assert git.intent_to_add_files() == ['c']
12 changes: 12 additions & 0 deletions tests/staged_files_only_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import pytest

from pre_commit import git
from pre_commit.staged_files_only import staged_files_only
from pre_commit.util import cmd_output
from testing.auto_namedtuple import auto_namedtuple
Expand Down Expand Up @@ -339,3 +340,14 @@ def test_autocrlf_commited_crlf(in_git_dir, patch_dir):

with staged_files_only(patch_dir):
assert_no_diff()


def test_intent_to_add(in_git_dir, patch_dir):
"""Regression test for #881"""
_write(b'hello\nworld\n')
cmd_output('git', 'add', '--intent-to-add', 'foo')

assert git.intent_to_add_files() == ['foo']
with staged_files_only(patch_dir):
assert_no_diff()
assert git.intent_to_add_files() == ['foo']

0 comments on commit 84c398d

Please sign in to comment.