Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Unified Diff: tools/git_utils.py

Issue 141483011: add_codereview_message script to append messages to a CL (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: linting Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/git_utils.py
diff --git a/tools/git_utils.py b/tools/git_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..910dc47a7086942e996dc1cbeef2999d5c11d9df
--- /dev/null
+++ b/tools/git_utils.py
@@ -0,0 +1,136 @@
+# Copyright 2014 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Module to host the ChangeGitBranch class and test_git_executable function.
+"""
+
+import os
+import subprocess
+from misc_utils import VerboseSubprocess
+
+
+class ChangeGitBranch(object):
+ """Class to manage git branches.
+
+ This class allows one to create a new branch in a repository based
+ off of a given commit, and restore the original tree state.
+
+ Assumes current working directory is a git repository.
+
+ Example:
+ with ChangeGitBranch('git', 'newBranch'):
+ edit_files(files)
+ git_add(files)
+ git_commit()
+ git_format_patch('HEAD~')
+ # At this point, the repository is returned to its original
+ # state.
+
+ Constructor Args:
+ git: (string) git executable.
+ brach_name: (string) if not None, the name of the branch to
borenet 2014/01/30 14:36:35 "branch_name". Also, please document that this ex
hal.canary 2014/01/30 20:11:02 Done.
+ use. If None, then use a temporary branch that will be
+ deleted.
+ start_point: (string) if not None, the name of the branch or
+ commit to branch from. If None, then use origin/master
borenet 2014/01/30 14:36:35 I think upstream_branch or tracking_branch are bet
hal.canary 2014/01/30 20:11:02 Done.
+ verbose: (boolean) if true, makes debugging easier.
+ delete_branch: (boolean) delete the branch afterwards
+
+ Raises:
+ OSError: failed to execute git.
+ subprocess.CalledProcessError: git returned unexpected status.
+ Exception: if the given branch name exists, or if the repository
+ isn't clean on exit
+ """
+ # pylint: disable=I0011,R0903,R0902
+
+ def __init__(self,
+ git,
+ branch_name,
+ start_point=None,
+ verbose=False,
+ delete_branch=False):
+ # pylint: disable=I0011,R0913
+ self._branch_name = branch_name
+ if start_point:
+ self._start_point = start_point
+ else:
+ self._start_point = 'origin/master'
+ self._git = git
+ self._stash = None
+ self._original_branch = None
+ self._vsp = VerboseSubprocess(verbose)
+ self._delete_branch = delete_branch
+
+ def _has_git_diff(self):
+ """Return true iff repository has uncommited changes."""
+ return bool(self._vsp.call([self._git, 'diff', '--quiet', 'HEAD']))
+
+ def _branch_exists(self, branch):
+ """Return true iff branch exists."""
+ return 0 == self._vsp.call([self._git, 'show-ref', '--quiet', branch])
+
+ def __enter__(self):
+ git, vsp = self._git, self._vsp
+
+ while self._branch_exists(self._branch_name):
+ self._branch_name += '_'
+
+ self._stash = self._has_git_diff()
+ if self._stash:
+ vsp.check_call([git, 'stash', 'save'])
+ self._original_branch = git_branch_name(git, vsp.verbose)
+ vsp.check_call(
+ [git, 'checkout', '-q', '-b',
+ self._branch_name, self._start_point])
+
+ def __exit__(self, etype, value, traceback):
+ # pylint: disable=I0011,R0912
+ git, vsp = self._git, self._vsp
+
+ if self._has_git_diff():
+ status = vsp.check_output([git, 'status', '-s'])
+ raise Exception('git checkout not clean:\n%s' % status)
+ vsp.check_call([git, 'checkout', '-q', self._original_branch])
+ if self._stash:
+ vsp.check_call([git, 'stash', 'pop'])
+ if self._delete_branch:
+ assert self._original_branch != self._branch_name
+ vsp.check_call([git, 'branch', '-D', self._branch_name])
+
+
+def git_branch_name(git, verbose):
+ """Return a description of the current branch.
+
+ Args:
+ git: (string) git executable.
+ verbose: (boolean) makes debugging easier
+
+ Returns:
+ A string suitable for passing to `git checkout` later.
+ """
+ vsp = VerboseSubprocess(verbose)
+ try:
+ full_branch = vsp.strip_output([git, 'symbolic-ref', 'HEAD'])
+ return full_branch.split('/')[-1]
+ except (subprocess.CalledProcessError,):
+ # "fatal: ref HEAD is not a symbolic ref"
+ return vsp.strip_output([git, 'rev-parse', 'HEAD'])
+
+
+def test_git_executable(git_executable):
+ """Test the git executable.
+
+ Args:
+ git_executable: git executable path.
+ Returns:
+ True if test is successful.
+ """
+ with open(os.devnull, 'w') as devnull:
+ try:
+ subprocess.call([git_executable, '--version'], stdout=devnull)
+ except (OSError,):
+ return False
+ return True

Powered by Google App Engine
This is Rietveld 408576698