| OLD | NEW | 
|    1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |    1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
|    2 # Use of this source code is governed by a BSD-style license that can be |    2 # Use of this source code is governed by a BSD-style license that can be | 
|    3 # found in the LICENSE file. |    3 # found in the LICENSE file. | 
|    4  |    4  | 
|    5 """Gclient-specific SCM-specific operations.""" |    5 """Gclient-specific SCM-specific operations.""" | 
|    6  |    6  | 
|    7 import logging |    7 import logging | 
|    8 import os |    8 import os | 
|    9 import posixpath |    9 import posixpath | 
|   10 import re |   10 import re | 
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  251                       " branch.") |  251                       " branch.") | 
|  252       elif upstream_branch.startswith('refs/remotes'): |  252       elif upstream_branch.startswith('refs/remotes'): | 
|  253         current_type = "branch" |  253         current_type = "branch" | 
|  254       else: |  254       else: | 
|  255         raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) |  255         raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) | 
|  256  |  256  | 
|  257     # Update the remotes first so we have all the refs. |  257     # Update the remotes first so we have all the refs. | 
|  258     backoff_time = 5 |  258     backoff_time = 5 | 
|  259     for _ in range(10): |  259     for _ in range(10): | 
|  260       try: |  260       try: | 
|  261         remote_output, remote_err = scm.GIT.Capture( |  261         remote_output = scm.GIT.Capture( | 
|  262             ['remote'] + verbose + ['update'], |  262             ['remote'] + verbose + ['update'], | 
|  263             self.checkout_path, |  263             cwd=self.checkout_path) | 
|  264             print_error=False) |  | 
|  265         break |  264         break | 
|  266       except gclient_utils.CheckCallError, e: |  265       except gclient_utils.CheckCallError, e: | 
|  267         # Hackish but at that point, git is known to work so just checking for |  266         # Hackish but at that point, git is known to work so just checking for | 
|  268         # 502 in stderr should be fine. |  267         # 502 in stderr should be fine. | 
|  269         if '502' in e.stderr: |  268         if '502' in e.stderr: | 
|  270           options.stdout.write(str(e) + '\n') |  269           options.stdout.write(str(e) + '\n') | 
|  271           options.stdout.write('Sleeping %.1f seconds and retrying...\n' % |  270           options.stdout.write('Sleeping %.1f seconds and retrying...\n' % | 
|  272                                backoff_time) |  271                                backoff_time) | 
|  273           time.sleep(backoff_time) |  272           time.sleep(backoff_time) | 
|  274           backoff_time *= 1.3 |  273           backoff_time *= 1.3 | 
|  275           continue |  274           continue | 
|  276         raise |  275         raise | 
|  277  |  276  | 
|  278     if verbose: |  277     if verbose: | 
|  279       options.stdout.write(remote_output.strip() + '\n') |  278       options.stdout.write(remote_output) | 
|  280       # git remote update prints to stderr when used with --verbose |  | 
|  281       options.stdout.write(remote_err.strip() + '\n') |  | 
|  282  |  279  | 
|  283     # This is a big hammer, debatable if it should even be here... |  280     # This is a big hammer, debatable if it should even be here... | 
|  284     if options.force or options.reset: |  281     if options.force or options.reset: | 
|  285       self._Run(['reset', '--hard', 'HEAD'], options) |  282       self._Run(['reset', '--hard', 'HEAD'], options) | 
|  286  |  283  | 
|  287     if current_type == 'detached': |  284     if current_type == 'detached': | 
|  288       # case 0 |  285       # case 0 | 
|  289       self._CheckClean(rev_str) |  286       self._CheckClean(rev_str) | 
|  290       self._CheckDetachedHead(rev_str, options) |  287       self._CheckDetachedHead(rev_str, options) | 
|  291       self._Capture(['checkout', '--quiet', '%s^0' % revision]) |  288       self._Capture(['checkout', '--quiet', '%s^0' % revision]) | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  324                      "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + |  321                      "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + | 
|  325                      "OR git checkout -b <some new branch> %s" % new_base) |  322                      "OR git checkout -b <some new branch> %s" % new_base) | 
|  326       raise gclient_utils.Error(switch_error) |  323       raise gclient_utils.Error(switch_error) | 
|  327     else: |  324     else: | 
|  328       # case 3 - the default case |  325       # case 3 - the default case | 
|  329       files = self._Capture(['diff', upstream_branch, '--name-only']).split() |  326       files = self._Capture(['diff', upstream_branch, '--name-only']).split() | 
|  330       if verbose: |  327       if verbose: | 
|  331         options.stdout.write('Trying fast-forward merge to branch : %s\n' % |  328         options.stdout.write('Trying fast-forward merge to branch : %s\n' % | 
|  332             upstream_branch) |  329             upstream_branch) | 
|  333       try: |  330       try: | 
|  334         merge_output, merge_err = scm.GIT.Capture(['merge', '--ff-only', |  331         merge_output = scm.GIT.Capture(['merge', '--ff-only', upstream_branch], | 
|  335                                                    upstream_branch], |  332             cwd=self.checkout_path) | 
|  336                                                   self.checkout_path, |  | 
|  337                                                   print_error=False) |  | 
|  338       except gclient_utils.CheckCallError, e: |  333       except gclient_utils.CheckCallError, e: | 
|  339         if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): |  334         if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): | 
|  340           if not printed_path: |  335           if not printed_path: | 
|  341             options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) |  336             options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) | 
|  342             printed_path = True |  337             printed_path = True | 
|  343           while True: |  338           while True: | 
|  344             try: |  339             try: | 
|  345               # TODO(maruel): That can't work. |  340               # TODO(maruel): That can't work with --jobs. | 
|  346               action = str(raw_input("Cannot fast-forward merge, attempt to " |  341               action = str(raw_input("Cannot fast-forward merge, attempt to " | 
|  347                                      "rebase? (y)es / (q)uit / (s)kip : ")) |  342                                      "rebase? (y)es / (q)uit / (s)kip : ")) | 
|  348             except ValueError: |  343             except ValueError: | 
|  349               gclient_utils.Error('Invalid Character') |  344               gclient_utils.Error('Invalid Character') | 
|  350               continue |  345               continue | 
|  351             if re.match(r'yes|y', action, re.I): |  346             if re.match(r'yes|y', action, re.I): | 
|  352               self._AttemptRebase(upstream_branch, files, options, |  347               self._AttemptRebase(upstream_branch, files, options, | 
|  353                                   printed_path=printed_path) |  348                                   printed_path=printed_path) | 
|  354               printed_path = True |  349               printed_path = True | 
|  355               break |  350               break | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  375           # Some other problem happened with the merge |  370           # Some other problem happened with the merge | 
|  376           logging.error("Error during fast-forward merge in %s!" % self.relpath) |  371           logging.error("Error during fast-forward merge in %s!" % self.relpath) | 
|  377           options.stdout.write(e.stderr + '\n') |  372           options.stdout.write(e.stderr + '\n') | 
|  378           raise |  373           raise | 
|  379       else: |  374       else: | 
|  380         # Fast-forward merge was successful |  375         # Fast-forward merge was successful | 
|  381         if not re.match('Already up-to-date.', merge_output) or verbose: |  376         if not re.match('Already up-to-date.', merge_output) or verbose: | 
|  382           if not printed_path: |  377           if not printed_path: | 
|  383             options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) |  378             options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) | 
|  384             printed_path = True |  379             printed_path = True | 
|  385           print merge_output.strip() |  380           options.stdout.write(merge_output) | 
|  386           if merge_err: |  | 
|  387             options.stdout.write('Merge produced error output:\n%s\n' % |  | 
|  388                 merge_err.strip()) |  | 
|  389           if not verbose: |  381           if not verbose: | 
|  390             # Make the output a little prettier. It's nice to have some |  382             # Make the output a little prettier. It's nice to have some | 
|  391             # whitespace between projects when syncing. |  383             # whitespace between projects when syncing. | 
|  392             options.stdout.write('\n') |  384             options.stdout.write('\n') | 
|  393  |  385  | 
|  394     file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |  386     file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 
|  395  |  387  | 
|  396     # If the rebase generated a conflict, abort and ask user to fix |  388     # If the rebase generated a conflict, abort and ask user to fix | 
|  397     if self._IsRebasing(): |  389     if self._IsRebasing(): | 
|  398       raise gclient_utils.Error('\n____ %s%s\n' |  390       raise gclient_utils.Error('\n____ %s%s\n' | 
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  523     rebase_cmd = ['rebase'] |  515     rebase_cmd = ['rebase'] | 
|  524     if options.verbose: |  516     if options.verbose: | 
|  525       rebase_cmd.append('--verbose') |  517       rebase_cmd.append('--verbose') | 
|  526     if newbase: |  518     if newbase: | 
|  527       rebase_cmd.extend(['--onto', newbase]) |  519       rebase_cmd.extend(['--onto', newbase]) | 
|  528     rebase_cmd.append(upstream) |  520     rebase_cmd.append(upstream) | 
|  529     if branch: |  521     if branch: | 
|  530       rebase_cmd.append(branch) |  522       rebase_cmd.append(branch) | 
|  531  |  523  | 
|  532     try: |  524     try: | 
|  533       rebase_output, rebase_err = scm.GIT.Capture(rebase_cmd, |  525       rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path) | 
|  534                                                   self.checkout_path, |  | 
|  535                                                   print_error=False) |  | 
|  536     except gclient_utils.CheckCallError, e: |  526     except gclient_utils.CheckCallError, e: | 
|  537       if re.match(r'cannot rebase: you have unstaged changes', e.stderr) or \ |  527       if (re.match(r'cannot rebase: you have unstaged changes', e.stderr) or | 
|  538          re.match(r'cannot rebase: your index contains uncommitted changes', |  528           re.match(r'cannot rebase: your index contains uncommitted changes', | 
|  539                   e.stderr): |  529                    e.stderr)): | 
|  540         while True: |  530         while True: | 
|  541           rebase_action = str(raw_input("Cannot rebase because of unstaged " |  531           rebase_action = str(raw_input("Cannot rebase because of unstaged " | 
|  542                                         "changes.\n'git reset --hard HEAD' ?\n" |  532                                         "changes.\n'git reset --hard HEAD' ?\n" | 
|  543                                         "WARNING: destroys any uncommitted " |  533                                         "WARNING: destroys any uncommitted " | 
|  544                                         "work in your current branch!" |  534                                         "work in your current branch!" | 
|  545                                         " (y)es / (q)uit / (s)how : ")) |  535                                         " (y)es / (q)uit / (s)how : ")) | 
|  546           if re.match(r'yes|y', rebase_action, re.I): |  536           if re.match(r'yes|y', rebase_action, re.I): | 
|  547             self._Run(['reset', '--hard', 'HEAD'], options) |  537             self._Run(['reset', '--hard', 'HEAD'], options) | 
|  548             # Should this be recursive? |  538             # Should this be recursive? | 
|  549             rebase_output, rebase_err = scm.GIT.Capture(rebase_cmd, |  539             rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path) | 
|  550                                                         self.checkout_path) |  | 
|  551             break |  540             break | 
|  552           elif re.match(r'quit|q', rebase_action, re.I): |  541           elif re.match(r'quit|q', rebase_action, re.I): | 
|  553             raise gclient_utils.Error("Please merge or rebase manually\n" |  542             raise gclient_utils.Error("Please merge or rebase manually\n" | 
|  554                                       "cd %s && git " % self.checkout_path |  543                                       "cd %s && git " % self.checkout_path | 
|  555                                       + "%s" % ' '.join(rebase_cmd)) |  544                                       + "%s" % ' '.join(rebase_cmd)) | 
|  556           elif re.match(r'show|s', rebase_action, re.I): |  545           elif re.match(r'show|s', rebase_action, re.I): | 
|  557             options.stdout.write('\n%s\n' % e.stderr.strip()) |  546             options.stdout.write('\n%s\n' % e.stderr.strip()) | 
|  558             continue |  547             continue | 
|  559           else: |  548           else: | 
|  560             gclient_utils.Error("Input not recognized") |  549             gclient_utils.Error("Input not recognized") | 
|  561             continue |  550             continue | 
|  562       elif re.search(r'^CONFLICT', e.stdout, re.M): |  551       elif re.search(r'^CONFLICT', e.stdout, re.M): | 
|  563         raise gclient_utils.Error("Conflict while rebasing this branch.\n" |  552         raise gclient_utils.Error("Conflict while rebasing this branch.\n" | 
|  564                                   "Fix the conflict and run gclient again.\n" |  553                                   "Fix the conflict and run gclient again.\n" | 
|  565                                   "See 'man git-rebase' for details.\n") |  554                                   "See 'man git-rebase' for details.\n") | 
|  566       else: |  555       else: | 
|  567         options.stdout.write(e.stdout.strip() + '\n') |  556         options.stdout.write(e.stdout.strip() + '\n') | 
|  568         options.stdout.write('Rebase produced error output:\n%s\n' % |  557         options.stdout.write('Rebase produced error output:\n%s\n' % | 
|  569             e.stderr.strip()) |  558             e.stderr.strip()) | 
|  570         raise gclient_utils.Error("Unrecognized error, please merge or rebase " |  559         raise gclient_utils.Error("Unrecognized error, please merge or rebase " | 
|  571                                   "manually.\ncd %s && git " % |  560                                   "manually.\ncd %s && git " % | 
|  572                                   self.checkout_path |  561                                   self.checkout_path | 
|  573                                   + "%s" % ' '.join(rebase_cmd)) |  562                                   + "%s" % ' '.join(rebase_cmd)) | 
|  574  |  563  | 
|  575     print rebase_output.strip() |  564     options.stdout.write(rebase_output) | 
|  576     if rebase_err: |  | 
|  577       options.stdout.write('Rebase produced error output:\n%s\n' % |  | 
|  578           rebase_err.strip()) |  | 
|  579     if not options.verbose: |  565     if not options.verbose: | 
|  580       # Make the output a little prettier. It's nice to have some |  566       # Make the output a little prettier. It's nice to have some | 
|  581       # whitespace between projects when syncing. |  567       # whitespace between projects when syncing. | 
|  582       options.stdout.write('\n') |  568       options.stdout.write('\n') | 
|  583  |  569  | 
|  584   @staticmethod |  570   @staticmethod | 
|  585   def _CheckMinVersion(min_version): |  571   def _CheckMinVersion(min_version): | 
|  586     (ok, current_version) = scm.GIT.AssertVersion(min_version) |  572     (ok, current_version) = scm.GIT.AssertVersion(min_version) | 
|  587     if not ok: |  573     if not ok: | 
|  588       raise gclient_utils.Error('git version %s < minimum required %s' % |  574       raise gclient_utils.Error('git version %s < minimum required %s' % | 
|  589                                 (current_version, min_version)) |  575                                 (current_version, min_version)) | 
|  590  |  576  | 
|  591   def _IsRebasing(self): |  577   def _IsRebasing(self): | 
|  592     # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't |  578     # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't | 
|  593     # have a plumbing command to determine whether a rebase is in progress, so |  579     # have a plumbing command to determine whether a rebase is in progress, so | 
|  594     # for now emualate (more-or-less) git-rebase.sh / git-completion.bash |  580     # for now emualate (more-or-less) git-rebase.sh / git-completion.bash | 
|  595     g = os.path.join(self.checkout_path, '.git') |  581     g = os.path.join(self.checkout_path, '.git') | 
|  596     return ( |  582     return ( | 
|  597       os.path.isdir(os.path.join(g, "rebase-merge")) or |  583       os.path.isdir(os.path.join(g, "rebase-merge")) or | 
|  598       os.path.isdir(os.path.join(g, "rebase-apply"))) |  584       os.path.isdir(os.path.join(g, "rebase-apply"))) | 
|  599  |  585  | 
|  600   def _CheckClean(self, rev_str): |  586   def _CheckClean(self, rev_str): | 
|  601     # Make sure the tree is clean; see git-rebase.sh for reference |  587     # Make sure the tree is clean; see git-rebase.sh for reference | 
|  602     try: |  588     try: | 
|  603       scm.GIT.Capture(['update-index', '--ignore-submodules', '--refresh'], |  589       scm.GIT.Capture(['update-index', '--ignore-submodules', '--refresh'], | 
|  604                       self.checkout_path, print_error=False) |  590                       cwd=self.checkout_path) | 
|  605     except gclient_utils.CheckCallError: |  591     except gclient_utils.CheckCallError: | 
|  606       raise gclient_utils.Error('\n____ %s%s\n' |  592       raise gclient_utils.Error('\n____ %s%s\n' | 
|  607                                 '\tYou have unstaged changes.\n' |  593                                 '\tYou have unstaged changes.\n' | 
|  608                                 '\tPlease commit, stash, or reset.\n' |  594                                 '\tPlease commit, stash, or reset.\n' | 
|  609                                   % (self.relpath, rev_str)) |  595                                   % (self.relpath, rev_str)) | 
|  610     try: |  596     try: | 
|  611       scm.GIT.Capture(['diff-index', '--cached', '--name-status', '-r', |  597       scm.GIT.Capture(['diff-index', '--cached', '--name-status', '-r', | 
|  612                        '--ignore-submodules', 'HEAD', '--'], self.checkout_path, |  598                        '--ignore-submodules', 'HEAD', '--'], | 
|  613                        print_error=False) |  599                        cwd=self.checkout_path) | 
|  614     except gclient_utils.CheckCallError: |  600     except gclient_utils.CheckCallError: | 
|  615       raise gclient_utils.Error('\n____ %s%s\n' |  601       raise gclient_utils.Error('\n____ %s%s\n' | 
|  616                                 '\tYour index contains uncommitted changes\n' |  602                                 '\tYour index contains uncommitted changes\n' | 
|  617                                 '\tPlease commit, stash, or reset.\n' |  603                                 '\tPlease commit, stash, or reset.\n' | 
|  618                                   % (self.relpath, rev_str)) |  604                                   % (self.relpath, rev_str)) | 
|  619  |  605  | 
|  620   def _CheckDetachedHead(self, rev_str, options): |  606   def _CheckDetachedHead(self, rev_str, options): | 
|  621     # HEAD is detached. Make sure it is safe to move away from (i.e., it is |  607     # HEAD is detached. Make sure it is safe to move away from (i.e., it is | 
|  622     # reference by a commit). If not, error out -- most likely a rebase is |  608     # reference by a commit). If not, error out -- most likely a rebase is | 
|  623     # in progress, try to detect so we can give a better error. |  609     # in progress, try to detect so we can give a better error. | 
|  624     try: |  610     try: | 
|  625       _, _ = scm.GIT.Capture( |  611       scm.GIT.Capture(['name-rev', '--no-undefined', 'HEAD'], | 
|  626         ['name-rev', '--no-undefined', 'HEAD'], |  612           cwd=self.checkout_path) | 
|  627         self.checkout_path, |  | 
|  628         print_error=False) |  | 
|  629     except gclient_utils.CheckCallError: |  613     except gclient_utils.CheckCallError: | 
|  630       # Commit is not contained by any rev. See if the user is rebasing: |  614       # Commit is not contained by any rev. See if the user is rebasing: | 
|  631       if self._IsRebasing(): |  615       if self._IsRebasing(): | 
|  632         # Punt to the user |  616         # Punt to the user | 
|  633         raise gclient_utils.Error('\n____ %s%s\n' |  617         raise gclient_utils.Error('\n____ %s%s\n' | 
|  634                                   '\tAlready in a conflict, i.e. (no branch).\n' |  618                                   '\tAlready in a conflict, i.e. (no branch).\n' | 
|  635                                   '\tFix the conflict and run gclient again.\n' |  619                                   '\tFix the conflict and run gclient again.\n' | 
|  636                                   '\tOr to abort run:\n\t\tgit-rebase --abort\n' |  620                                   '\tOr to abort run:\n\t\tgit-rebase --abort\n' | 
|  637                                   '\tSee man git-rebase for details.\n' |  621                                   '\tSee man git-rebase for details.\n' | 
|  638                                    % (self.relpath, rev_str)) |  622                                    % (self.relpath, rev_str)) | 
|  639       # Let's just save off the commit so we can proceed. |  623       # Let's just save off the commit so we can proceed. | 
|  640       name = ('saved-by-gclient-' + |  624       name = ('saved-by-gclient-' + | 
|  641               self._Capture(['rev-parse', '--short', 'HEAD'])) |  625               self._Capture(['rev-parse', '--short', 'HEAD'])) | 
|  642       self._Capture(['branch', name]) |  626       self._Capture(['branch', name]) | 
|  643       options.stdout.write( |  627       options.stdout.write( | 
|  644           '\n_____ found an unreferenced commit and saved it as \'%s\'\n' % |  628           '\n_____ found an unreferenced commit and saved it as \'%s\'\n' % | 
|  645           name) |  629           name) | 
|  646  |  630  | 
|  647   def _GetCurrentBranch(self): |  631   def _GetCurrentBranch(self): | 
|  648     # Returns name of current branch or None for detached HEAD |  632     # Returns name of current branch or None for detached HEAD | 
|  649     branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) |  633     branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) | 
|  650     if branch == 'HEAD': |  634     if branch == 'HEAD': | 
|  651       return None |  635       return None | 
|  652     return branch |  636     return branch | 
|  653  |  637  | 
|  654   def _Capture(self, args): |  638   def _Capture(self, args): | 
|  655     return gclient_utils.CheckCall(['git'] + args, |  639     return gclient_utils.CheckCall( | 
|  656                                    cwd=self.checkout_path)[0].strip() |  640         ['git'] + args, cwd=self.checkout_path, print_error=False)[0].strip() | 
|  657  |  641  | 
|  658   def _Run(self, args, options, **kwargs): |  642   def _Run(self, args, options, **kwargs): | 
|  659     kwargs.setdefault('cwd', self.checkout_path) |  643     kwargs.setdefault('cwd', self.checkout_path) | 
|  660     gclient_utils.CheckCallAndFilterAndHeader(['git'] + args, |  644     gclient_utils.CheckCallAndFilterAndHeader(['git'] + args, | 
|  661         always=options.verbose, stdout=options.stdout, **kwargs) |  645         always=options.verbose, stdout=options.stdout, **kwargs) | 
|  662  |  646  | 
|  663  |  647  | 
|  664 class SVNWrapper(SCMWrapper): |  648 class SVNWrapper(SCMWrapper): | 
|  665   """ Wrapper for SVN """ |  649   """ Wrapper for SVN """ | 
|  666  |  650  | 
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  963  |  947  | 
|  964     This method returns a new list to be used as a command.""" |  948     This method returns a new list to be used as a command.""" | 
|  965     new_command = command[:] |  949     new_command = command[:] | 
|  966     if revision: |  950     if revision: | 
|  967       new_command.extend(['--revision', str(revision).strip()]) |  951       new_command.extend(['--revision', str(revision).strip()]) | 
|  968     # --force was added to 'svn update' in svn 1.5. |  952     # --force was added to 'svn update' in svn 1.5. | 
|  969     if ((options.force or options.manually_grab_svn_rev) and |  953     if ((options.force or options.manually_grab_svn_rev) and | 
|  970         scm.SVN.AssertVersion("1.5")[0]): |  954         scm.SVN.AssertVersion("1.5")[0]): | 
|  971       new_command.append('--force') |  955       new_command.append('--force') | 
|  972     return new_command |  956     return new_command | 
| OLD | NEW |