fix: initial commit error

This commit is contained in:
simos
2025-11-17 15:54:08 +01:00
parent b892985700
commit 544c72434a
2 changed files with 126 additions and 16 deletions

View File

@@ -80,34 +80,47 @@ async function validateGitRepository(projectPath) {
// Get git status for a project
router.get('/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);
// Validate git repository
await validateGitRepository(projectPath);
// Get current branch
const { stdout: branch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
// Get current branch - handle case where there are no commits yet
let branch = 'main';
let hasCommits = true;
try {
const { stdout: branchOutput } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
branch = branchOutput.trim();
} catch (error) {
// No HEAD exists - repository has no commits yet
if (error.message.includes('unknown revision') || error.message.includes('ambiguous argument')) {
hasCommits = false;
branch = 'main';
} else {
throw error;
}
}
// Get git status
const { stdout: statusOutput } = await execAsync('git status --porcelain', { cwd: projectPath });
const modified = [];
const added = [];
const deleted = [];
const untracked = [];
statusOutput.split('\n').forEach(line => {
if (!line.trim()) return;
const status = line.substring(0, 2);
const file = line.substring(3);
if (status === 'M ' || status === ' M' || status === 'MM') {
modified.push(file);
} else if (status === 'A ' || status === 'AM') {
@@ -118,9 +131,10 @@ router.get('/status', async (req, res) => {
untracked.push(file);
}
});
res.json({
branch: branch.trim(),
branch,
hasCommits,
modified,
added,
deleted,
@@ -128,9 +142,9 @@ router.get('/status', async (req, res) => {
});
} catch (error) {
console.error('Git status error:', error);
res.json({
error: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
? error.message
res.json({
error: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
? error.message
: 'Git operation failed',
details: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
? error.message
@@ -264,6 +278,50 @@ router.get('/file-with-diff', async (req, res) => {
}
});
// Create initial commit
router.post('/initial-commit', 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);
// Validate git repository
await validateGitRepository(projectPath);
// Check if there are already commits
try {
await execAsync('git rev-parse HEAD', { cwd: projectPath });
return res.status(400).json({ error: 'Repository already has commits. Use regular commit instead.' });
} catch (error) {
// No HEAD - this is good, we can create initial commit
}
// Add all files
await execAsync('git add .', { cwd: projectPath });
// Create initial commit
const { stdout } = await execAsync('git commit -m "Initial commit"', { cwd: projectPath });
res.json({ success: true, output: stdout, message: 'Initial commit created successfully' });
} catch (error) {
console.error('Git initial commit error:', error);
// Handle the case where there's nothing to commit
if (error.message.includes('nothing to commit')) {
return res.status(400).json({
error: 'Nothing to commit',
details: 'No files found in the repository. Add some files first.'
});
}
res.status(500).json({ error: error.message });
}
});
// Commit changes
router.post('/commit', async (req, res) => {
const { project, message, files } = req.body;

View File

@@ -32,6 +32,7 @@ function GitPanel({ selectedProject, isMobile, onFileOpen }) {
const [isPublishing, setIsPublishing] = useState(false);
const [isCommitAreaCollapsed, setIsCommitAreaCollapsed] = useState(isMobile); // Collapsed by default on mobile
const [confirmAction, setConfirmAction] = useState(null); // { type: 'discard|commit|pull|push', file?: string, message?: string }
const [isCreatingInitialCommit, setIsCreatingInitialCommit] = useState(false);
const textareaRef = useRef(null);
const dropdownRef = useRef(null);
@@ -547,7 +548,7 @@ function GitPanel({ selectedProject, isMobile, onFileOpen }) {
const handleCommit = async () => {
if (!commitMessage.trim() || selectedFiles.size === 0) return;
setIsCommitting(true);
try {
const response = await authenticatedFetch('/api/git/commit', {
@@ -559,7 +560,7 @@ function GitPanel({ selectedProject, isMobile, onFileOpen }) {
files: Array.from(selectedFiles)
})
});
const data = await response.json();
if (data.success) {
// Reset state after successful commit
@@ -577,6 +578,32 @@ function GitPanel({ selectedProject, isMobile, onFileOpen }) {
}
};
const createInitialCommit = async () => {
setIsCreatingInitialCommit(true);
try {
const response = await authenticatedFetch('/api/git/initial-commit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
project: selectedProject.name
})
});
const data = await response.json();
if (data.success) {
fetchGitStatus();
fetchRemoteStatus();
} else {
console.error('Initial commit failed:', data.error);
alert(data.error || 'Failed to create initial commit');
}
} catch (error) {
console.error('Error creating initial commit:', error);
alert('Failed to create initial commit');
} finally {
setIsCreatingInitialCommit(false);
}
};
const getStatusLabel = (status) => {
switch (status) {
@@ -1161,6 +1188,31 @@ function GitPanel({ selectedProject, isMobile, onFileOpen }) {
<div className="flex items-center justify-center h-32">
<RefreshCw className="w-6 h-6 animate-spin text-gray-400" />
</div>
) : gitStatus?.hasCommits === false ? (
<div className="flex flex-col items-center justify-center p-8 text-center">
<GitBranch className="w-16 h-16 mb-4 opacity-30 text-gray-400 dark:text-gray-500" />
<h3 className="text-lg font-medium mb-2 text-gray-900 dark:text-white">No commits yet</h3>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-6 max-w-md">
This repository doesn't have any commits yet. Create your first commit to start tracking changes.
</p>
<button
onClick={createInitialCommit}
disabled={isCreatingInitialCommit}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
{isCreatingInitialCommit ? (
<>
<RefreshCw className="w-4 h-4 animate-spin" />
<span>Creating Initial Commit...</span>
</>
) : (
<>
<GitCommit className="w-4 h-4" />
<span>Create Initial Commit</span>
</>
)}
</button>
</div>
) : !gitStatus || (!gitStatus.modified?.length && !gitStatus.added?.length && !gitStatus.deleted?.length && !gitStatus.untracked?.length) ? (
<div className="flex flex-col items-center justify-center h-32 text-gray-500 dark:text-gray-400">
<GitCommit className="w-12 h-12 mb-2 opacity-50" />