[llvm] r357180 - Add "git llvm revert" and "git llvm svn-lookup" subcommands

Jordan Rupprecht via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 28 09:15:28 PDT 2019


Author: rupprecht
Date: Thu Mar 28 09:15:28 2019
New Revision: 357180

URL: http://llvm.org/viewvc/llvm-project?rev=357180&view=rev
Log:
Add "git llvm revert" and "git llvm svn-lookup" subcommands

Summary:
The current git-svnrevert script only works with git-svn repos (e.g. using "git svn find-rev" to find the commit to revert). This adds a similar implementation that works with the llvm git command handler.

Usage:
```
// Revert by svn id
$ git llvm revert r123456
// See what commands would be run instead of actually reverting
$ git llvm revert -n r123456
<full git revert + git commit commands>
// Git commit hash also fine
$ git llvm revert abc123456
// For convenience, the git->svn method can be used directly:
$ git llvm svn-lookup abc123456
r123456
// Push revert upstream (drop the -n when ready)
$ git llvm push -n
```

Regardless of how the command is invoked (with a svn revision or git hash), the message is:

```
Revert [LibFoo] Change Foo implementation

This reverts r123456 (git commit abc123)
```

Reviewers: jyknight, mehdi_amini, jlebar

Reviewed By: jlebar

Subscribers: llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59837

Modified:
    llvm/trunk/utils/git-svn/git-llvm

Modified: llvm/trunk/utils/git-svn/git-llvm
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/git-svn/git-llvm?rev=357180&r1=357179&r2=357180&view=diff
==============================================================================
--- llvm/trunk/utils/git-svn/git-llvm (original)
+++ llvm/trunk/utils/git-svn/git-llvm Thu Mar 28 09:15:28 2019
@@ -40,6 +40,13 @@ else:
     def iteritems(d):
         return d.iteritems()
 
+try:
+    # Python 3
+    from shlex import quote
+except ImportError:
+    # Python 2
+    from pipes import quote
+
 # It's *almost* a straightforward mapping from the monorepo to svn...
 GIT_TO_SVN_DIR = {
     d: (d + '/trunk')
@@ -110,7 +117,9 @@ def get_dev_null():
 
 def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True,
           ignore_errors=False, text=True):
-    log_verbose('Running in %s: %s' % (cwd, ' '.join(cmd)))
+    # Escape args when logging for easy repro.
+    quoted_cmd = [quote(arg) for arg in cmd]
+    log_verbose('Running in %s: %s' % (cwd, ' '.join(quoted_cmd)))
 
     err_pipe = subprocess.PIPE
     if ignore_errors:
@@ -128,7 +137,7 @@ def shell(cmd, strip=True, cwd=None, std
 
     if p.returncode == 0 or ignore_errors:
         if stderr and not ignore_errors:
-            eprint('`%s` printed to stderr:' % ' '.join(cmd))
+            eprint('`%s` printed to stderr:' % ' '.join(quoted_cmd))
             eprint(stderr.rstrip())
         if strip:
             if text:
@@ -139,7 +148,7 @@ def shell(cmd, strip=True, cwd=None, std
             for l in stdout.splitlines():
                 log_verbose("STDOUT: %s" % l)
         return stdout
-    err_msg = '`%s` returned %s' % (' '.join(cmd), p.returncode)
+    err_msg = '`%s` returned %s' % (' '.join(quoted_cmd), p.returncode)
     eprint(err_msg)
     if stderr:
         eprint(stderr.rstrip())
@@ -398,6 +407,85 @@ def cmd_push(args):
         svn_push_one_rev(svn_root, r, dry_run)
 
 
+def lookup_llvm_svn_id(git_commit_hash):
+    commit_msg = git('log', '-1', git_commit_hash, ignore_errors=True)
+    if len(commit_msg) == 0:
+      die("Can't find git commit " + git_commit_hash)
+    svn_match = re.search('llvm-svn: (\d{5,7})$', commit_msg)
+    if svn_match:
+      return int(svn_match.group(1))
+    die("Can't find svn revision in git commit " + git_commit_hash)
+
+
+def cmd_svn_lookup(args):
+    '''Find the SVN revision id for a given git commit hash.
+
+    This is identified by 'llvm-svn: NNNNNN' in the git commit message.'''
+    # Get the git root
+    git_root = git('rev-parse', '--show-toplevel')
+    if not os.path.isdir(git_root):
+        die("Can't find git root dir")
+
+    # Run commands from the root
+    os.chdir(git_root)
+
+    log('r' + str(lookup_llvm_svn_id(args.git_commit_hash)))
+
+
+def cmd_revert(args):
+    '''Revert a commit by either SVN id (rNNNNNN) or git hash. This also
+    populates the git commit message with both the SVN revision and git hash of
+    the change being reverted.'''
+
+    # Get the git root
+    git_root = git('rev-parse', '--show-toplevel')
+    if not os.path.isdir(git_root):
+        die("Can't find git root dir")
+
+    # Run commands from the root
+    os.chdir(git_root)
+
+    # Check for a client branch first.
+    open_files = git('status', '-uno', '-s', '--porcelain')
+    if len(open_files) > 0:
+      die("Found open files. Please stash and then revert.\n" + open_files)
+
+    # If the revision looks like rNNNNNN, use that. Otherwise, look for it in
+    # the git commit.
+    svn_match = re.match('^r(\d{5,7})$', args.revision)
+    if svn_match:
+      svn_rev = svn_match.group(1)
+    else:
+      svn_rev = str(lookup_llvm_svn_id(args.revision))
+
+    oneline = git('log', '--all',  '-1', '--format=%H %s', '--grep',
+                  'llvm-svn: ' + svn_rev)
+    if len(oneline) == 0:
+      die("Can't find svn revision r" + svn_rev)
+    (git_hash, msg) = oneline.split(' ', 1)
+
+    log_verbose('Ready to revert r%s/%s: "%s"' % (svn_rev, git_hash, msg))
+
+    revert_args = ['revert', '--no-commit', git_hash]
+    # TODO: Running --edit doesn't seem to work, with errors that stdin is not
+    # a tty.
+    commit_args = [
+        'commit', '-m', 'Revert ' + msg,
+        '-m', 'This reverts r%s (git commit %s)' % (svn_rev, git_hash)]
+    if args.dry_run:
+      log("Would have run the following commands, if this weren't a dry run:\n"
+          '1) git %s\n2) git %s' % (
+              ' '.join(quote(arg) for arg in revert_args),
+              ' '.join(quote(arg) for arg in commit_args)))
+      return
+
+    git(*revert_args)
+    commit_log = git(*commit_args)
+
+    log('Created revert of r%s: %s' % (svn_rev, commit_log))
+    log("Run 'git llvm push -n' to inspect your changes and "
+        "run 'git llvm push' when ready")
+
 if __name__ == '__main__':
     if not program_exists('svn'):
         die('error: git-llvm needs svn command, but svn is not installed.')
@@ -435,6 +523,32 @@ if __name__ == '__main__':
         'upstream, or not in origin/master if the branch lacks '
         'an explicit upstream)')
     parser_push.set_defaults(func=cmd_push)
+
+    parser_revert = subcommands.add_parser(
+        'revert', description=cmd_revert.__doc__,
+        help='Revert a commit locally.')
+    parser_revert.add_argument(
+        'revision',
+        help='Revision to revert. Can either be an SVN revision number '
+        "(rNNNNNN) or a git commit hash (anything that doesn't look "
+        'like an SVN revision number).')
+    parser_revert.add_argument(
+        '-n',
+        '--dry-run',
+        dest='dry_run',
+        action='store_true',
+        help='Do everything other than perform a revert. Prints the git '
+        'revert command it would have run.')
+    parser_revert.set_defaults(func=cmd_revert)
+
+    parser_svn_lookup = subcommands.add_parser(
+        'svn-lookup', description=cmd_svn_lookup.__doc__,
+        help='Find the llvm-svn revision for a given commit.')
+    parser_svn_lookup.add_argument(
+        'git_commit_hash',
+        help='git_commit_hash for which we will look up the svn revision id.')
+    parser_svn_lookup.set_defaults(func=cmd_svn_lookup)
+
     args = p.parse_args(argv)
     VERBOSE = args.verbose
     QUIET = args.quiet




More information about the llvm-commits mailing list