def __get_notes_filename(cls, notes_rev): """Return the filename used to store the git notes. PARAMETERS notes_rev: The revision of the notes change. """ # A git note for any given commit (called the "annotated commit" # in this function) is maintained through a file in the special # refs/notes/commits namespace. The name of that file seems # to vary a little bit from case to case (sometimes it is just # equal to "%s" % rev, while some other times it is equal to # "%s/%s" % (rev[:2], rev[2:]) where rev is the revision of # the annotated commit. The one constant is that it is easy # to deduce the annotated commit ID, by just stripping the '/' # characters. # Look at the files modified by the git notes commit via # diff-tree. There should be only one, pointing us towards # the annotated commit. all_changes = git.diff_tree('-r', notes_rev, _split_lines=True) if not all_changes: # notes_rev is probably the root commit. Just use the empty # tree's sha1 as the reference. empty_tree_rev = git.mktree(_input='') all_changes = git.diff_tree('-r', empty_tree_rev, notes_rev, _split_lines=True) # The output should be 2 lines... # - The first line contains the hash of what is being compared, # which should be notes_rev; # - The second line contains the file change that interests us. # ... except in the case where the notes_rev does not have # a parent (first note). In that case, we diff-tree'ed against # the empty tree rev, and the first line is omitted. # # There is also another situation where the output is more than # two lines: Newer version of git sometimes rename some of the # files created by older versions of "git notes" during notes # updates, and bunches those renamings together with a note # update, thus creating commits that actually touch multiple # files (N707-041). In that situation, it appears as though # the first entry is always the one corresponding to the commit # being annotated, so discard anything past the second line. all_changes = all_changes[:2] assert all_changes (_, _, _, _, _, filename) = all_changes[-1].split(None, 5) return filename
def check_commit(old_rev, new_rev, project_name): """Call check_file for every file changed between old_rev and new_rev. Raise InvalidUpdate if one or more style violation are detected. PARAMETERS old_rev: The commit to be used as a reference to determine the list of files that have been modified/added by the new commit. Must be a valid revision. new_rev: The commit to be checked. project_name: The name of the project (same as the attribute in updates.emails.EmailInfo). """ debug('check_commit(old_rev=%s, new_rev=%s)' % (old_rev, new_rev)) all_changes = git.diff_tree('-r', old_rev, new_rev, _split_lines=True) for item in all_changes: (old_mode, new_mode, old_sha1, new_sha1, status, filename) \ = item.split(None, 5) debug('diff-tree entry: %s %s %s %s %s %s' % (old_mode, new_mode, old_sha1, new_sha1, status, filename), level=5) if status in ('D'): debug('deleted file ignored: %s' % filename, level=2) elif new_mode == '160000': debug('subproject entry ignored: %s' % filename, level=2) else: # Note: We treat a file rename as the equivalent of the old # file being deleted and the new file being added. This means # that we should run the pre-commit checks if applicable. # This is why we did not tell the `git diff-tree' command # above to detect renames, and why we do not have a special # branch for status values starting with `R'. check_file(filename, new_sha1, new_rev, project_name)
def files_changed(self): """Return the list of files changed by this commit. Cache the result in self.__files_changed so that subsequent calls to this method do not require calling git again. """ if self.__files_changed is None: self.__files_changed = [] all_changes = git.diff_tree('-r', self.base_rev_for_git(), self.rev, _split_lines=True) for item in all_changes: (old_mode, new_mode, old_sha1, new_sha1, status, filename) \ = item.split(None, 5) debug('diff-tree entry: %s %s %s %s %s %s' % (old_mode, new_mode, old_sha1, new_sha1, status, filename), level=5) self.__files_changed.append(filename) return self.__files_changed
def diff_filenames(*args): """Return a list of filenames that have been modified""" diff_zstr = git.diff_tree(name_only=True, no_commit_id=True, r=True, z=True, *args) return _parse_diff_filenames(diff_zstr)