OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 from __future__ import print_function | 7 from __future__ import print_function |
8 | 8 |
9 import errno | 9 import errno |
10 import logging | 10 import logging |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 rev_str = ' at %s' % revision | 362 rev_str = ' at %s' % revision |
363 files = [] if file_list is not None else None | 363 files = [] if file_list is not None else None |
364 | 364 |
365 printed_path = False | 365 printed_path = False |
366 verbose = [] | 366 verbose = [] |
367 if options.verbose: | 367 if options.verbose: |
368 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 368 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) |
369 verbose = ['--verbose'] | 369 verbose = ['--verbose'] |
370 printed_path = True | 370 printed_path = True |
371 | 371 |
372 if revision.startswith('refs/'): | 372 remote_ref = scm.GIT.RefToRemoteRef(revision, self.remote) |
| 373 if remote_ref: |
| 374 # Rewrite remote refs to their local equivalents. |
| 375 revision = ''.join(remote_ref) |
373 rev_type = "branch" | 376 rev_type = "branch" |
374 elif revision.startswith(self.remote + '/'): | 377 elif revision.startswith('refs/'): |
375 # Rewrite remote refs to their local equivalents. | 378 # Local branch? We probably don't want to support, since DEPS should |
376 revision = 'refs/remotes/' + revision | 379 # always specify branches as they are in the upstream repo. |
377 rev_type = "branch" | 380 rev_type = "branch" |
378 else: | 381 else: |
379 # hash is also a tag, only make a distinction at checkout | 382 # hash is also a tag, only make a distinction at checkout |
380 rev_type = "hash" | 383 rev_type = "hash" |
381 | 384 |
382 mirror = self._GetMirror(url, options) | 385 mirror = self._GetMirror(url, options) |
383 if mirror: | 386 if mirror: |
384 url = mirror.mirror_path | 387 url = mirror.mirror_path |
385 | 388 |
386 if (not os.path.exists(self.checkout_path) or | 389 if (not os.path.exists(self.checkout_path) or |
387 (os.path.isdir(self.checkout_path) and | 390 (os.path.isdir(self.checkout_path) and |
388 not os.path.exists(os.path.join(self.checkout_path, '.git')))): | 391 not os.path.exists(os.path.join(self.checkout_path, '.git')))): |
389 if mirror: | 392 if mirror: |
390 self._UpdateMirror(mirror, options) | 393 self._UpdateMirror(mirror, options) |
391 try: | 394 try: |
392 self._Clone(revision, url, options) | 395 self._Clone(revision, url, options) |
393 except subprocess2.CalledProcessError: | 396 except subprocess2.CalledProcessError: |
394 self._DeleteOrMove(options.force) | 397 self._DeleteOrMove(options.force) |
395 self._Clone(revision, url, options) | 398 self._Clone(revision, url, options) |
396 if deps_revision and deps_revision.startswith('branch-heads/'): | |
397 deps_branch = deps_revision.replace('branch-heads/', '') | |
398 self._Capture(['branch', deps_branch, deps_revision]) | |
399 self._Checkout(options, deps_branch, quiet=True) | |
400 if file_list is not None: | 399 if file_list is not None: |
401 files = self._Capture(['ls-files']).splitlines() | 400 files = self._Capture(['ls-files']).splitlines() |
402 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 401 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
403 if not verbose: | 402 if not verbose: |
404 # Make the output a little prettier. It's nice to have some whitespace | 403 # Make the output a little prettier. It's nice to have some whitespace |
405 # between projects when cloning. | 404 # between projects when cloning. |
406 self.Print('') | 405 self.Print('') |
407 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 406 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
408 | 407 |
409 if not managed: | 408 if not managed: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 | 443 |
445 # Cases: | 444 # Cases: |
446 # 0) HEAD is detached. Probably from our initial clone. | 445 # 0) HEAD is detached. Probably from our initial clone. |
447 # - make sure HEAD is contained by a named ref, then update. | 446 # - make sure HEAD is contained by a named ref, then update. |
448 # Cases 1-4. HEAD is a branch. | 447 # Cases 1-4. HEAD is a branch. |
449 # 1) current branch is not tracking a remote branch (could be git-svn) | 448 # 1) current branch is not tracking a remote branch (could be git-svn) |
450 # - try to rebase onto the new hash or branch | 449 # - try to rebase onto the new hash or branch |
451 # 2) current branch is tracking a remote branch with local committed | 450 # 2) current branch is tracking a remote branch with local committed |
452 # changes, but the DEPS file switched to point to a hash | 451 # changes, but the DEPS file switched to point to a hash |
453 # - rebase those changes on top of the hash | 452 # - rebase those changes on top of the hash |
454 # 3) current branch is tracking a remote branch w/or w/out changes, | 453 # 3) current branch is tracking a remote branch w/or w/out changes, and |
455 # no switch | 454 # no DEPS switch |
456 # - see if we can FF, if not, prompt the user for rebase, merge, or stop | 455 # - see if we can FF, if not, prompt the user for rebase, merge, or stop |
457 # 4) current branch is tracking a remote branch, switches to a different | 456 # 4) current branch is tracking a remote branch, but DEPS switches to a |
458 # remote branch | 457 # different remote branch, and |
459 # - exit | 458 # a) current branch has no local changes, and --force: |
| 459 # - checkout new branch |
| 460 # b) current branch has local changes, and --force and --reset: |
| 461 # - checkout new branch |
| 462 # c) otherwise exit |
460 | 463 |
461 # GetUpstreamBranch returns something like 'refs/remotes/origin/master' for | 464 # GetUpstreamBranch returns something like 'refs/remotes/origin/master' for |
462 # a tracking branch | 465 # a tracking branch |
463 # or 'master' if not a tracking branch (it's based on a specific rev/hash) | 466 # or 'master' if not a tracking branch (it's based on a specific rev/hash) |
464 # or it returns None if it couldn't find an upstream | 467 # or it returns None if it couldn't find an upstream |
465 if cur_branch is None: | 468 if cur_branch is None: |
466 upstream_branch = None | 469 upstream_branch = None |
467 current_type = "detached" | 470 current_type = "detached" |
468 logging.debug("Detached HEAD") | 471 logging.debug("Detached HEAD") |
469 else: | 472 else: |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 upstream_branch = revision | 530 upstream_branch = revision |
528 self._AttemptRebase(upstream_branch, files, options, | 531 self._AttemptRebase(upstream_branch, files, options, |
529 printed_path=printed_path, merge=options.merge) | 532 printed_path=printed_path, merge=options.merge) |
530 printed_path = True | 533 printed_path = True |
531 elif rev_type == 'hash': | 534 elif rev_type == 'hash': |
532 # case 2 | 535 # case 2 |
533 self._AttemptRebase(upstream_branch, files, options, | 536 self._AttemptRebase(upstream_branch, files, options, |
534 newbase=revision, printed_path=printed_path, | 537 newbase=revision, printed_path=printed_path, |
535 merge=options.merge) | 538 merge=options.merge) |
536 printed_path = True | 539 printed_path = True |
537 elif revision.replace('heads', 'remotes/' + self.remote) != upstream_branch: | 540 elif remote_ref and ''.join(remote_ref) != upstream_branch: |
538 # case 4 | 541 # case 4 |
539 new_base = revision.replace('heads', 'remotes/' + self.remote) | 542 new_base = ''.join(remote_ref) |
540 if not printed_path: | 543 if not printed_path: |
541 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 544 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) |
542 switch_error = ("Switching upstream branch from %s to %s\n" | 545 switch_error = ("Could not switch upstream branch from %s to %s\n" |
543 % (upstream_branch, new_base) + | 546 % (upstream_branch, new_base) + |
544 "Please merge or rebase manually:\n" + | 547 "Please use --force or merge or rebase manually:\n" + |
545 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + | 548 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + |
546 "OR git checkout -b <some new branch> %s" % new_base) | 549 "OR git checkout -b <some new branch> %s" % new_base) |
547 raise gclient_utils.Error(switch_error) | 550 force_switch = False |
| 551 if options.force: |
| 552 try: |
| 553 self._CheckClean(rev_str) |
| 554 # case 4a |
| 555 force_switch = True |
| 556 except gclient_utils.Error as e: |
| 557 if options.reset: |
| 558 # case 4b |
| 559 force_switch = True |
| 560 else: |
| 561 switch_error = '%s\n%s' % (e.message, switch_error) |
| 562 if force_switch: |
| 563 self.Print("Switching upstream branch from %s to %s" % |
| 564 (upstream_branch, new_base)) |
| 565 switch_branch = 'gclient_' + remote_ref[1] |
| 566 self._Capture(['branch', '-f', switch_branch, new_base]) |
| 567 self._Checkout(options, switch_branch, force=True, quiet=True) |
| 568 else: |
| 569 # case 4c |
| 570 raise gclient_utils.Error(switch_error) |
548 else: | 571 else: |
549 # case 3 - the default case | 572 # case 3 - the default case |
550 if files is not None: | 573 if files is not None: |
551 files = self._Capture(['diff', upstream_branch, '--name-only']).split() | 574 files = self._Capture(['diff', upstream_branch, '--name-only']).split() |
552 if verbose: | 575 if verbose: |
553 self.Print('Trying fast-forward merge to branch : %s' % upstream_branch) | 576 self.Print('Trying fast-forward merge to branch : %s' % upstream_branch) |
554 try: | 577 try: |
555 merge_args = ['merge'] | 578 merge_args = ['merge'] |
556 if options.merge: | 579 if options.merge: |
557 merge_args.append('--ff') | 580 merge_args.append('--ff') |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 except: | 886 except: |
864 traceback.print_exc(file=self.out_fh) | 887 traceback.print_exc(file=self.out_fh) |
865 raise | 888 raise |
866 finally: | 889 finally: |
867 if os.listdir(tmp_dir): | 890 if os.listdir(tmp_dir): |
868 self.Print('_____ removing non-empty tmp dir %s' % tmp_dir) | 891 self.Print('_____ removing non-empty tmp dir %s' % tmp_dir) |
869 gclient_utils.rmtree(tmp_dir) | 892 gclient_utils.rmtree(tmp_dir) |
870 if template_dir: | 893 if template_dir: |
871 gclient_utils.rmtree(template_dir) | 894 gclient_utils.rmtree(template_dir) |
872 self._UpdateBranchHeads(options, fetch=True) | 895 self._UpdateBranchHeads(options, fetch=True) |
873 self._Checkout(options, revision.replace('refs/heads/', ''), quiet=True) | 896 remote_ref = scm.GIT.RefToRemoteRef(revision, self.remote) |
| 897 self._Checkout(options, ''.join(remote_ref or revision), quiet=True) |
874 if self._GetCurrentBranch() is None: | 898 if self._GetCurrentBranch() is None: |
875 # Squelch git's very verbose detached HEAD warning and use our own | 899 # Squelch git's very verbose detached HEAD warning and use our own |
876 self.Print( | 900 self.Print( |
877 ('Checked out %s to a detached HEAD. Before making any commits\n' | 901 ('Checked out %s to a detached HEAD. Before making any commits\n' |
878 'in this repo, you should use \'git checkout <branch>\' to switch to\n' | 902 'in this repo, you should use \'git checkout <branch>\' to switch to\n' |
879 'an existing branch or use \'git checkout %s -b <branch>\' to\n' | 903 'an existing branch or use \'git checkout %s -b <branch>\' to\n' |
880 'create a new branch for your work.') % (revision, self.remote)) | 904 'create a new branch for your work.') % (revision, self.remote)) |
881 | 905 |
882 def _AskForData(self, prompt, options): | 906 def _AskForData(self, prompt, options): |
883 if options.jobs > 1: | 907 if options.jobs > 1: |
(...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1576 new_command.append('--force') | 1600 new_command.append('--force') |
1577 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1601 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1578 new_command.extend(('--accept', 'theirs-conflict')) | 1602 new_command.extend(('--accept', 'theirs-conflict')) |
1579 elif options.manually_grab_svn_rev: | 1603 elif options.manually_grab_svn_rev: |
1580 new_command.append('--force') | 1604 new_command.append('--force') |
1581 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1605 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1582 new_command.extend(('--accept', 'postpone')) | 1606 new_command.extend(('--accept', 'postpone')) |
1583 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1607 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1584 new_command.extend(('--accept', 'postpone')) | 1608 new_command.extend(('--accept', 'postpone')) |
1585 return new_command | 1609 return new_command |
OLD | NEW |