5c5e7bf6a7
* fix(changes-panel): scope commits/diff to live branch divergence; flatten single-repo Two bugs in the COMMITS panel made it surface commits and file changes that were already on main: 1. The commit list and the cumulative diff both anchored to a stale base. Commit list used `git merge-base HEAD <local-branch>` and the file diff used the session's stored base SHA captured once at session start. On long-lived worktrees the local main ref lags far behind origin/main, so the merge-base lands on an old SHA; once the agent merges main back in, the stored base is also stale. Both end up sweeping in dozens of main commits as if they were the branch's work. 2. `git log <base>..HEAD` follows both parents of a merge commit by default, surfacing main commits brought in via merges from main. Fixes: - agentctl computes merge-base against `origin/<target_branch>` (with a local-ref fallback for unfetched/local-only branches), and uses that for both the commit log and the cumulative diff. Mirrors GitHub's three-dot PR diff semantics — anchor to live divergence with the upstream, not a session-start snapshot. - `git log` now passes `--first-parent` so only the branch's own line of work plus its merge commits show up; commits brought in via merges from main are excluded. Frontend: drop the per-repo "REPOSITORY" sub-header in the COMMITS panel for single-repo workspaces. CommitsRepoGroup gains a `showHeader` prop; when the workspace has one untagged group the section renders flat with the per-repo Push / PR (and Stage all / Commit / Unstage all) buttons lifted into the section header. Multi-repo rendering unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: address PR review feedback - Scope --first-parent to the divergence-range path only (Greptile P1). The flag is wrong for open-ended history calls — future activity widgets etc. need the full graph. - Log empty merge-base case in cumulative diff (Greptile P2). Silent fallback to stored base was invisible during diagnostics. - Rename TestRunGitCumulativeDiffForRepo_PrefersOriginRef → TestComputeMergeBase_CorrectAnchorForCumulativeDiff (Claude). Test exercises computeMergeBase, not the runGitCumulativeDiffForRepo conditional; new name reflects what it actually proves. - Add TestGetLog_NoBaseReturnsFullGraph to lock in the --first-parent scoping. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: address PR review round 2 - Drop dead ActionButtonsSection from changes-panel-timeline.tsx (unused export, no consumers anywhere). Brings the file from 640 → 516 lines, comfortably under the 600-line TS limit Claude flagged. - Extract isSingleRepoGroup helper into lib/group-by-repo.ts and use it in all three sites (CommitsSection, FileListBody, FileListSection) so single-repo detection has one source of truth. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
/**
|
|
* Buckets a list into per-repository groups, preserving the original item
|
|
* order within each bucket and producing groups in first-seen order. Items
|
|
* whose `getName` returns undefined or empty land in a single empty-named
|
|
* group so callers can decide whether to render a header for it.
|
|
*
|
|
* One copy of this lived in three places before — review-diff-list-groups,
|
|
* changes-panel-timeline (files), and changes-panel-timeline (commits) —
|
|
* differing only in element type. The generic shape collapses them all.
|
|
*/
|
|
export function groupByRepositoryName<T>(
|
|
items: T[],
|
|
getName: (item: T) => string | undefined,
|
|
): Array<{ repositoryName: string; items: T[] }> {
|
|
const order: string[] = [];
|
|
const buckets = new Map<string, T[]>();
|
|
for (const item of items) {
|
|
const name = getName(item) ?? "";
|
|
if (!buckets.has(name)) {
|
|
buckets.set(name, []);
|
|
order.push(name);
|
|
}
|
|
buckets.get(name)!.push(item);
|
|
}
|
|
return order.map((name) => ({ repositoryName: name, items: buckets.get(name)! }));
|
|
}
|
|
|
|
/**
|
|
* True when the grouped output represents a single-repo workspace — exactly
|
|
* one bucket with the empty-name key. Callers use this to drop the redundant
|
|
* per-repo sub-header in the changes panel and lift action buttons up to the
|
|
* section header. Single source of truth so the three call sites
|
|
* (CommitsSection, FileListBody, FileListSection) stay in sync.
|
|
*/
|
|
export function isSingleRepoGroup(groups: Array<{ repositoryName: string }>): boolean {
|
|
return groups.length === 1 && groups[0].repositoryName === "";
|
|
}
|