def is_modified(name, git=git): status, out = git.diff('--', name, name_only=True, exit_code=True, with_status=True, **_common_diff_opts()) return status != 0
def diff_upstream(head): tracked = tracked_branch() if not tracked: return [] diff_expr = merge_base_to(head, tracked) output = git.diff(diff_expr, name_only=True, z=True, **_common_diff_opts()) if output.startswith('fatal:'): return [] return [core.decode(n) for n in output.split('\0') if n]
def _branch_status(branch, git=git): """ Returns a tuple of staged, unstaged, untracked, and unmerged files This shows only the changes that were introduced in branch """ status, output = git.diff(name_only=True, M=True, z=True, with_status=True, *branch.strip().split(), **_common_diff_opts()) if status != 0: return {} staged = map(core.decode, [n for n in output.split('\0') if n]) return {'staged': staged, 'upstream_changed': staged}
def changed_files(start, end, git=git): zfiles_str = git.diff('%s..%s' % (start, end), name_only=True, z=True, **_common_diff_opts()).strip('\0') return [core.decode(enc) for enc in zfiles_str.split('\0') if enc]
def renamed_files(start, end, git=git): difflines = git.diff('%s..%s' % (start, end), M=True, **_common_diff_opts()).splitlines() return [eval_path(r[12:].rstrip()) for r in difflines if r.startswith('rename from ')]
def diff_filenames(arg, git=git): """Return a list of filenames that have been modified""" diff_zstr = git.diff(arg, name_only=True, z=True, **_common_diff_opts()).rstrip('\0') return [core.decode(f) for f in diff_zstr.split('\0') if f]
def diff_helper(commit=None, branch=None, ref=None, endref=None, filename=None, cached=True, with_diff_header=False, suppress_header=True, reverse=False, git=git): "Invokes git diff on a filepath." if commit: ref, endref = commit+'^', commit argv = [] if ref and endref: argv.append('%s..%s' % (ref, endref)) elif ref: for r in ref.strip().split(): argv.append(r) elif branch: argv.append(branch) if filename: argv.append('--') if type(filename) is list: argv.extend(filename) else: argv.append(filename) start = False del_tag = 'deleted file mode ' headers = [] deleted = cached and not os.path.exists(core.encode(filename)) diffoutput = git.diff(R=reverse, M=True, cached=cached, *argv, **_common_diff_opts()) # Handle 'git init' if diffoutput.startswith('fatal:'): if with_diff_header: return ('', '') else: return '' if diffoutput.startswith('Submodule'): if with_diff_header: return ('', diffoutput) else: return diffoutput output = StringIO() diff = diffoutput.split('\n') for line in map(core.decode, diff): if not start and '@@' == line[:2] and '@@' in line[2:]: start = True if start or (deleted and del_tag in line): output.write(core.encode(line) + '\n') else: if with_diff_header: headers.append(core.encode(line)) elif not suppress_header: output.write(core.encode(line) + '\n') result = core.decode(output.getvalue()) output.close() if with_diff_header: return('\n'.join(headers), result) else: return result
def sha1_diff(sha1, git=git): return core.decode(git.diff(sha1 + '^!', **_common_diff_opts()))
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}
def sha1_diff(sha1, git=git): return git.diff(sha1 + '^!', **_common_diff_opts())