def commit_object(): with seeded(17): # 20-byte sha1 k = 20 bits = random.getrandbits(k * 8) data = bits.to_bytes(k, sys.byteorder) # in py39, can use randbytes(k) repo = None commit = git.Commit(repo, data) yield commit
def _copy_commit(self, orig_commit, tree, parents): new_commit = git.Commit( self._repo, git.Commit.NULL_BIN_SHA, tree, orig_commit.author, orig_commit.authored_date, orig_commit.author_tz_offset, orig_commit.committer, orig_commit.committed_date, orig_commit.committer_tz_offset, "%s\n(sapling split of %s)" % (orig_commit.message, orig_commit.hexsha), parents, orig_commit.encoding) return self._write_commit(new_commit)
def test_collect_committers(user, expected): binsha = b'\x12' * 20 commit = git.Commit('fake-repo', binsha, author=user, committer=user, message="fake commit message") dictresult = {'team-committers': [], 'team-committers-mails': [], 'external-committers': [], 'external-committers-mails': []} collect_committers(commit, dictresult, {'*****@*****.**': '*****@*****.**', }) assert dictresult == expected
def commits_between(repo, start, stop): """ Args: start (git.Commit): toplogically (chronologically) first commit stop (git.Commit): toplogically (chronologically) last commit Returns: list of git.Commit: between commits References: https://stackoverflow.com/questions/18679870/commits-between-2-hashes https://stackoverflow.com/questions/462974/diff-double-and-triple-dot Warning: this gets messy any node on the path between <start> and <stop> has more than one parent that is not on a path between <start> and <stop> Notes: As a prefix: the carrot (^A) removes commits reachable from A. As a suffix: the carrot (A^) references the 1st parent of A Furthermore: (A^n) references the n-th parent of A (A~n) references the n-th ancestor of A The tilde and carrot can be chained. A^^ = A~2 = the grandparent of A Reachable means everything in the past. PAST...............................PRESENT <p1> -- <start> -- <A> -- <B> -- <stop> / <p2> __/ Example: >>> repo = git.Repo() >>> stop = repo.head.commit >>> start = stop.parents[0].parents[0].parents[0].parents[0] >>> commits = commits_between(repo, start, stop) >>> assert commits[0] == start >>> assert commits[-1] == stop >>> assert len(commits) == 4 """ import binascii argstr = '{start}^..{stop}'.format(start=start, stop=stop) hexshas = repo.git.rev_list(argstr).splitlines() binshas = [binascii.unhexlify(h) for h in hexshas] commits = [git.Commit(repo, b) for b in binshas] return commits
def _raw_copy_commit(self, commit, message=None, parents=None, actor=None): warnings.warn("Will probable be removed with Git.merge_release_back().", PendingDeprecationWarning) # create a new commit reusing the tree (meaning no file changes) new_commit = git.Commit(self._get_local_repo(), git.Commit.NULL_BIN_SHA) new_commit.tree = commit.tree # set commit date unix_time = int(time()) offset = altzone new_commit.authored_date = unix_time new_commit.author_tz_offset = offset # make sure we have a somewhat more linear history # (gitg and possibly others will get confused otherwise) if new_commit.authored_date == commit.authored_date: new_commit.authored_date = new_commit.authored_date + 1 new_commit.committed_date = unix_time new_commit.committer_tz_offset = offset if new_commit.committed_date == commit.committed_date: new_commit.committed_date = new_commit.committed_date + 1 # set author / comitter actor = self._get_release_actor(actor) new_commit.author = actor new_commit.committer = actor # set commit message if message: new_commit.message = message else: new_commit.message = commit.message # set parents new_commit.parents = parents if not parents is None else [] # reuse encoding new_commit.encoding = commit.encoding return new_commit
def ln_list_groups(self, groups): tags = self.ln_list_tags_commits() result = [] for tag in tags: commits = dict() for item in tag['data']: for message in item.message.split('\n'): for index in groups: if index not in commits: commits[index] = [] optional = re.findall(groups[index], message) if optional: commits[index].append( dict( optional=optional[0], commit=git.Commit( item.repo, item.binsha, tree=item.tree, author=item.author, authored_date=item.authored_date, author_tz_offset=item.author_tz_offset, committer=item.committer, committed_date=item.committed_date, committer_tz_offset=item. committer_tz_offset, message=message.strip(), parents=item.parents, encoding=item.encoding, gpgsig=item.gpgsig))) for index in groups: if index in commits: tag[index] = commits[index] else: tag[index] = [] result.append(tag) return result
def _iter_commits_with_refs(self, *args, **kwargs): """ A reimplementation of GitPython's iter_commits that includes the --decorate option. Unfortunately, iter_commits discards the additional info returned by adding --decorate, and the ref names are not exposed on the commit objects without making an entirely separate call to log. Ideally, since we're reimplementing it anyway, we would prefer to add all the info we need to the format to avoid the additional overhead of the lazy-load of the commit data, but the commit message is a problem since it can contain newlines which breaks parsing of the log lines (iter_commits can be broken this way, too). This does keep the id_only case fast and the overhead of lazy-loading the commit data is probably fine. But if this ends up being a bottleneck, that would be one possibile optimization. Renaming Detection of renaming can be implemented using diff with parent with create_path=True. But taking diffs is slow. That's why --name-status is added to log. Then log returns something like this: <commit hash>x00 <refs> \n # empty line R100 <renamed from path> <renamed to path> # when rename happens A\t<some path> # other cases D\t<some path> # other cases etc """ proc = self._git.git.log(*args, format='%H%x00%d', as_process=True, **kwargs) stream = proc.stdout commit_lines = [] while True: line = stream.readline() if '\x00' in line or not (len(line)): # hash line read, need to yield previous commit # first, cleaning lines a bit commit_lines = [ ln.strip('\n ').replace('\t', ' ') for ln in commit_lines if ln.strip('\n ') ] if commit_lines: hexsha, decoration = commit_lines[0].split('\x00') if decoration: # "->" replacement is because git 2.4 introduced "HEAD -> master" syntax refs = decoration.strip(' ()').replace( ' -> ', ', ').split(', ') else: refs = [] tag_prefix = 'tag: ' # introduced in git 1.8.3 for i, ref in enumerate(refs): if ref.startswith(tag_prefix): refs[i] = ref[len(tag_prefix):] refs.sort() renamed = {} # merge commits don't have any --name-status output if len(commit_lines) > 1: name_stat_parts = commit_lines[1].split(' ') if name_stat_parts[0] == 'R100': renamed['from'] = name_stat_parts[1] renamed['to'] = name_stat_parts[2] yield (git.Commit(self._git, gitdb.util.hex_to_bin(hexsha)), refs, renamed) if not (len(line)): # if all lines have been read break commit_lines = [line] else: commit_lines.append(line)
if len(user_responses) == 1: continue time_categories = report['user_responses']['time_categories'] #nasa_tlx = report['NASA-TLX'] for category in time_categories: if 'refectoring' in category: break else: time_categories['refactoring'] = {u'time_spent': 0.0, u'difficulty': 0} #pp.pprint(log) total_time = (time_categories['planning']['time_spent'] + time_categories['coding']['time_spent'] + time_categories['refactoring']['time_spent'] + time_categories['debugging']['time_spent'] + time_categories['optimising']['time_spent']) total_time_per_commit.append(total_time) commit = git.Commit(repo, binascii.unhexlify(log[0])) lines_changed = 0 print commit.diff(commit.parents[0])[0].diff diff = subprocess.check_output([ "git", "--git-dir", os.path.join(args.repo_dir, ".git"), 'diff', commit.hexsha, commit.parents[0].hexsha ]) sloc = 0 for line in diff.split('\n'): if not (line.startswith("-") or line.startswith("+")): continue if line.strip() == "+" or line.strip() == "-": continue if line.startswith('+++') or line.startswith('---'): continue sloc += 1 total_time_per_commit = sloc
#!/usr/bin/python # -*- encoding: utf-8 -*- import git import sys from collections import defaultdict from textwrap import wrap from email.Utils import formatdate repo = git.Repo('.') start = git.Commit(repo, sys.argv[1]) end = git.Commit(repo, 'HEAD') curlog = repo.log(end) oldlog = repo.log(start) changelog = defaultdict(list) for id in repo.commits_between(start, end): commit = git.Commit(repo, id) changelog[commit.author.name].append(commit.summary) print 'bash-completion (X.Y)' print for author in sorted(changelog.keys()): print " [ %s ]" % author for log in changelog[author]: print '\n'.join( wrap(log, initial_indent=' * ', subsequent_indent=' ')) print