From d592894f280e0d12a50b7342890375dbbb3c98e4 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Mon, 6 Jul 2026 08:22:41 +0200 Subject: [PATCH 1/3] fix(git): split long path args to avoid Windows CreateProcess limit Git operations that stage or restore many files could exceed the Windows command line length limit, causing os error 206 failures. This change splits file paths into size-bounded chunks and concatenates the output from multiple git invocations to keep commands within safe limits. - Chunk file path arguments for Windows compatibility - Add a local dev command to list pkg-config packages --- .claude/settings.local.json | 3 ++- package-lock.json | 4 ++-- src-tauri/src/git.rs | 41 ++++++++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f7ccea6..7d9e6ce 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -78,7 +78,8 @@ "Bash(rustfmt --edition 2024 --check src/badge.rs src/main.rs)", "Bash(rustfmt --edition 2024 --check src/git.rs)", "Bash(rustfmt --edition 2024 --check src/badge.rs)", - "Bash(rustfmt --edition 2024 --check src/git.rs src/main.rs)" + "Bash(rustfmt --edition 2024 --check src/git.rs src/main.rs)", + "Bash(pkg-config --list-all)" ] } } diff --git a/package-lock.json b/package-lock.json index 589dd3e..a7855eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "git-lite", - "version": "2026.7.12", + "version": "2026.7.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "git-lite", - "version": "2026.7.12", + "version": "2026.7.11", "dependencies": { "@lucide/svelte": "^1.21.0", "@tailwindcss/vite": "^4.3.1", diff --git a/src-tauri/src/git.rs b/src-tauri/src/git.rs index 7d25b81..a3a67c8 100644 --- a/src-tauri/src/git.rs +++ b/src-tauri/src/git.rs @@ -3415,16 +3415,47 @@ fn is_auth_error(details: &str) -> bool { || d.contains("authentication required") } +// Windows' CreateProcess rejects command lines longer than ~32K chars with +// "os error 206" (filename or extension too long). Staging/restoring a large +// number of files can easily exceed that, so split the paths across multiple +// invocations and concatenate their output. +const MAX_PATH_ARGS_CHARS: usize = 8_000; + fn run_git_with_paths( repo: &Path, base_args: &[&str], files: &[String], ) -> Result, String> { - let mut args = Vec::with_capacity(base_args.len() + files.len() + 1); - args.extend(base_args.iter().map(OsString::from)); - args.push(OsString::from("--")); - args.extend(files.iter().map(OsString::from)); - run_git(repo, args) + if files.is_empty() { + let args: Vec = base_args.iter().map(OsString::from).collect(); + return run_git(repo, args); + } + + let mut combined = Vec::new(); + let mut start = 0; + while start < files.len() { + let mut end = start; + let mut chunk_chars = 0usize; + while end < files.len() { + let len = files[end].len() + 1; + if end > start && chunk_chars + len > MAX_PATH_ARGS_CHARS { + break; + } + chunk_chars += len; + end += 1; + } + let chunk = &files[start..end]; + + let mut args = Vec::with_capacity(base_args.len() + chunk.len() + 1); + args.extend(base_args.iter().map(OsString::from)); + args.push(OsString::from("--")); + args.extend(chunk.iter().map(OsString::from)); + combined.extend(run_git(repo, args)?); + + start = end; + } + + Ok(combined) } fn run_git_with_paths_cancellable( -- 2.54.0 From aaa4228b82cc807cc1c2f0aadf4a0a6afd79c2b6 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Mon, 6 Jul 2026 11:16:52 +0200 Subject: [PATCH 2/3] feat(history): add commit action context menu in HistoryPanel The commit history UI now provides a compact actions menu per commit, with positioning constrained to the history panel. The menu supports keyboard dismissal via Escape and closes on outside clicks to keep the interaction predictable. - Replace per-commit action buttons with an ellipsis menu - Add context menu state and panel-relative positioning logic - Style the new history context menu and menu button --- src/app.css | 27 ++++++- src/lib/components/HistoryPanel.svelte | 102 ++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/app.css b/src/app.css index 1d1be11..6dac7bd 100644 --- a/src/app.css +++ b/src/app.css @@ -1639,6 +1639,7 @@ .branch-actions .btn-sm { min-height: 24px; padding: 0 6px; font-size: 11px; } .branch-context-menu, + .history-context-menu, .explorer-context-menu { z-index: 120; display: grid; @@ -1651,10 +1652,12 @@ box-shadow: 0 18px 50px rgba(0,0,0,0.5); } - .branch-context-menu { position: absolute; } + .branch-context-menu, + .history-context-menu { position: absolute; } .explorer-context-menu { position: fixed; } .branch-context-menu button, + .history-context-menu button, .explorer-context-menu button { display: flex; align-items: center; @@ -1673,13 +1676,15 @@ } .branch-context-menu button:hover:not(:disabled), + .history-context-menu button:hover:not(:disabled), .explorer-context-menu button:hover:not(:disabled) { border-color: var(--color-border-subtle); background: rgba(255,255,255,0.06); color: var(--color-ink); } - .branch-context-menu .menu-separator { + .branch-context-menu .menu-separator, + .history-context-menu .menu-separator { height: 1px; margin: 4px 3px; background: var(--color-border-subtle); @@ -1696,6 +1701,7 @@ } .branch-context-menu button:disabled, + .history-context-menu button:disabled, .explorer-context-menu button:disabled { cursor: not-allowed; opacity: 0.48; @@ -1817,6 +1823,7 @@ /* --- Commit history --- */ + .history-panel { position: relative; } .history-list { min-width: 0; padding: 6px; overflow: auto; } .commit-row { display: grid; min-width: 0; gap: 8px; padding: 10px; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: var(--color-surface-raised); transition: border-color 120ms; } @@ -2017,6 +2024,22 @@ } .commit-action-buttons { display: flex; flex: 0 0 auto; align-items: center; gap: 5px; } .commit-action-buttons button { flex: 0 0 auto; white-space: nowrap; } + .commit-menu-button { + width: 28px; + min-width: 28px; + min-height: 26px; + padding: 0; + border-color: rgba(94,110,156,0.16); + border-radius: 7px; + background: rgba(255,255,255,0.035); + color: var(--color-ink-dim); + } + .commit-menu-button:hover:not(:disabled), + .commit-menu-button[aria-expanded="true"] { + border-color: rgba(65,209,255,0.28); + background: rgba(65,209,255,0.08); + color: var(--color-ink); + } .file-history-head { align-items: flex-start; } .file-history-heading { min-width: 0; flex: 1 1 auto; overflow: hidden; } .section-head .file-history-name { diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index 4e56f2b..7fa3fb3 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -1,5 +1,5 @@ - + -
+
History @@ -433,7 +485,12 @@ {@const row = graphRows[rowIndex]} {@const hoverBranchRefs = visibleBranchLabels(row?.branchLabels ?? [])} {@const otherRefs = visibleRefs(item)} -
1} class:root-row={item.parents.length === 0} class:tip-row={item.refs.length > 0}> +
1} + class:root-row={item.parents.length === 0} + class:tip-row={item.refs.length > 0} + > {/if} + + {#if contextCommit} + + {/if}
{#if branchDialogOpen} -- 2.54.0 From eac0f059fac2427559c3b56d0e731fae730b18d7 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Mon, 6 Jul 2026 11:31:41 +0200 Subject: [PATCH 3/3] feat(history): improve commit hover branch labels and titles The history panel now generates more informative hover text for commits. It prefers direct local branch refs when available, otherwise it derives a concise list from containing branch labels and summarizes overflow. - Add helpers to compute hover branch labels and title text - Update the graph row hover rendering to use the new helpers --- src/lib/components/HistoryPanel.svelte | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index 7fa3fb3..49f9885 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -207,6 +207,24 @@ return labels.filter(branchIsVisible); } + function commitHoverBranchLabels(commit: GitCommit, row: GraphRow | undefined): string[] { + const directBranches = localBranchRefs(commit); + if (directBranches.length > 0) return directBranches; + + const containingBranches = row?.branchLabels ?? []; + if (containingBranches.length <= 3) return containingBranches; + return [...containingBranches.slice(0, 3), `+${containingBranches.length - 3} more`]; + } + + function commitHoverTitle(commit: GitCommit, row: GraphRow | undefined): string { + const directBranches = localBranchRefs(commit); + if (directBranches.length > 0) return `Branches: ${directBranches.join(", ")}`; + + const containingBranches = row?.branchLabels ?? []; + if (containingBranches.length === 0) return commit.short_hash; + return `Branches containing this commit: ${containingBranches.join(", ")}`; + } + function segmentIsVisible(segment: GraphSegment): boolean { return segment.branches.length === 0 || segment.branches.some(branchIsVisible); } @@ -483,7 +501,7 @@ {#each visibleCommitEntries as entry, rowIndex (entry.commit.hash)} {@const item = entry.commit} {@const row = graphRows[rowIndex]} - {@const hoverBranchRefs = visibleBranchLabels(row?.branchLabels ?? [])} + {@const hoverBranchRefs = commitHoverBranchLabels(item, row)} {@const otherRefs = visibleRefs(item)}
1} class:tip={item.refs.length > 0} class:hidden-branch={!rowGraphIsVisible(row)} - title={hoverBranchRefs.length > 0 ? `Contained in: ${hoverBranchRefs.join(", ")}` : item.short_hash} + title={commitHoverTitle(item, row)} style={`left:${graphColX(row.dotCol)}px; --dot-color:${row.dotColor}`} > {#if hoverBranchRefs.length > 0} -- 2.54.0