| Index: gclient_scm.py | 
| diff --git a/gclient_scm.py b/gclient_scm.py | 
| index 0392c4e6d57b842af88f48972e94d8e6d4e64430..c80575e0d2fae66f8a5a134443e3bd1db3d643b2 100644 | 
| --- a/gclient_scm.py | 
| +++ b/gclient_scm.py | 
| @@ -221,13 +221,6 @@ | 
|  | 
| def GetCheckoutRoot(self): | 
| return scm.GIT.GetCheckoutRoot(self.checkout_path) | 
| - | 
| -  def GetRemoteURL(self, options, cwd=None): | 
| -    try: | 
| -      return self._Capture(['config', 'remote.%s.url' % self.remote], | 
| -                           cwd=cwd or self.checkout_path).rstrip() | 
| -    except (OSError, subprocess2.CalledProcessError): | 
| -      return None | 
|  | 
| def GetRevisionDate(self, _revision): | 
| """Returns the given revision's date in ISO-8601 format (which contains the | 
| @@ -286,6 +279,22 @@ | 
|  | 
| gclient_utils.CheckCallAndFilter(cmd4, **kwargs) | 
|  | 
| +  def _FetchAndReset(self, revision, file_list, options): | 
| +    """Equivalent to git fetch; git reset.""" | 
| +    quiet = [] | 
| +    if not options.verbose: | 
| +      quiet = ['--quiet'] | 
| +    self._UpdateBranchHeads(options, fetch=False) | 
| + | 
| +    fetch_cmd = [ | 
| +      '-c', 'core.deltaBaseCacheLimit=2g', 'fetch', self.remote, '--prune'] | 
| +    self._Run(fetch_cmd + quiet, options, retry=True) | 
| +    self._Run(['reset', '--hard', revision] + quiet, options) | 
| +    self.UpdateSubmoduleConfig() | 
| +    if file_list is not None: | 
| +      files = self._Capture(['ls-files']).splitlines() | 
| +      file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 
| + | 
| def update(self, options, args, file_list): | 
| """Runs git to update or transparently checkout the working copy. | 
|  | 
| @@ -372,9 +381,34 @@ | 
| '\tAnd run gclient sync again\n' | 
| % (self.relpath, rev_str, self.relpath)) | 
|  | 
| +    # See if the url has changed (the unittests use git://foo for the url, let | 
| +    # that through). | 
| +    current_url = self._Capture(['config', 'remote.%s.url' % self.remote]) | 
| +    return_early = False | 
| +    # TODO(maruel): Delete url != 'git://foo' since it's just to make the | 
| +    # unit test pass. (and update the comment above) | 
| +    # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. | 
| +    # This allows devs to use experimental repos which have a different url | 
| +    # but whose branch(s) are the same as official repos. | 
| +    if (current_url != url and | 
| +        url != 'git://foo' and | 
| +        subprocess2.capture( | 
| +            ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], | 
| +            cwd=self.checkout_path).strip() != 'False'): | 
| +      print('_____ switching %s to a new upstream' % self.relpath) | 
| +      # Make sure it's clean | 
| +      self._CheckClean(rev_str) | 
| +      # Switch over to the new upstream | 
| +      self._Run(['remote', 'set-url', self.remote, url], options) | 
| +      self._FetchAndReset(revision, file_list, options) | 
| +      return_early = True | 
| + | 
| # Need to do this in the normal path as well as in the post-remote-switch | 
| # path. | 
| self._PossiblySwitchCache(url, options) | 
| + | 
| +    if return_early: | 
| +      return self._Capture(['rev-parse', '--verify', 'HEAD']) | 
|  | 
| cur_branch = self._GetCurrentBranch() | 
|  | 
| @@ -781,7 +815,8 @@ | 
| # to relax this restriction in the future to allow for smarter cache | 
| # repo update schemes (such as pulling the same repo, but from a | 
| # different host). | 
| -        existing_url = self.GetRemoteURL(options, cwd=folder) | 
| +        existing_url = self._Capture(['config', 'remote.%s.url' % self.remote], | 
| +                                     cwd=folder) | 
| assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) | 
|  | 
| if use_reference: | 
| @@ -1050,13 +1085,6 @@ | 
| def GetCheckoutRoot(self): | 
| return scm.SVN.GetCheckoutRoot(self.checkout_path) | 
|  | 
| -  def GetRemoteURL(self, options): | 
| -    try: | 
| -      local_info = scm.SVN.CaptureLocalInfo([os.curdir], self.checkout_path) | 
| -    except (OSError, subprocess2.CalledProcessError): | 
| -      return None | 
| -    return local_info.get('URL') | 
| - | 
| def GetRevisionDate(self, revision): | 
| """Returns the given revision's date in ISO-8601 format (which contains the | 
| time zone).""" | 
| @@ -1096,12 +1124,25 @@ | 
| Raises: | 
| Error: if can't get URL for relative path. | 
| """ | 
| +    # Only update if git or hg is not controlling the directory. | 
| +    git_path = os.path.join(self.checkout_path, '.git') | 
| +    if os.path.exists(git_path): | 
| +      print('________ found .git directory; skipping %s' % self.relpath) | 
| +      return | 
| + | 
| +    hg_path = os.path.join(self.checkout_path, '.hg') | 
| +    if os.path.exists(hg_path): | 
| +      print('________ found .hg directory; skipping %s' % self.relpath) | 
| +      return | 
| + | 
| if args: | 
| raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 
|  | 
| # revision is the revision to match. It is None if no revision is specified, | 
| # i.e. the 'deps ain't pinned'. | 
| url, revision = gclient_utils.SplitUrlRevision(self.url) | 
| +    # Keep the original unpinned url for reference in case the repo is switched. | 
| +    base_url = url | 
| managed = True | 
| if options.revision: | 
| # Override the revision number. | 
| @@ -1247,6 +1288,53 @@ | 
| from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) | 
| revision = str(from_info_live['Revision']) | 
| rev_str = ' at %s' % revision | 
| + | 
| +    if from_info['URL'] != base_url: | 
| +      # The repository url changed, need to switch. | 
| +      try: | 
| +        to_info = scm.SVN.CaptureRemoteInfo(url) | 
| +      except (gclient_utils.Error, subprocess2.CalledProcessError): | 
| +        # The url is invalid or the server is not accessible, it's safer to bail | 
| +        # out right now. | 
| +        raise gclient_utils.Error('This url is unreachable: %s' % url) | 
| +      can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) | 
| +                    and (from_info['UUID'] == to_info['UUID'])) | 
| +      if can_switch: | 
| +        print('\n_____ relocating %s to a new checkout' % self.relpath) | 
| +        # We have different roots, so check if we can switch --relocate. | 
| +        # Subversion only permits this if the repository UUIDs match. | 
| +        # Perform the switch --relocate, then rewrite the from_url | 
| +        # to reflect where we "are now."  (This is the same way that | 
| +        # Subversion itself handles the metadata when switch --relocate | 
| +        # is used.)  This makes the checks below for whether we | 
| +        # can update to a revision or have to switch to a different | 
| +        # branch work as expected. | 
| +        # TODO(maruel):  TEST ME ! | 
| +        command = ['switch', '--relocate', | 
| +                   from_info['Repository Root'], | 
| +                   to_info['Repository Root'], | 
| +                   self.relpath] | 
| +        self._Run(command, options, cwd=self._root_dir) | 
| +        from_info['URL'] = from_info['URL'].replace( | 
| +            from_info['Repository Root'], | 
| +            to_info['Repository Root']) | 
| +      else: | 
| +        if not options.force and not options.reset: | 
| +          # Look for local modifications but ignore unversioned files. | 
| +          for status in scm.SVN.CaptureStatus(None, self.checkout_path): | 
| +            if status[0][0] != '?': | 
| +              raise gclient_utils.Error( | 
| +                  ('Can\'t switch the checkout to %s; UUID don\'t match and ' | 
| +                   'there is local changes in %s. Delete the directory and ' | 
| +                   'try again.') % (url, self.checkout_path)) | 
| +        # Ok delete it. | 
| +        print('\n_____ switching %s to a new checkout' % self.relpath) | 
| +        gclient_utils.rmtree(self.checkout_path) | 
| +        # We need to checkout. | 
| +        command = ['checkout', url, self.checkout_path] | 
| +        command = self._AddAdditionalUpdateFlags(command, options, revision) | 
| +        self._RunAndGetFileList(command, options, file_list, self._root_dir) | 
| +        return self.Svnversion() | 
|  | 
| # If the provided url has a revision number that matches the revision | 
| # number of the existing directory, then we don't need to bother updating. | 
| @@ -1314,6 +1402,12 @@ | 
| return self.update(options, [], file_list) | 
|  | 
| if not os.path.isdir(os.path.join(self.checkout_path, '.svn')): | 
| +      if os.path.isdir(os.path.join(self.checkout_path, '.git')): | 
| +        print('________ found .git directory; skipping %s' % self.relpath) | 
| +        return | 
| +      if os.path.isdir(os.path.join(self.checkout_path, '.hg')): | 
| +        print('________ found .hg directory; skipping %s' % self.relpath) | 
| +        return | 
| if not options.force: | 
| raise gclient_utils.Error('Invalid checkout path, aborting') | 
| print( | 
|  |