def show_log(self, num): cur_commit = Commit(self.workspace, sha1=self.head_tree) print_str = cur_commit.raw_content while num > 1 and cur_commit.parent_sha1: num -= 1 parent_commit = Commit(self.workspace, sha1=cur_commit.parent_sha1) print_str += '\n%s' % (parent_commit.raw_content) cur_commit = parent_commit less_str(print_str)
def test_commit_once(self): Command.cmd_commit('first ci') commit = Commit(sha1=Branch().head_commit) self.assertIsNone(commit.parent_sha1) tree = Tree(sha1=commit.tree) objects = tree.parse_objects() self.assertEqual(objects[self.path]['sha1'], Blob(self.content).sha1)
def commit(self, msg): new_tree = self.index.do_commit(self.workspace) committer_name = self.config.config_dict['user']['name'] committer_email = '<%s>' % (self.config.config_dict['user']['email']) commit_time = int(time.time()) commit_timezone = time.strftime("%z", time.gmtime()) commit = Commit(self.workspace, sha1=None, tree_sha1=new_tree.sha1, parent_sha1=self.head_tree, name=committer_name, email=committer_email, \ timestamp=commit_time, timezone=commit_timezone, msg=msg) write_object_to_file(commit.path, commit.content) write_to_file(self.head_path, commit.sha1)
def _from_line(cls, remote, line): """ Create a new PushInfo instance as parsed from line which is expected to be like c refs/heads/master:refs/heads/master 05d2687..1d0568e """ control_character, from_to, summary = line.split('\t', 3) flags = 0 # control character handling try: flags |= cls._flag_map[control_character] except KeyError: raise ValueError( "Control Character %r unknown as parsed from line %r" % (control_character, line)) # END handle control character # from_to handling from_ref_string, to_ref_string = from_to.split(':') if flags & cls.DELETED: from_ref = None else: from_ref = Reference.from_path(remote.repo, from_ref_string) # commit handling, could be message or commit info old_commit = None if summary.startswith('['): if "[rejected]" in summary: flags |= cls.REJECTED elif "[remote rejected]" in summary: flags |= cls.REMOTE_REJECTED elif "[remote failure]" in summary: flags |= cls.REMOTE_FAILURE elif "[no match]" in summary: flags |= cls.ERROR elif "[new tag]" in summary: flags |= cls.NEW_TAG elif "[new branch]" in summary: flags |= cls.NEW_HEAD # uptodate encoded in control character else: # fast-forward or forced update - was encoded in control character, # but we parse the old and new commit split_token = "..." if control_character == " ": split_token = ".." old_sha, new_sha = summary.split(' ')[0].split(split_token) old_commit = Commit(remote.repo, old_sha) # END message handling return PushInfo(flags, from_ref, to_ref_string, remote, old_commit, summary)
def _get_commit(self): """ :return: Commit object we point to, works for detached and non-detached SymbolicReferences""" # we partially reimplement it to prevent unnecessary file access hexsha, target_ref_path = self._get_ref_info() # it is a detached reference if hexsha: return Commit(self.repo, hex_to_bin(hexsha)) return self.from_path(self.repo, target_ref_path).commit
def read_commits(repo_path): """ Возвращает (yield) объекты Commit для всех коммитов """ commit = None cmds = git_cmd_start(repo_path) + ['log', '-m', '--parents', '--numstat', '--date=iso'] process = Popen(cmds, stdout=PIPE, stderr=PIPE) for line in iter(process.stdout): line = line.replace('\n', '') if line.startswith("Author: "): commit.author = author_alias(line[len("Author: "):]) elif line.startswith("Date: "): commit.date = line[len("Date: "):] commit.date = commit.date[:-6].strip() # убираем +0300 elif line.startswith("commit "): if commit: yield commit if ' (from' in line: line = line[:line.index(' (from')] hashes = line.split(' ')[1:] commit = Commit(hashes[0], hashes[1:]) elif line.startswith(" "): commit.message = line[4:] else: m = r_numstat.match(line) if m: f_add, f_rem, f_name = m.groups() if f_add != '-': # не бинарный f_add, f_rem = int(f_add), int(f_rem) commit.changes.append((f_name, f_add, f_rem)) if commit: yield commit errors = process.stderr.read() if errors: raise GitError("log: " + errors)
def test_commit_twice(self): Command.cmd_commit('first ci') parent_sha1 = Branch().head_commit second_content = '11\n' write_to_file(self.path, second_content) new_path = '2.txt' new_content = '2\n' write_to_file(new_path, new_content) Command.cmd_add('.') Command.cmd_commit('second ci') commit = Commit(sha1=Branch().head_commit) self.assertEqual(parent_sha1, commit.parent_sha1) tree = Tree(sha1=commit.tree) objects = tree.parse_objects() self.assertEqual(objects[self.path]['sha1'], Blob(second_content).sha1) self.assertEqual(objects[new_path]['sha1'], Blob(new_content).sha1)
def _from_line(cls, repo, line, fetch_line): """ Parse information from the given line as returned by git-fetch -v and return a new FetchInfo object representing this information. We can handle a line as follows "%c %-*s %-*s -> %s%s" Where c is either ' ', !, +, -, *, or = ! means error + means success forcing update - means a tag was updated * means birth of new branch or tag = means the head was up to date ( and not moved ) ' ' means a fast-forward fetch line is the corresponding line from FETCH_HEAD, like acb0fa8b94ef421ad60c8507b634759a472cd56c not-for-merge branch '0.1.7RC' of /tmp/tmpya0vairemote_repo """ match = cls.re_fetch_result.match(line) if match is None: raise ValueError("Failed to parse line: %r" % line) # parse lines control_character, operation, local_remote_ref, remote_local_ref, note = match.groups( ) try: new_hex_sha, fetch_operation, fetch_note = fetch_line.split("\t") ref_type_name, fetch_note = fetch_note.split(' ', 1) except ValueError: # unpack error raise ValueError("Failed to parse FETCH__HEAD line: %r" % fetch_line) # handle FETCH_HEAD and figure out ref type # If we do not specify a target branch like master:refs/remotes/origin/master, # the fetch result is stored in FETCH_HEAD which destroys the rule we usually # have. In that case we use a symbolic reference which is detached ref_type = None if remote_local_ref == "FETCH_HEAD": ref_type = SymbolicReference elif ref_type_name == "branch": ref_type = RemoteReference elif ref_type_name == "tag": ref_type = TagReference else: raise TypeError("Cannot handle reference type: %r" % ref_type_name) # create ref instance if ref_type is SymbolicReference: remote_local_ref = ref_type(repo, "FETCH_HEAD") else: remote_local_ref = Reference.from_path( repo, os.path.join(ref_type._common_path_default, remote_local_ref.strip())) # END create ref instance note = (note and note.strip()) or '' # parse flags from control_character flags = 0 try: flags |= cls._flag_map[control_character] except KeyError: raise ValueError( "Control character %r unknown as parsed from line %r" % (control_character, line)) # END control char exception hanlding # parse operation string for more info - makes no sense for symbolic refs old_commit = None if isinstance(remote_local_ref, Reference): if 'rejected' in operation: flags |= cls.REJECTED if 'new tag' in operation: flags |= cls.NEW_TAG if 'new branch' in operation: flags |= cls.NEW_HEAD if '...' in operation or '..' in operation: split_token = '...' if control_character == ' ': split_token = split_token[:-1] old_commit = Commit(repo, operation.split(split_token)[0]) # END handle refspec # END reference flag handling return cls(remote_local_ref, flags, note, old_commit)