Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625)
- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790)

### Changed
- Added commit graph generation to improve performance for commit traversal operations. [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)

## [4.10.17] - 2026-01-23

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion docs/docs/connections/local-repos.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,6 @@ To get Sourcebot to index these repositories:

## Examples


<AccordionGroup>
<Accordion title="Sync individual repo">
```json
Expand All@@ -76,6 +75,22 @@ To get Sourcebot to index these repositories:
</Accordion>
</AccordionGroup>

## Optimizing git operations

Sourcebot performs a number of operations that require traversing a repository's entire commit history (e.g., `git rev-list --count HEAD`). These operations can be slow in repositories with a large number of commits.

Typically, a [commit graph](https://git-scm.com/docs/commit-graph) is generated to speed up these operations (see [#791](https://github.com/sourcebot-dev/sourcebot/pull/791)). However, since local repositories are treated as read-only, Sourcebot **will not** generate a commit graph for them.

A commit graph can be manually generated by running the following command in the repository's root directory:
```sh
git commit-graph write --reachable
```

The commit graph can be updated when fetching with `--write-commit-graph`:
```sh
git fetch --write-commit-graph
```

## Schema reference

<Accordion title="Reference">
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/git.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,12 @@ export const cloneRepository = async (
keys: ["remote.origin.url"],
signal,
});

// @note: operations that need to iterate over a lot of commits (e.g., rev-list --count)
// can be slow on larger repositories. Commit graphs are a acceleration structure that
// speed up these operations.
// @see: https://git-scm.com/docs/commit-graph
await writeCommitGraph({ path, signal });
} catch (error: unknown) {
const baseLog = `Failed to clone repository: ${path}`;

Expand DownExpand Up@@ -121,7 +127,10 @@ export const fetchRepository = async (
cloneUrl,
"+refs/heads/*:refs/heads/*",
"--prune",
"--progress"
"--progress",
// On fetch, ensure the commit graph is up to date.
// @see: https://git-scm.com/docs/commit-graph
"--write-commit-graph"
]);

// Update HEAD to match the remote's default branch. This handles the case where the remote's
Expand DownExpand Up@@ -405,3 +414,27 @@ export const getLatestCommitTimestamp = async ({
return undefined;
}
}

/**
* Writes or updates the commit-graph file for the repository.
* This pre-computes commit metadata to speed up operations like
* rev-list --count, log, and merge-base.
*/
export const writeCommitGraph = async ({
path,
onProgress,
signal,
}: {
path: string,
onProgress?: onProgressFn,
signal?: AbortSignal,
}): Promise<void> => {
const git = createGitClientForPath(path, onProgress, signal);

try {
await git.raw(['commit-graph', 'write', '--reachable']);
} catch (error) {
// Don't throw an exception here since this is just a performance optimization.
logger.debug(`Failed to write commit-graph for ${path}:`, error);
}
}