/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { useState, useEffect, useCallback } from 'react'; import { exec } from 'node:child_process'; import fs from 'node:fs'; import fsPromises from 'node:fs/promises'; import path from 'path'; export function useGitBranchName(cwd: string): string | undefined { const [branchName, setBranchName] = useState(undefined); const fetchBranchName = useCallback( () => exec( 'git rev-parse --abbrev-ref HEAD', { cwd }, (error, stdout, _stderr) => { if (error) { setBranchName(undefined); return; } const branch = stdout.toString().trim(); if (branch && branch !== 'HEAD') { setBranchName(branch); } else { setBranchName(undefined); } }, ), [cwd, setBranchName], ); useEffect(() => { fetchBranchName(); // Initial fetch const gitHeadPath = path.join(cwd, '.git', 'HEAD'); let watcher: fs.FSWatcher | undefined; const setupWatcher = async () => { try { await fsPromises.access(gitHeadPath, fs.constants.F_OK); watcher = fs.watch(gitHeadPath, (eventType) => { if (eventType === 'change') { 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; }