Skip to content

Commit 204c6e4

Browse files
committed
Moves GK metadata to a dedicated config file
- Adds a separate storage location at `.git/gk/config` for custom branch metadata to avoid cluttering the primary Git config and causing repo changes
1 parent b02e94c commit 204c6e4

File tree

7 files changed

+420
-176
lines changed

7 files changed

+420
-176
lines changed

src/constants.ts

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,33 +59,28 @@ export type GitCoreConfigKeys =
5959
| 'init.defaultBranch'
6060
| 'user.signingkey';
6161

62-
/**
63-
* `gk-merge-target` means the branch that the current branch is most likely to be merged into, e.g.
64-
* - branch to compare with by default
65-
* - default target for creating a PR
66-
* - etc.
67-
*
68-
* `gk-merge-target-user` — merge target branch explicitly defined by user,
69-
* if it's defined we use this value instead of `gk-merge-target`, but we keep storing `gk-merge-target` value that was determined automatically.
70-
*
71-
* `gk-merge-base` means the branch that the current branch originates from, e.g. what was the base in the moment of creation.
72-
* This value is used for: ... (TODO describe use cases).
73-
*
74-
* `vscode-merge-base` — value determined by VS Code that is used to determine the merge base for the current branch.
75-
* once `gk-merge-base` is determined, we stop using `vscode-merge-base`
76-
*
77-
*/
7862
export type GitConfigKeys =
63+
| GitCoreConfigKeys
64+
/** `vscode-merge-base` — value determined by VS Code that is used to determine the merge base for the current branch. Once `gk-merge-base` is determined, we stop using `vscode-merge-base` */
7965
| `branch.${string}.vscode-merge-base`
66+
/** `github-pr-owner-number` — value determined by VS Code/GitHub PR extension that is used to determine the PR number for the current branch */
67+
| `branch.${string}.github-pr-owner-number`;
68+
69+
export type GkConfigKeys =
70+
/** `gk-merge-base` — the branch that the current branch was created from (the original base at branch creation time) */
8071
| `branch.${string}.gk-merge-base`
72+
/** `gk-merge-target` — the auto-detected branch that the current branch will likely be merged into (used for comparisons, PR targets, etc.) */
8173
| `branch.${string}.gk-merge-target`
74+
/** `gk-merge-target-user` — user-specified merge target branch; takes precedence over auto-detected `gk-merge-target` */
8275
| `branch.${string}.gk-merge-target-user`
76+
/** `gk-associated-issues` — JSON array of issue/PR entity identifiers linked to this branch */
8377
| `branch.${string}.gk-associated-issues`
84-
| `branch.${string}.github-pr-owner-number`
78+
/** `gk-last-accessed` — ISO 8601 timestamp of when the branch was last checked out or viewed */
8579
| `branch.${string}.gk-last-accessed`
80+
/** `gk-last-modified` — ISO 8601 timestamp of when the branch last received a commit */
8681
| `branch.${string}.gk-last-modified`;
8782

88-
export type DeprecatedGitConfigKeys = `branch.${string}.gk-target-base`;
83+
export type DeprecatedGkConfigKeys = `branch.${string}.gk-target-base`;
8984

9085
export const enum GlyphChars {
9186
AngleBracketLeftHeavy = '\u2770',

src/env/node/git/sub-providers/branches.ts

Lines changed: 33 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -542,26 +542,18 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
542542
if (data == null) {
543543
const defaultBranch =
544544
(await this.provider.config.getConfig(repoPath, 'init.defaultBranch')) ?? 'main';
545-
const branchConfig = await this.provider.config.getConfigRegex(
545+
const configMap = await this.provider.config.getConfigRegex(
546546
repoPath,
547547
`branch\\.${defaultBranch}\\.+`,
548548
{ runGitLocally: true },
549549
);
550550

551-
let remote;
552-
let remoteBranch;
551+
const remote = configMap.get(`branch.${defaultBranch}.remote`);
552+
const merge = configMap.get(`branch.${defaultBranch}.merge`);
553+
const remoteBranch = merge?.startsWith('refs/heads/')
554+
? merge.substring('refs/heads/'.length)
555+
: undefined;
553556

554-
if (branchConfig) {
555-
let match = /^branch\..+\.remote\s(.+)$/m.exec(branchConfig);
556-
if (match != null) {
557-
remote = match[1];
558-
}
559-
560-
match = /^branch\..+\.merge\srefs\/heads\/(.+)$/m.exec(branchConfig);
561-
if (match != null) {
562-
remoteBranch = match[1];
563-
}
564-
}
565557
data = [
566558
`${defaultBranch}${remote && remoteBranch ? `\n${remote}/${remoteBranch}` : ''}`,
567559
undefined,
@@ -1135,37 +1127,23 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
11351127
cancellation?: CancellationToken,
11361128
): Promise<string | undefined> {
11371129
try {
1138-
const pattern = `^branch\\.${ref}\\.`;
1139-
const data = await this.provider.config.getConfigRegex?.(repoPath, pattern);
1140-
if (data) {
1141-
const regex = new RegExp(`${pattern}(.+) (.+)$`, 'gm');
1142-
1143-
let mergeBase: string | undefined;
1144-
let update = false;
1145-
while (true) {
1146-
const match = regex.exec(data);
1147-
if (match == null) break;
1148-
1149-
const [, key, value] = match;
1150-
if (key === 'gk-merge-base') {
1151-
mergeBase = value;
1152-
update = false;
1153-
break;
1154-
} else if (key === 'vscode-merge-base') {
1155-
mergeBase = value;
1156-
update = true;
1157-
continue;
1158-
}
1159-
}
1130+
// getGkConfig has built-in fallback to regular config for backward compatibility
1131+
let mergeBase = await this.provider.config.getGkConfig(repoPath, `branch.${ref}.gk-merge-base`);
1132+
let update = false;
1133+
1134+
// Also check vscode-merge-base in regular config (VS Code compatibility)
1135+
if (mergeBase == null) {
1136+
mergeBase = await this.provider.config.getConfig(repoPath, `branch.${ref}.vscode-merge-base`);
1137+
update = mergeBase != null;
1138+
}
11601139

1161-
if (mergeBase != null) {
1162-
const branch = await this.provider.refs.getSymbolicReferenceName(repoPath, mergeBase);
1163-
if (branch != null) {
1164-
if (update) {
1165-
void this.storeBaseBranchName(repoPath, ref, branch);
1166-
}
1167-
return branch;
1140+
if (mergeBase != null) {
1141+
const branch = await this.provider.refs.getSymbolicReferenceName(repoPath, mergeBase);
1142+
if (branch != null) {
1143+
if (update) {
1144+
void this.storeBaseBranchName(repoPath, ref, branch);
11681145
}
1146+
return branch;
11691147
}
11701148
}
11711149
} catch {}
@@ -1251,14 +1229,14 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
12511229
@log({ exit: true })
12521230
async getStoredDetectedMergeTargetBranchName(repoPath: string, ref: string): Promise<string | undefined> {
12531231
const target =
1254-
(await this.provider.config.getConfig(repoPath, `branch.${ref}.gk-merge-target`)) ??
1255-
(await this.provider.config.getConfig(repoPath, `branch.${ref}.gk-target-base`));
1232+
(await this.provider.config.getGkConfig(repoPath, `branch.${ref}.gk-merge-target`)) ??
1233+
(await this.provider.config.getGkConfig(repoPath, `branch.${ref}.gk-target-base`)); // legacy key
12561234
return target?.trim() || undefined;
12571235
}
12581236

12591237
@log()
12601238
async getStoredUserMergeTargetBranchName(repoPath: string, ref: string): Promise<string | undefined> {
1261-
const target = await this.provider.config.getConfig(repoPath, `branch.${ref}.gk-merge-target-user`);
1239+
const target = await this.provider.config.getGkConfig(repoPath, `branch.${ref}.gk-merge-target-user`);
12621240
return target?.trim() || undefined;
12631241
}
12641242

@@ -1333,17 +1311,17 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
13331311

13341312
@log()
13351313
async storeBaseBranchName(repoPath: string, ref: string, base: string): Promise<void> {
1336-
await this.provider.config.setConfig(repoPath, `branch.${ref}.gk-merge-base`, base);
1314+
await this.provider.config.setGkConfig(repoPath, `branch.${ref}.gk-merge-base`, base);
13371315
}
13381316

13391317
@log()
13401318
async storeMergeTargetBranchName(repoPath: string, ref: string, target: string): Promise<void> {
1341-
await this.provider.config.setConfig(repoPath, `branch.${ref}.gk-merge-target`, target);
1319+
await this.provider.config.setGkConfig(repoPath, `branch.${ref}.gk-merge-target`, target);
13421320
}
13431321

13441322
@log()
13451323
async storeUserMergeTargetBranchName(repoPath: string, ref: string, target: string | undefined): Promise<void> {
1346-
await this.provider.config.setConfig(repoPath, `branch.${ref}.gk-merge-target-user`, target);
1324+
await this.provider.config.setGkConfig(repoPath, `branch.${ref}.gk-merge-target-user`, target);
13471325
}
13481326

13491327
/**
@@ -1356,24 +1334,14 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
13561334

13571335
try {
13581336
// Use git config --get-regexp to load all gk-* branch date metadata in one call
1359-
const data = await this.provider.config.getConfigRegex(
1337+
const configMap = await this.provider.config.getGkConfigRegex(
13601338
repoPath,
13611339
'^branch\\..*\\.gk-last-(accessed|modified)$',
1362-
{ runGitLocally: true },
13631340
);
1364-
if (!data) return dateMetadataMap;
1365-
1366-
// Parse the output: "branch.{name}.gk-last-accessed {timestamp}"
1367-
for (const line of data.split('\n')) {
1368-
if (!line) continue;
1369-
1370-
// Find the last space to split key from value
1371-
const spaceIndex = line.lastIndexOf(' ');
1372-
if (spaceIndex === -1) continue;
1373-
1374-
const key = line.substring(0, spaceIndex);
1375-
const value = line.substring(spaceIndex + 1);
1341+
if (!configMap.size) return dateMetadataMap;
13761342

1343+
// Parse entries: key is "branch.{name}.gk-last-accessed" or "branch.{name}.gk-last-modified"
1344+
for (const [key, value] of configMap) {
13771345
// Extract branch name and date metadata key from "branch.{name}.gk-{key}"
13781346
if (!key.startsWith('branch.')) continue;
13791347

@@ -1410,12 +1378,12 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
14101378
ref: string,
14111379
date: Date,
14121380
): Promise<void> {
1413-
const value = await this.provider.config.getConfig(repoPath, `branch.${ref}.${key}`);
1381+
const value = await this.provider.config.getGkConfig(repoPath, `branch.${ref}.${key}`);
14141382
// Skip if incoming date is not at least 5 minutes newer than stored date
14151383
if (value != null && date.getTime() - new Date(value).getTime() < dateMetadataStaleThresholdMs) {
14161384
return;
14171385
}
14181386

1419-
return this.provider.config.setConfig(repoPath, `branch.${ref}.${key}`, date.toISOString());
1387+
return this.provider.config.setGkConfig(repoPath, `branch.${ref}.${key}`, date.toISOString());
14201388
}
14211389
}

0 commit comments

Comments
 (0)