def diff_worktree(): modified = [] submodules = set() output = git.diff_files(z=True, with_stderr=True) if output.startswith('fatal:'): # handle git init ls_files = git.ls_files(modified=True, z=True)[:-1].split('\0') modified = [core.decode(f) for f in ls_files if f] return modified, submodules while output: rest, output = output.split('\0', 1) name, output = output.split('\0', 1) status = rest[-1] name = core.decode(name) if '160000' in rest[1:14]: submodules.add(name) elif status in 'DAM': modified.append(name) return modified, submodules
def untracked_files(git=git): """Returns a sorted list of untracked files.""" ls_files = git.ls_files(z=True, others=True, exclude_standard=True) return [core.decode(f) for f in ls_files.split('\0') if f]
def all_files(git=git): """Return the names of all files in the repository""" return [core.decode(f) for f in git.ls_files(z=True) .strip('\0').split('\0') if f]
def worktree_state_dict(head='HEAD', staged_only=False, update_index=False, git=git): """Return a dict of files in various states of being :rtype: dict, keys are staged, unstaged, untracked, unmerged, changed_upstream, and submodule. """ if update_index: git.update_index(refresh=True) if staged_only: return _branch_status(head) staged_set = set() modified_set = set() staged = [] modified = [] unmerged = [] untracked = [] upstream_changed = [] submodules = set() try: output = git.diff_index(head, cached=True, with_stderr=True) if output.startswith('fatal:'): raise errors.GitInitError('git init') for line in output.splitlines(): rest, name = line.split('\t', 1) status = rest[-1] name = eval_path(name) if '160000' in rest[1:14]: submodules.add(name) if status == 'M': staged.append(name) staged_set.add(name) # This file will also show up as 'M' without --cached # so by default don't consider it modified unless # it's truly modified modified_set.add(name) if not staged_only and is_modified(name): modified.append(name) elif status == 'A': staged.append(name) staged_set.add(name) elif status == 'D': staged.append(name) staged_set.add(name) modified_set.add(name) elif status == 'U': unmerged.append(name) modified_set.add(name) except errors.GitInitError: # handle git init staged.extend(all_files()) try: output = git.diff_index(head, with_stderr=True) if output.startswith('fatal:'): raise errors.GitInitError('git init') for line in output.splitlines(): rest , name = line.split('\t', 1) status = rest[-1] name = eval_path(name) if '160000' in rest[1:13]: submodules.add(name) if status == 'M' or status == 'D': if name not in modified_set: modified.append(name) elif status == 'A': # newly-added yet modified if (name not in modified_set and not staged_only and is_modified(name)): modified.append(name) except errors.GitInitError: # handle git init ls_files = git.ls_files(modified=True, z=True)[:-1].split('\0') modified.extend(map(core.decode, [f for f in ls_files if f])) untracked.extend(untracked_files()) # Look for upstream modified files if this is a tracking branch tracked = tracked_branch() if tracked: try: diff_expr = merge_base_to(tracked) output = git.diff(diff_expr, name_only=True, z=True, **_common_diff_opts()) if output.startswith('fatal:'): raise errors.GitInitError('git init') for name in [n for n in output.split('\0') if n]: name = core.decode(name) upstream_changed.append(name) except errors.GitInitError: # handle git init pass # Keep stuff sorted staged.sort() modified.sort() unmerged.sort() untracked.sort() upstream_changed.sort() return {'staged': staged, 'modified': modified, 'unmerged': unmerged, 'untracked': untracked, 'upstream_changed': upstream_changed, 'submodules': submodules}