|
44 | 44 | r'^(?!.*/\.)(?!.*\.\.)(?!/)(?!.*//)(?!.*@\{)(?!.*\\)'
|
45 | 45 | r'[^\040\177 ~^:?*[]+(?<!\.lock)(?<!/)(?<!\.)$')
|
46 | 46 |
|
| 47 | +GIT_COMMIT_REGEX = re.compile(r'[0-9a-f]{5,40}') |
| 48 | + |
47 | 49 | # the name of the branch which holds the vanilla clone of sage
|
48 | 50 | MASTER_BRANCH = "master"
|
49 | 51 | USER_BRANCH = re.compile(r"^u/([^/]+)/")
|
@@ -3157,6 +3159,26 @@ def merge(self, ticket_or_branch=MASTER_BRANCH, pull=None, create_dependency=Non
|
3157 | 3159 | Cannot merge because working directory is not in a clean state.
|
3158 | 3160 | <BLANKLINE>
|
3159 | 3161 | # (use "sage --dev commit" to commit your changes)
|
| 3162 | +
|
| 3163 | + Merging a ticket whose branch field points to a commit checks whether |
| 3164 | + the commit is present in the current branch:: |
| 3165 | +
|
| 3166 | + sage: alice.trac.set_attributes(1, branch='12345678') |
| 3167 | + sage: alice._UI.append("discard") |
| 3168 | + sage: alice.merge(ticket_or_branch=1, pull=True) |
| 3169 | + The following files in your working directory contain uncommitted changes: |
| 3170 | + <BLANKLINE> |
| 3171 | + alice2 |
| 3172 | + <BLANKLINE> |
| 3173 | + Discard changes? [discard/Cancel/stash] discard |
| 3174 | + # It seems that the branch for #1 has already been merged in the latest version of sage. The branch field on #1 points to the commit "12345678". |
| 3175 | + Failed to determine whether commit "12345678" is present in the current branch "ticket/2". Is your "master" branch up to date? |
| 3176 | + sage: sha = alice.git.show_ref('master',hash=True)[:8] |
| 3177 | + sage: alice.trac.set_attributes(1, branch=sha) |
| 3178 | + sage: alice.merge(ticket_or_branch=1, pull=True) |
| 3179 | + # It seems that the branch for #1 has already been merged in the latest version of sage. The branch field on #1 points to the commit "...". |
| 3180 | + Your branch "ticket/2" already contains commit "...". Nothing to merge. |
| 3181 | +
|
3160 | 3182 | """
|
3161 | 3183 | try:
|
3162 | 3184 | self.reset_to_clean_state()
|
@@ -3238,9 +3260,34 @@ def merge(self, ticket_or_branch=MASTER_BRANCH, pull=None, create_dependency=Non
|
3238 | 3260 | if pull:
|
3239 | 3261 | assert remote_branch
|
3240 | 3262 | if not self._is_remote_branch_name(remote_branch, exists=True):
|
| 3263 | + if ticket and self._is_commit_name(remote_branch): |
| 3264 | + commit = remote_branch |
| 3265 | + self._UI.info('It seems that the branch for #{0} has already been merged in the latest version of sage. The branch field on #{0} points to the commit "{1}".', ticket, commit) |
| 3266 | + from git_error import GitError |
| 3267 | + try: |
| 3268 | + branches = self.git.branch(contains=commit) |
| 3269 | + except GitError as e: |
| 3270 | + self._UI.error('Failed to determine whether commit "{0}" is present in the current branch "{1}". Is your "{2}" branch up to date?', commit, current_branch, MASTER_BRANCH) |
| 3271 | + raise OperationCancelledError("unknown commit") |
| 3272 | + present_in_master = False |
| 3273 | + for present_in_branch in branches.split(): |
| 3274 | + present_in_branch = present_in_branch.split()[-1] |
| 3275 | + if current_branch == present_in_branch: |
| 3276 | + self._UI.show('Your branch "{0}" already contains commit "{1}". Nothing to merge.', current_branch, commit) |
| 3277 | + return |
| 3278 | + if MASTER_BRANCH == present_in_branch: |
| 3279 | + present_in_master = True |
| 3280 | + self._UI.show('Your branch "{0}" does not contain commit "{1}". Merging of remote commits is not implemented. You need to merge manually.', current_branch, commit) |
| 3281 | + if present_in_master: |
| 3282 | + self._UI.info('Merge "{0}" into your branch "{1}" with "{2}".', MASTER_BRANCH, current_branch, self._format_command("merge")) |
| 3283 | + else: |
| 3284 | + self._UI.info('Your branch "{0}" seems to be out of date. Pull the latest changes to "{0}" with "{1}" and "{2}". Then come back to this branch and merge "{0}" with "{3}" and "{4}".', MASTER_BRANCH, self._format_command("checkout", branch=MASTER_BRANCH), self._format_command("pull"), self._format_command("checkout", branch=current_branch), self._format_command("merge")) |
| 3285 | + raise OperationCancelledError("Remote commit merge not implemented.") |
| 3286 | + |
3241 | 3287 | self._UI.error('Can not merge remote branch "{0}". It does not exist.',
|
3242 | 3288 | remote_branch)
|
3243 | 3289 | raise OperationCancelledError("no such branch")
|
| 3290 | + |
3244 | 3291 | self._UI.show('Merging the remote branch "{0}" into the local branch "{1}".',
|
3245 | 3292 | remote_branch, current_branch)
|
3246 | 3293 | self.git.super_silent.fetch(self.git._repository_anonymous, remote_branch)
|
@@ -4357,6 +4404,33 @@ def _is_local_branch_name(self, name, exists=any):
|
4357 | 4404 | else:
|
4358 | 4405 | raise ValueError("exists")
|
4359 | 4406 |
|
| 4407 | + def _is_commit_name(self, name): |
| 4408 | + r""" |
| 4409 | + Return whether ``name`` is a valid name for a commit. |
| 4410 | +
|
| 4411 | + INPUT: |
| 4412 | +
|
| 4413 | + - ``name`` -- a string |
| 4414 | +
|
| 4415 | + TESTS:: |
| 4416 | +
|
| 4417 | + sage: from sage.dev.test.sagedev import single_user_setup |
| 4418 | + sage: dev, config, UI, server = single_user_setup() |
| 4419 | + sage: dev = dev._sagedev |
| 4420 | +
|
| 4421 | + sage: dev._is_commit_name('') |
| 4422 | + False |
| 4423 | + sage: dev._is_commit_name('ticket/1') |
| 4424 | + False |
| 4425 | + sage: dev._is_commit_name('12345a78') |
| 4426 | + True |
| 4427 | +
|
| 4428 | + """ |
| 4429 | + if not isinstance(name, str): |
| 4430 | + raise ValueError("name must be a string") |
| 4431 | + |
| 4432 | + return bool(GIT_COMMIT_REGEX.match(name)) |
| 4433 | + |
4360 | 4434 | def _is_trash_name(self, name, exists=any):
|
4361 | 4435 | r"""
|
4362 | 4436 | Return whether ``name`` is a valid name for an abandoned branch.
|
|
0 commit comments