From fedec73c2b4800284d5f60a8bb56b516a227fc57 Mon Sep 17 00:00:00 2001 From: Randy Lai Date: Mon, 24 Jul 2017 23:39:07 -0400 Subject: [PATCH] Enhancement: more history related methods --- core/commands/inline_diff.py | 43 ------------ core/git_mixins/history.py | 128 ++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 44 deletions(-) diff --git a/core/commands/inline_diff.py b/core/commands/inline_diff.py index ea1b3fe37..84f2d0a8a 100644 --- a/core/commands/inline_diff.py +++ b/core/commands/inline_diff.py @@ -198,49 +198,6 @@ def run(self, edit): sublime.set_timeout_async(lambda: self.verify_not_conflict(), 0) - def get_indexed_file_object(self, file_path): - """ - Given an absolute path to a file contained in a git repo, return - git's internal object hash associated with the version of that file - in the index (if the file is staged) or in the HEAD (if it is not - staged). - """ - stdout = self.git("ls-files", "-s", file_path) - - # 100644 c9d70aa928a3670bc2b879b4a596f10d3e81ba7c 0 SomeFile.py - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - git_file_entry = stdout.split(" ") - return git_file_entry[1] - - def get_head_file_object(self, file_path): - """ - Given an absolute path to a file contained in a git repo, return - git's internal object hash associated with the version of that - file in the HEAD. - """ - stdout = self.git("ls-tree", "HEAD", file_path) - - # 100644 blob 7317069f30eafd4d7674612679322d59f9fb65a4 SomeFile.py - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - git_file_entry = stdout.split() # split by spaces and tabs - return git_file_entry[2] - - def get_object_contents(self, object_hash): - """ - Given the object hash to a versioned object in the current git repo, - display the contents of that object. - """ - return self.git("show", "--no-color", object_hash) - - def get_object_from_string(self, string): - """ - Given a string, pipe the contents of that string to git and have it - stored in the current repo, and return an object-hash that can be - used to diff against. - """ - stdout = self.git("hash-object", "-w", "--stdin", stdin=string, encode=False) - return stdout.split("\n")[0] - def get_inline_diff_contents(self, original_contents, diff): """ Given a file's original contents and an array of hunks that could be diff --git a/core/git_mixins/history.py b/core/git_mixins/history.py index 18e746c85..aeb718d46 100644 --- a/core/git_mixins/history.py +++ b/core/git_mixins/history.py @@ -148,7 +148,12 @@ def get_short_hash(self, commit_hash): def filename_at_commit(self, filename, commit_hash): commit_len = len(commit_hash) lines = self.git( - "log", "--pretty=oneline", "--follow", "--name-status", "--", filename + "log", + "--pretty=oneline", + "--follow", + "--name-status", + "{}..{}".format(commit_hash, "HEAD"), + "--", filename ).split("\n") for i in range(0, len(lines), 2): @@ -160,3 +165,124 @@ def filename_at_commit(self, filename, commit_hash): # If the commit hash is not for this file. return filename + + def get_file_content_at_commit(self, filename, commit_hash): + filename = self.get_rel_path(filename) + filename = filename.replace('\\\\', '/') + filename = self.filename_at_commit(filename, commit_hash) + return self.git("show", commit_hash + ':' + filename) + + def find_matching_lineno(self, base_commit, target_commit, line, file_path=None): + """ + Return the matching line of the target_commit given the line number of the base_commit. + """ + if not file_path: + file_path = self.file_path + + if base_commit: + base_object = self.get_commit_file_object(base_commit, file_path) + else: + base_file_contents = util.file.get_file_contents_binary(self.repo_path, file_path) + base_object = self.get_object_from_string(base_file_contents) + + target_object = self.get_commit_file_object(target_commit, file_path) + + stdout = self.git( + "diff", "--no-color", "-U0", base_object, target_object) + diff = util.parse_diff(stdout) + + if not diff: + return line + + for hunk in reversed(diff): + head_start = hunk.head_start if hunk.head_length else hunk.head_start + 1 + saved_start = hunk.saved_start if hunk.saved_length else hunk.saved_start + 1 + head_end = head_start + hunk.head_length + saved_end = saved_start + hunk.saved_length + + if head_end <= line: + return saved_end + line - head_end + elif head_start <= line: + return saved_start + + # fails to find matching + return 1 + + def neighbor_commit(self, commit_hash, position): + """ + Get the commit before or after a specific commit + """ + if position == "older": + return self.git( + "log", + "--format=%H", + "--follow", + "-n", "1", + "{}~1".format(commit_hash), + "--", self.file_path + ).strip() + elif position == "newer": + return self.git( + "log", + "--format=%H", + "--follow", + "--reverse", + "{}..{}".format(commit_hash, "HEAD"), + "--", self.file_path + ).strip().split("\n", 1)[0] + + def get_indexed_file_object(self, file_path): + """ + Given an absolute path to a file contained in a git repo, return + git's internal object hash associated with the version of that file + in the index (if the file is staged) or in the HEAD (if it is not + staged). + """ + stdout = self.git("ls-files", "-s", file_path) + + # 100644 c9d70aa928a3670bc2b879b4a596f10d3e81ba7c 0 SomeFile.py + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + git_file_entry = stdout.split(" ") + return git_file_entry[1] + + def get_head_file_object(self, file_path): + """ + Given an absolute path to a file contained in a git repo, return + git's internal object hash associated with the version of that + file in the HEAD. + """ + stdout = self.git("ls-tree", "HEAD", file_path) + + # 100644 blob 7317069f30eafd4d7674612679322d59f9fb65a4 SomeFile.py + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + git_file_entry = stdout.split() # split by spaces and tabs + return git_file_entry[2] + + def get_commit_file_object(self, commit, file_path): + """ + Given an absolute path to a file contained in a git repo, return + git's internal object hash associated with the version of that + file in the commit. + """ + stdout = self.git("ls-tree", commit, file_path) + + # 100644 blob 7317069f30eafd4d7674612679322d59f9fb65a4 SomeFile.py + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + git_file_entry = stdout.split() # split by spaces and tabs + return git_file_entry[2] + + def get_object_contents(self, object_hash): + """ + Given the object hash to a versioned object in the current git repo, + display the contents of that object. + """ + return self.git("show", "--no-color", object_hash) + + def get_object_from_string(self, string): + """ + Given a string, pipe the contents of that string to git and have it + stored in the current repo, and return an object-hash that can be + used to diff against. + """ + stdout = self.git("hash-object", "-w", "--stdin", stdin=string, encode=False) + return stdout.split("\n")[0]