+ New

fierj

Public

Tiny personal git forge

f2199f85268b4cdef79a39553f14476a0aa3436c
diff --git a/git.go b/git.go
index 280be92..948e7d5 100644
--- a/git.go
+++ b/git.go
@@ -225,15 +225,28 @@ func (g *Git) Diff(hash string) (string, error) {
 
 func (g *Git) DefaultBranch() string {
 	out, err := g.cmd("symbolic-ref", "--short", "HEAD")
-	if err != nil {
-		return "main"
+	if err == nil {
+		ref := strings.TrimSpace(out)
+		// Verify the default branch actually exists (HEAD might point to
+		// a not-yet-created branch in an empty/dangling-HEAD repo).
+		if _, err2 := g.cmd("rev-parse", "--verify", ref); err2 == nil {
+			return ref
+		}
+	}
+	// Fall back to the first real branch, or "main" as last resort.
+	branches := g.Branches()
+	if len(branches) > 0 {
+		return branches[0]
 	}
-	return strings.TrimSpace(out)
+	return "main"
 }
 
 func (g *Git) IsEmpty() bool {
-	_, err := g.cmd("rev-parse", "--verify", "HEAD")
-	return err != nil
+	// Check if any refs exist, not just HEAD.
+	// HEAD can be a dangling symbolic ref after git init --bare.
+	branches := g.Branches()
+	tags := g.Tags()
+	return len(branches) == 0 && len(tags) == 0
 }
 
 func (g *Git) Branches() []string {
diff --git a/ssh.go b/ssh.go
index 52fe3bc..bbf6ceb 100644
--- a/ssh.go
+++ b/ssh.go
@@ -13,6 +13,7 @@ import (
 	"path/filepath"
 	"strings"
 	"sync"
+	"time"
 
 	"golang.org/x/crypto/ssh"
 )
@@ -159,8 +160,21 @@ func (s *SSHServer) runGitCommand(channel ssh.Channel, gitCmd string) {
 	go func() { defer wg.Done(); io.Copy(channel, stdout) }()
 	go func() { io.Copy(stdin, channel); stdin.Close() }()
 
-	cmd.Wait()
-	wg.Wait() // drain stdout before returning
+	if err := cmd.Wait(); err != nil {
+		slog.Warn("git failed", "cmd", subCmd, "repo", repoName, "err", err)
+	}
+	wg.Wait()
+
+	// Send exit status so the client knows the command finished successfully.
+	// Without this, git push reports an error even when the push succeeded.
+	exitCode := uint32(0)
+	if cmd.ProcessState != nil && !cmd.ProcessState.Success() {
+		exitCode = 1
+	}
+	channel.SendRequest("exit-status", false, ssh.Marshal(&struct{ ExitStatus uint32 }{exitCode}))
+
+	// Give the SSH library time to flush before channel.Close in handleSession.
+	time.Sleep(50 * time.Millisecond)
 }
 
 func loadOrGenerateHostKey(path string) (ssh.Signer, error) {