Files
qwen-code/packages/cli/src/ui/hooks/useGitBranchName.ts

76 lines
2.2 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useEffect, useCallback } from 'react';
import { isCommandAvailable, execCommand } from '@qwen-code/qwen-code-core';
import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import path from 'node:path';
export function useGitBranchName(cwd: string): string | undefined {
const [branchName, setBranchName] = useState<string | undefined>(undefined);
const fetchBranchName = useCallback(async () => {
try {
if (!isCommandAvailable('git').available) {
return;
}
const { stdout } = await execCommand(
'git',
['rev-parse', '--abbrev-ref', 'HEAD'],
{ cwd },
);
const branch = stdout.toString().trim();
if (branch && branch !== 'HEAD') {
setBranchName(branch);
} else {
const { stdout: hashStdout } = await execCommand(
'git',
['rev-parse', '--short', 'HEAD'],
{ cwd },
);
setBranchName(hashStdout.toString().trim());
}
} catch (_error) {
setBranchName(undefined);
}
}, [cwd, setBranchName]);
useEffect(() => {
fetchBranchName(); // Initial fetch
const gitLogsHeadPath = path.join(cwd, '.git', 'logs', 'HEAD');
let watcher: fs.FSWatcher | undefined;
const setupWatcher = async () => {
try {
// Check if .git/logs/HEAD exists, as it might not in a new repo or orphaned head
await fsPromises.access(gitLogsHeadPath, fs.constants.F_OK);
watcher = fs.watch(gitLogsHeadPath, (eventType: string) => {
// Changes to .git/logs/HEAD (appends) indicate HEAD has likely changed
if (eventType === 'change' || eventType === 'rename') {
// Handle rename just in case
fetchBranchName();
}
});
} catch (_watchError) {
// Silently ignore watcher errors (e.g. permissions or file not existing),
// similar to how exec errors are handled.
// The branch name will simply not update automatically.
}
};
setupWatcher();
return () => {
watcher?.close();
};
}, [cwd, fetchBranchName]);
return branchName;
}