From 48bdd2a2de11bfac3ac25fcb9930dbbf44fcddef Mon Sep 17 00:00:00 2001 From: Konstantin Ryabitsev Date: Tue, 22 Jun 2021 10:10:16 -0400 Subject: Additional --guess-base refinements Use --all by default, instead of limiting ourselves just to the current HEAD. This is actually a faster operation, because we don't have to pre-filter results. Signed-off-by: Konstantin Ryabitsev --- b4/__init__.py | 52 +++++++++++++++++++++++++++++++++------------------- b4/command.py | 4 ++-- b4/mbox.py | 19 +++++++++++-------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/b4/__init__.py b/b4/__init__.py index 53eaf27..9a18d00 100644 --- a/b4/__init__.py +++ b/b4/__init__.py @@ -630,7 +630,7 @@ class LoreSeries: return msgs - def check_applies_clean(self, gitdir, at='HEAD'): + def check_applies_clean(self, gitdir: str, at: Optional[str] = None) -> Tuple[int, list]: if self._indexes is None: self._indexes = list() seenfiles = set() @@ -649,6 +649,8 @@ class LoreSeries: self._indexes.append((fn, bh)) mismatches = list() + if at is None: + at = 'HEAD' for fn, bh in self._indexes: ecode, out = git_run_command(gitdir, ['ls-tree', at, fn]) if ecode == 0 and len(out): @@ -665,7 +667,7 @@ class LoreSeries: return len(self._indexes), mismatches - def find_base(self, gitdir: str, branches: str = 'HEAD', maxdays: int = 30) -> Tuple[str, len]: + def find_base(self, gitdir: str, branches: Optional[str] = None, maxdays: int = 30) -> Tuple[str, len, len]: # Find the date of the first patch we have pdate = datetime.datetime.now() for lmsg in self.patches: @@ -676,7 +678,12 @@ class LoreSeries: # Find latest commit on that date guntil = pdate.strftime('%Y-%m-%d') - gitargs = ['log', '--pretty=oneline', '--until', guntil, '--max-count=1', '--branches', branches] + if branches: + where = ['--branches', branches] + else: + where = ['--all'] + + gitargs = ['log', '--pretty=oneline', '--until', guntil, '--max-count=1'] + where lines = git_get_command_lines(gitdir, gitargs) if not lines: raise IndexError @@ -689,34 +696,41 @@ class LoreSeries: logger.debug('Starting --find-object from %s to %s', gsince, guntil) best = commit for fn, bi in mismatches: - logger.debug('Finding tree matching %s=%s in %s', fn, bi, branches) - gitargs = ['log', '-m', '--pretty=oneline', '--since', gsince, '--until', guntil, - '--max-count=1', '--find-object', bi, '--branches', branches] + logger.debug('Finding tree matching %s=%s in %s', fn, bi, where) + gitargs = ['log', '--pretty=oneline', '--since', gsince, '--until', guntil, + '--find-object', bi] + where lines = git_get_command_lines(gitdir, gitargs) if not lines: logger.debug('Could not find object %s in the tree', bi) continue - commit = lines[0].split()[0] - logger.debug('commit=%s', commit) - # We try both that commit and the one preceding it, in case it was a delete - # Keep track of the fewest mismatches - for tc in [commit, f'{commit}~1']: - sc, sm = self.check_applies_clean(gitdir, tc) - if len(sm) < fewest and len(sm) != sc: - fewest = len(sm) - best = tc - logger.debug('fewest=%s, best=%s', fewest, best) + for line in lines: + commit = line.split()[0] + logger.debug('commit=%s', commit) + # We try both that commit and the one preceding it, in case it was a delete + # Keep track of the fewest mismatches + for tc in [commit, f'{commit}~1']: + sc, sm = self.check_applies_clean(gitdir, tc) + if len(sm) < fewest and len(sm) != sc: + fewest = len(sm) + best = tc + logger.debug('fewest=%s, best=%s', fewest, best) + if fewest == 0: + break if fewest == 0: break - + if fewest == 0: + break if fewest == 0: break else: best = commit + if fewest == len(self._indexes): + # None of the blobs matched + raise IndexError - lines = git_get_command_lines(gitdir, ['describe', best]) + lines = git_get_command_lines(gitdir, ['describe', '--all', best]) if len(lines): - return lines[0], fewest + return lines[0], len(self._indexes), fewest raise IndexError diff --git a/b4/command.py b/b4/command.py index ebbb361..5bb3384 100644 --- a/b4/command.py +++ b/b4/command.py @@ -120,8 +120,8 @@ def cmd(): '"-P *globbing*" to match on commit subject)') sp_am.add_argument('-g', '--guess-base', dest='guessbase', action='store_true', default=False, help='Try to guess the base of the series (if not specified)') - sp_am.add_argument('-b', '--guess-branch', dest='guessbranch', default='HEAD', - help='When guessing base, use this branch instead of HEAD (use with -g)') + sp_am.add_argument('-b', '--guess-branch', dest='guessbranch', default=None, + help='When guessing base, restrict to this branch (use with -g)') sp_am.add_argument('--guess-lookback', dest='guessdays', type=int, default=14, help='When guessing base, go back this many days from the date of the patch') sp_am.add_argument('-3', '--prep-3way', dest='threeway', action='store_true', default=False, diff --git a/b4/mbox.py b/b4/mbox.py index 98bd920..7adfecd 100644 --- a/b4/mbox.py +++ b/b4/mbox.py @@ -230,23 +230,26 @@ def make_am(msgs, cmdargs, msgid): logger.critical(' Base: %s', base_commit) else: if topdir is not None: + guessed = False checked, mismatches = lser.check_applies_clean(topdir, at=cmdargs.guessbranch) if len(mismatches) == 0 and checked != mismatches: + guessed = True logger.critical(' Base: current tree') - elif len(mismatches) and cmdargs.guessbase: + if not guessed and cmdargs.guessbase: logger.critical(' attempting to guess base-commit...') try: - base_commit, mismatches = lser.find_base(topdir, branches=cmdargs.guessbranch, - maxdays=cmdargs.guessdays) + base_commit, nblobs, mismatches = lser.find_base(topdir, branches=cmdargs.guessbranch, + maxdays=cmdargs.guessdays) if mismatches == 0: logger.critical(' Base: %s (exact match)', base_commit) + elif nblobs == mismatches: + logger.critical(' Base: failed to guess base') else: - logger.critical(' Base: %s (best guess, %s blobs not matched)', base_commit, - mismatches) + logger.critical(' Base: %s (best guess, %s/%s blobs matched)', base_commit, + nblobs-mismatches, nblobs) except IndexError: - logger.critical(' Base: not specified') - pass - else: + logger.critical(' Base: failed to guess base') + elif not cmdargs.guessbase: logger.critical(' Base: not specified') else: logger.critical(' Base: not specified') -- cgit v1.2.3