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

Side by Side Diff: git_cl.py

Issue 1064933004: git-squash-branch: handle empty squashes and dirty trees (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 5 years, 8 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | git_common.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Copyright (C) 2008 Evan Martin <martine@danga.com> 6 # Copyright (C) 2008 Evan Martin <martine@danga.com>
7 7
8 """A git-command for integrating reviews on Rietveld.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 else: 194 else:
195 git_set_branch_value('git-find-copies', int(options.find_copies)) 195 git_set_branch_value('git-find-copies', int(options.find_copies))
196 196
197 print('Using %d%% similarity for rename/copy detection. ' 197 print('Using %d%% similarity for rename/copy detection. '
198 'Override with --similarity.' % options.similarity) 198 'Override with --similarity.' % options.similarity)
199 199
200 return options, args 200 return options, args
201 parser.parse_args = Parse 201 parser.parse_args = Parse
202 202
203 203
204 def is_dirty_git_tree(cmd):
205 # Make sure index is up-to-date before running diff-index.
206 RunGit(['update-index', '--refresh', '-q'], error_ok=True)
207 dirty = RunGit(['diff-index', '--name-status', 'HEAD'])
208 if dirty:
209 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd
210 print 'Uncommitted files: (git diff-index --name-status HEAD)'
211 print dirty[:4096]
212 if len(dirty) > 4096:
213 print '... (run "git diff-index --name-status HEAD" to see full output).'
214 return True
215 return False
216
217
218 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): 204 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards):
219 """Return the corresponding git ref if |base_url| together with |glob_spec| 205 """Return the corresponding git ref if |base_url| together with |glob_spec|
220 matches the full |url|. 206 matches the full |url|.
221 207
222 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). 208 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below).
223 """ 209 """
224 fetch_suburl, as_ref = glob_spec.split(':') 210 fetch_suburl, as_ref = glob_spec.split(':')
225 if allow_wildcards: 211 if allow_wildcards:
226 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) 212 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl)
227 if glob_match: 213 if glob_match:
(...skipping 1420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1648 1634
1649 1635
1650 def CMDpresubmit(parser, args): 1636 def CMDpresubmit(parser, args):
1651 """Runs presubmit tests on the current changelist.""" 1637 """Runs presubmit tests on the current changelist."""
1652 parser.add_option('-u', '--upload', action='store_true', 1638 parser.add_option('-u', '--upload', action='store_true',
1653 help='Run upload hook instead of the push/dcommit hook') 1639 help='Run upload hook instead of the push/dcommit hook')
1654 parser.add_option('-f', '--force', action='store_true', 1640 parser.add_option('-f', '--force', action='store_true',
1655 help='Run checks even if tree is dirty') 1641 help='Run checks even if tree is dirty')
1656 (options, args) = parser.parse_args(args) 1642 (options, args) = parser.parse_args(args)
1657 1643
1658 if not options.force and is_dirty_git_tree('presubmit'): 1644 if not options.force and git_common.is_dirty_git_tree('presubmit'):
1659 print 'use --force to check even if tree is dirty.' 1645 print 'use --force to check even if tree is dirty.'
1660 return 1 1646 return 1
1661 1647
1662 cl = Changelist() 1648 cl = Changelist()
1663 if args: 1649 if args:
1664 base_branch = args[0] 1650 base_branch = args[0]
1665 else: 1651 else:
1666 # Default to diffing against the common ancestor of the upstream branch. 1652 # Default to diffing against the common ancestor of the upstream branch.
1667 base_branch = cl.GetCommonAncestorWithUpstream() 1653 base_branch = cl.GetCommonAncestorWithUpstream()
1668 1654
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
2025 help='email address to use to connect to Rietveld') 2011 help='email address to use to connect to Rietveld')
2026 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', 2012 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true',
2027 help='add a set of OWNERS to TBR') 2013 help='add a set of OWNERS to TBR')
2028 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', 2014 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true',
2029 help='Send the patchset to do a CQ dry run right after ' 2015 help='Send the patchset to do a CQ dry run right after '
2030 'upload.') 2016 'upload.')
2031 2017
2032 add_git_similarity(parser) 2018 add_git_similarity(parser)
2033 (options, args) = parser.parse_args(args) 2019 (options, args) = parser.parse_args(args)
2034 2020
2035 if is_dirty_git_tree('upload'): 2021 if git_common.is_dirty_git_tree('upload'):
2036 return 1 2022 return 1
2037 2023
2038 options.reviewers = cleanup_list(options.reviewers) 2024 options.reviewers = cleanup_list(options.reviewers)
2039 options.cc = cleanup_list(options.cc) 2025 options.cc = cleanup_list(options.cc)
2040 2026
2041 cl = Changelist() 2027 cl = Changelist()
2042 if args: 2028 if args:
2043 # TODO(ukai): is it ok for gerrit case? 2029 # TODO(ukai): is it ok for gerrit case?
2044 base_branch = args[0] 2030 base_branch = args[0]
2045 else: 2031 else:
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2155 args = [cl.GetUpstreamBranch()] 2141 args = [cl.GetUpstreamBranch()]
2156 2142
2157 if options.contributor: 2143 if options.contributor:
2158 if not re.match('^.*\s<\S+@\S+>$', options.contributor): 2144 if not re.match('^.*\s<\S+@\S+>$', options.contributor):
2159 print "Please provide contibutor as 'First Last <email@example.com>'" 2145 print "Please provide contibutor as 'First Last <email@example.com>'"
2160 return 1 2146 return 1
2161 2147
2162 base_branch = args[0] 2148 base_branch = args[0]
2163 base_has_submodules = IsSubmoduleMergeCommit(base_branch) 2149 base_has_submodules = IsSubmoduleMergeCommit(base_branch)
2164 2150
2165 if is_dirty_git_tree(cmd): 2151 if git_common.is_dirty_git_tree(cmd):
2166 return 1 2152 return 1
2167 2153
2168 # This rev-list syntax means "show all commits not in my branch that 2154 # This rev-list syntax means "show all commits not in my branch that
2169 # are in base_branch". 2155 # are in base_branch".
2170 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), 2156 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(),
2171 base_branch]).splitlines() 2157 base_branch]).splitlines()
2172 if upstream_commits: 2158 if upstream_commits:
2173 print ('Base branch "%s" has %d commits ' 2159 print ('Base branch "%s" has %d commits '
2174 'not in this branch.' % (base_branch, len(upstream_commits))) 2160 'not in this branch.' % (base_branch, len(upstream_commits)))
2175 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) 2161 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd)
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after
2531 'attempting a 3-way merge') 2517 'attempting a 3-way merge')
2532 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', 2518 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit',
2533 help="don't commit after patch applies") 2519 help="don't commit after patch applies")
2534 (options, args) = parser.parse_args(args) 2520 (options, args) = parser.parse_args(args)
2535 if len(args) != 1: 2521 if len(args) != 1:
2536 parser.print_help() 2522 parser.print_help()
2537 return 1 2523 return 1
2538 issue_arg = args[0] 2524 issue_arg = args[0]
2539 2525
2540 # We don't want uncommitted changes mixed up with the patch. 2526 # We don't want uncommitted changes mixed up with the patch.
2541 if is_dirty_git_tree('patch'): 2527 if git_common.is_dirty_git_tree('patch'):
2542 return 1 2528 return 1
2543 2529
2544 # TODO(maruel): Use apply_issue.py 2530 # TODO(maruel): Use apply_issue.py
2545 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? 2531 # TODO(ukai): use gerrit-cherry-pick for gerrit repository?
2546 2532
2547 if options.newbranch: 2533 if options.newbranch:
2548 if options.force: 2534 if options.force:
2549 RunGit(['branch', '-D', options.newbranch], 2535 RunGit(['branch', '-D', options.newbranch],
2550 stderr=subprocess2.PIPE, error_ok=True) 2536 stderr=subprocess2.PIPE, error_ok=True)
2551 RunGit(['checkout', '-b', options.newbranch, 2537 RunGit(['checkout', '-b', options.newbranch,
2552 Changelist().GetUpstreamBranch()]) 2538 Changelist().GetUpstreamBranch()])
2553 2539
2554 return PatchIssue(issue_arg, options.reject, options.nocommit, 2540 return PatchIssue(issue_arg, options.reject, options.nocommit,
2555 options.directory) 2541 options.directory)
2556 2542
2557 2543
2558 def PatchIssue(issue_arg, reject, nocommit, directory): 2544 def PatchIssue(issue_arg, reject, nocommit, directory):
2559 # There's a "reset --hard" when failing to apply the patch. In order 2545 # There's a "reset --hard" when failing to apply the patch. In order
2560 # not to destroy users' data, make sure the tree is not dirty here. 2546 # not to destroy users' data, make sure the tree is not dirty here.
2561 assert(not is_dirty_git_tree('apply')) 2547 assert(not git_common.is_dirty_git_tree('apply'))
2562 2548
2563 if type(issue_arg) is int or issue_arg.isdigit(): 2549 if type(issue_arg) is int or issue_arg.isdigit():
2564 # Input is an issue id. Figure out the URL. 2550 # Input is an issue id. Figure out the URL.
2565 issue = int(issue_arg) 2551 issue = int(issue_arg)
2566 cl = Changelist(issue=issue) 2552 cl = Changelist(issue=issue)
2567 patchset = cl.GetMostRecentPatchset() 2553 patchset = cl.GetMostRecentPatchset()
2568 patch_data = cl.GetPatchSetDiff(issue, patchset) 2554 patch_data = cl.GetPatchSetDiff(issue, patchset)
2569 else: 2555 else:
2570 # Assume it's a URL to the patch. Default to https. 2556 # Assume it's a URL to the patch. Default to https.
2571 issue_url = gclient_utils.UpgradeToHttps(issue_arg) 2557 issue_url = gclient_utils.UpgradeToHttps(issue_arg)
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
2914 2900
2915 def CMDdiff(parser, args): 2901 def CMDdiff(parser, args):
2916 """Shows differences between local tree and last upload.""" 2902 """Shows differences between local tree and last upload."""
2917 parser.parse_args(args) 2903 parser.parse_args(args)
2918 2904
2919 # Uncommitted (staged and unstaged) changes will be destroyed by 2905 # Uncommitted (staged and unstaged) changes will be destroyed by
2920 # "git reset --hard" if there are merging conflicts in PatchIssue(). 2906 # "git reset --hard" if there are merging conflicts in PatchIssue().
2921 # Staged changes would be committed along with the patch from last 2907 # Staged changes would be committed along with the patch from last
2922 # upload, hence counted toward the "last upload" side in the final 2908 # upload, hence counted toward the "last upload" side in the final
2923 # diff output, and this is not what we want. 2909 # diff output, and this is not what we want.
2924 if is_dirty_git_tree('diff'): 2910 if git_common.is_dirty_git_tree('diff'):
2925 return 1 2911 return 1
2926 2912
2927 cl = Changelist() 2913 cl = Changelist()
2928 issue = cl.GetIssue() 2914 issue = cl.GetIssue()
2929 branch = cl.GetBranch() 2915 branch = cl.GetBranch()
2930 if not issue: 2916 if not issue:
2931 DieWithError('No issue found for current branch (%s)' % branch) 2917 DieWithError('No issue found for current branch (%s)' % branch)
2932 TMP_BRANCH = 'git-cl-diff' 2918 TMP_BRANCH = 'git-cl-diff'
2933 base_branch = cl.GetCommonAncestorWithUpstream() 2919 base_branch = cl.GetCommonAncestorWithUpstream()
2934 2920
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
3161 if __name__ == '__main__': 3147 if __name__ == '__main__':
3162 # These affect sys.stdout so do it outside of main() to simplify mocks in 3148 # These affect sys.stdout so do it outside of main() to simplify mocks in
3163 # unit testing. 3149 # unit testing.
3164 fix_encoding.fix_encoding() 3150 fix_encoding.fix_encoding()
3165 colorama.init() 3151 colorama.init()
3166 try: 3152 try:
3167 sys.exit(main(sys.argv[1:])) 3153 sys.exit(main(sys.argv[1:]))
3168 except KeyboardInterrupt: 3154 except KeyboardInterrupt:
3169 sys.stderr.write('interrupted\n') 3155 sys.stderr.write('interrupted\n')
3170 sys.exit(1) 3156 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | git_common.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698