Browse Source

fix new branch creation

Nostr-Signature: 7802c9afbf005e2637282f9d06ac8130fe27bfe3a94cc67c211da51d2e9e8350 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 30978d6a71b4935c88ff9cd1412294d850a752977943e1aa65bcfc2290d2f2e8bbce809556849a14f0923da33b12cb53d3339741cdabab3ba949dfbb48e9cc4c
main
Silberengel 3 weeks ago
parent
commit
16484aa8e3
  1. 1
      nostr/commit-signatures.jsonl
  2. 33
      src/lib/components/RepoHeaderEnhanced.svelte
  3. 15
      src/lib/services/git/file-manager.ts
  4. 24
      src/routes/api/repos/[npub]/[repo]/branches/+server.ts
  5. 31
      src/routes/repos/[npub]/[repo]/+page.svelte

1
nostr/commit-signatures.jsonl

@ -64,3 +64,4 @@ @@ -64,3 +64,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771845583,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix search and relay connections"]],"content":"Signed commit: fix search and relay connections","id":"24db15027960b244eb4c8664a3642c64684ebfef8c200250093dd047cd119e7d","sig":"561d15ae39b3bf7a5b8a67539a5cfa19d53cbaca9f904589ab7cb69e568ddf056d0d83ced4830cdfdc0b386f13c4bab930264a0f6144cbb833b187b5d452c4ae"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771847704,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"9566e4e2964d0a7b80cce1889092c4db333f89843b5d68906b3c3c568e4ba57d","sig":"8cf9166c630a8dc21bbc3dfaea4330c80c93bf7bc9e8d5d3be182fb11a3b96ea2e5969f452d3e2b309103b3e7fea8fc1aa6e5908d499d0696e9bfcd3859a8e32"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771849427,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"1d4e6ff4059b064d7cdd465d623a606cfcc5d0565681a34f6384463d40cc8c71","sig":"f5fe3547289e994ff1a3b191607e76d778d318ca4538e70253406867ecef214c1be437dca373f9a461c9cf2ca2978a581b54a9d323baeb2c91851e9cc6ffbfd6"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771850840,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","rearrange repo pages"]],"content":"Signed commit: rearrange repo pages","id":"9f8b68f36189073807510a2dac268b466629ecbc6b8dca66ba809cbf3a36dab5","sig":"911debb546c23038bbf77a57bee089130c7cce3a51f2cfb385c3904ec39bc76b90dc9bef2e8e501824ecff13925523d802b6c916d07fef2718554f4f65e6f4d2"}

33
src/lib/components/RepoHeaderEnhanced.svelte

@ -241,6 +241,20 @@ @@ -241,6 +241,20 @@
Create New Branch
</button>
{/if}
{#if isMaintainer && currentBranch && currentBranch !== defaultBranch && onDeleteBranch}
<button
class="menu-item menu-item-danger"
onclick={() => {
if (currentBranch) {
onDeleteBranch(currentBranch);
}
showMoreMenu = false;
}}
title="Delete branch"
>
Delete Branch
</button>
{/if}
{#if onCopyEventId}
<button class="menu-item" onclick={() => { onCopyEventId(); showMoreMenu = false; }}>
Copy Event ID
@ -357,13 +371,19 @@ @@ -357,13 +371,19 @@
</div>
{/if}
{#if currentBranch}
{#if branches.length === 0}
<div class="repo-branch">
<div class="branch-button" style="opacity: 0.6; cursor: not-allowed;">
<img src="/icons/git-branch.svg" alt="" class="icon" />
No branches
</div>
</div>
{:else if currentBranch}
<div class="repo-branch">
<button
class="branch-button"
onclick={() => showBranchMenu = !showBranchMenu}
aria-expanded={showBranchMenu}
disabled={branches.length === 0}
>
<img src="/icons/git-branch.svg" alt="" class="icon" />
{currentBranch}
@ -388,15 +408,6 @@ @@ -388,15 +408,6 @@
{/each}
</div>
{/if}
{#if isMaintainer && currentBranch && currentBranch !== defaultBranch && onDeleteBranch}
<button
class="delete-branch-button"
onclick={() => currentBranch && onDeleteBranch(currentBranch)}
title="Delete branch"
>
×
</button>
{/if}
</div>
{/if}
</div>

15
src/lib/services/git/file-manager.ts

@ -1765,15 +1765,12 @@ export class FileManager { @@ -1765,15 +1765,12 @@ export class FileManager {
npub: string,
repoName: string,
branchName: string,
fromBranch: string = 'main'
fromBranch?: string
): Promise<void> {
// Security: Validate branch names to prevent path traversal
if (!isValidBranchName(branchName)) {
throw new Error(`Invalid branch name: ${branchName}`);
}
if (!isValidBranchName(fromBranch)) {
throw new Error(`Invalid source branch name: ${fromBranch}`);
}
const repoPath = this.getRepoPath(npub, repoName);
@ -1870,8 +1867,16 @@ export class FileManager { @@ -1870,8 +1867,16 @@ export class FileManager {
await this.removeWorktree(repoPath, worktreePath);
} else {
// Repo has branches - use normal branch creation
// Validate fromBranch if provided
if (fromBranch && !isValidBranchName(fromBranch)) {
throw new Error(`Invalid source branch name: ${fromBranch}`);
}
// Use default branch if fromBranch not provided
const sourceBranch = fromBranch || await this.getDefaultBranch(npub, repoName).catch(() => 'main');
// Use git worktree instead of cloning (much more efficient)
const workDir = await this.getWorktree(repoPath, fromBranch, npub, repoName);
const workDir = await this.getWorktree(repoPath, sourceBranch, npub, repoName);
const workGit: SimpleGit = simpleGit(workDir);
// Create and checkout new branch

24
src/routes/api/repos/[npub]/[repo]/branches/+server.ts

@ -244,18 +244,30 @@ export const POST: RequestHandler = createRepoPostHandler( @@ -244,18 +244,30 @@ export const POST: RequestHandler = createRepoPostHandler(
}
}
// Get default branch if fromBranch not provided
// If repo has no branches, use 'master' as default
// Check if repo has any branches first
let hasBranches = false;
try {
const existingBranches = await fileManager.getBranches(context.npub, context.repo);
hasBranches = existingBranches.length > 0;
} catch (err) {
// If getBranches fails, assume no branches exist
logger.debug({ error: err, npub: context.npub, repo: context.repo }, 'Failed to get branches, assuming empty repo');
hasBranches = false;
}
// Get default branch if fromBranch not provided and repo has branches
// If repo has no branches, don't pass fromBranch (will use --orphan)
let sourceBranch = fromBranch;
if (!sourceBranch) {
if (!sourceBranch && hasBranches) {
try {
sourceBranch = await fileManager.getDefaultBranch(context.npub, context.repo);
} catch (err) {
// If getDefaultBranch fails (e.g., no branches exist), use 'master' as default
logger.debug({ error: err, npub: context.npub, repo: context.repo }, 'No default branch found, using master');
sourceBranch = 'master';
// If getDefaultBranch fails, use 'main' as default (only if branches exist)
logger.debug({ error: err, npub: context.npub, repo: context.repo }, 'No default branch found, using main');
sourceBranch = 'main';
}
}
// If repo has no branches, sourceBranch will be undefined/null, which createBranch will handle correctly
await fileManager.createBranch(context.npub, context.repo, branchName, sourceBranch);
return json({ success: true, message: 'Branch created successfully' });

31
src/routes/repos/[npub]/[repo]/+page.svelte

@ -2806,15 +2806,8 @@ @@ -2806,15 +2806,8 @@
currentBranch = defaultBranch;
}
} else {
// No branches loaded yet or empty repo - set currentBranch from settings if not set
if (!currentBranch) {
try {
const settings = await settingsStore.getSettings();
currentBranch = settings.defaultBranch || 'master';
} catch {
currentBranch = 'master';
}
}
// No branches exist - set currentBranch to null to show "no branches" in header
currentBranch = null;
}
} else if (response.status === 404) {
// Check if this is a "not cloned" error - API fallback might be available
@ -3803,11 +3796,16 @@ @@ -3803,11 +3796,16 @@
error = null;
try {
// If no branches exist, use default branch from settings
let fromBranch = newBranchFrom || currentBranch;
if (!fromBranch && branches.length === 0) {
const settings = await settingsStore.getSettings();
fromBranch = settings.defaultBranch || 'master';
// If no branches exist, don't pass fromBranch (will use --orphan)
// Otherwise, use the selected branch or current branch
let fromBranch: string | undefined = newBranchFrom || currentBranch || undefined;
// Only include fromBranch if repo has branches
const requestBody: { branchName: string; fromBranch?: string } = {
branchName: newBranchName
};
if (branches.length > 0 && fromBranch) {
requestBody.fromBranch = fromBranch;
}
const response = await fetch(`/api/repos/${npub}/${repo}/branches`, {
@ -3816,10 +3814,7 @@ @@ -3816,10 +3814,7 @@
'Content-Type': 'application/json',
...buildApiHeaders()
},
body: JSON.stringify({
branchName: newBranchName,
fromBranch: fromBranch || 'master' // Final fallback
})
body: JSON.stringify(requestBody)
});
if (!response.ok) {

Loading…
Cancel
Save