mirror of
https://github.com/siteboon/claudecodeui.git
synced 2025-12-09 10:59:47 +00:00
Added pull and fetch on git panel
Made UX enhancements
This commit is contained in:
@@ -420,4 +420,167 @@ function generateSimpleCommitMessage(files, diff) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get remote status (ahead/behind commits with smart remote detection)
|
||||
router.get('/remote-status', async (req, res) => {
|
||||
const { project } = req.query;
|
||||
|
||||
if (!project) {
|
||||
return res.status(400).json({ error: 'Project name is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const projectPath = await getActualProjectPath(project);
|
||||
await validateGitRepository(projectPath);
|
||||
|
||||
// Get current branch
|
||||
const { stdout: currentBranch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
|
||||
const branch = currentBranch.trim();
|
||||
|
||||
// Check if there's a remote tracking branch (smart detection)
|
||||
let trackingBranch;
|
||||
let remoteName;
|
||||
try {
|
||||
const { stdout } = await execAsync(`git rev-parse --abbrev-ref ${branch}@{upstream}`, { cwd: projectPath });
|
||||
trackingBranch = stdout.trim();
|
||||
remoteName = trackingBranch.split('/')[0]; // Extract remote name (e.g., "origin/main" -> "origin")
|
||||
} catch (error) {
|
||||
// No upstream branch configured
|
||||
return res.json({
|
||||
hasRemote: false,
|
||||
branch,
|
||||
message: 'No remote tracking branch configured'
|
||||
});
|
||||
}
|
||||
|
||||
// Get ahead/behind counts
|
||||
const { stdout: countOutput } = await execAsync(
|
||||
`git rev-list --count --left-right ${trackingBranch}...HEAD`,
|
||||
{ cwd: projectPath }
|
||||
);
|
||||
|
||||
const [behind, ahead] = countOutput.trim().split('\t').map(Number);
|
||||
|
||||
res.json({
|
||||
hasRemote: true,
|
||||
branch,
|
||||
remoteBranch: trackingBranch,
|
||||
remoteName,
|
||||
ahead: ahead || 0,
|
||||
behind: behind || 0,
|
||||
isUpToDate: ahead === 0 && behind === 0
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Git remote status error:', error);
|
||||
res.json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch from remote (using smart remote detection)
|
||||
router.post('/fetch', async (req, res) => {
|
||||
const { project } = req.body;
|
||||
|
||||
if (!project) {
|
||||
return res.status(400).json({ error: 'Project name is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const projectPath = await getActualProjectPath(project);
|
||||
await validateGitRepository(projectPath);
|
||||
|
||||
// Get current branch and its upstream remote
|
||||
const { stdout: currentBranch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
|
||||
const branch = currentBranch.trim();
|
||||
|
||||
let remoteName = 'origin'; // fallback
|
||||
try {
|
||||
const { stdout } = await execAsync(`git rev-parse --abbrev-ref ${branch}@{upstream}`, { cwd: projectPath });
|
||||
remoteName = stdout.trim().split('/')[0]; // Extract remote name
|
||||
} catch (error) {
|
||||
// No upstream, try to fetch from origin anyway
|
||||
console.log('No upstream configured, using origin as fallback');
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(`git fetch ${remoteName}`, { cwd: projectPath });
|
||||
|
||||
res.json({ success: true, output: stdout || 'Fetch completed successfully', remoteName });
|
||||
} catch (error) {
|
||||
console.error('Git fetch error:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fetch failed',
|
||||
details: error.message.includes('Could not resolve hostname')
|
||||
? 'Unable to connect to remote repository. Check your internet connection.'
|
||||
: error.message.includes('fatal: \'origin\' does not appear to be a git repository')
|
||||
? 'No remote repository configured. Add a remote with: git remote add origin <url>'
|
||||
: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Pull from remote (fetch + merge using smart remote detection)
|
||||
router.post('/pull', async (req, res) => {
|
||||
const { project } = req.body;
|
||||
|
||||
if (!project) {
|
||||
return res.status(400).json({ error: 'Project name is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const projectPath = await getActualProjectPath(project);
|
||||
await validateGitRepository(projectPath);
|
||||
|
||||
// Get current branch and its upstream remote
|
||||
const { stdout: currentBranch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
|
||||
const branch = currentBranch.trim();
|
||||
|
||||
let remoteName = 'origin'; // fallback
|
||||
let remoteBranch = branch; // fallback
|
||||
try {
|
||||
const { stdout } = await execAsync(`git rev-parse --abbrev-ref ${branch}@{upstream}`, { cwd: projectPath });
|
||||
const tracking = stdout.trim();
|
||||
remoteName = tracking.split('/')[0]; // Extract remote name
|
||||
remoteBranch = tracking.split('/').slice(1).join('/'); // Extract branch name
|
||||
} catch (error) {
|
||||
// No upstream, use fallback
|
||||
console.log('No upstream configured, using origin/branch as fallback');
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(`git pull ${remoteName} ${remoteBranch}`, { cwd: projectPath });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
output: stdout || 'Pull completed successfully',
|
||||
remoteName,
|
||||
remoteBranch
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Git pull error:', error);
|
||||
|
||||
// Enhanced error handling for common pull scenarios
|
||||
let errorMessage = 'Pull failed';
|
||||
let details = error.message;
|
||||
|
||||
if (error.message.includes('CONFLICT')) {
|
||||
errorMessage = 'Merge conflicts detected';
|
||||
details = 'Pull created merge conflicts. Please resolve conflicts manually in the editor, then commit the changes.';
|
||||
} else if (error.message.includes('Please commit your changes or stash them')) {
|
||||
errorMessage = 'Uncommitted changes detected';
|
||||
details = 'Please commit or stash your local changes before pulling.';
|
||||
} else if (error.message.includes('Could not resolve hostname')) {
|
||||
errorMessage = 'Network error';
|
||||
details = 'Unable to connect to remote repository. Check your internet connection.';
|
||||
} else if (error.message.includes('fatal: \'origin\' does not appear to be a git repository')) {
|
||||
errorMessage = 'Remote not configured';
|
||||
details = 'No remote repository configured. Add a remote with: git remote add origin <url>';
|
||||
} else if (error.message.includes('diverged')) {
|
||||
errorMessage = 'Branches have diverged';
|
||||
details = 'Your local branch and remote branch have diverged. Consider fetching first to review changes.';
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: errorMessage,
|
||||
details: details
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user