diff --git a/handlers.go b/handlers.go index afae489..6ee3a0d 100644 --- a/handlers.go +++ b/handlers.go @@ -82,7 +82,27 @@ func serveDiffsText(w http.ResponseWriter, r *http.Request) { } cmd := exec.CommandContext(ctx, "bash", "-c", ` -git diff --src-prefix=a/`+repoName+`/ --dst-prefix=b/`+repoName+`/ HEAD +# Determine the default branch (main or master) +DEFAULT_BRANCH="" +if git rev-parse --verify main >/dev/null 2>&1; then + DEFAULT_BRANCH="main" +elif git rev-parse --verify master >/dev/null 2>&1; then + DEFAULT_BRANCH="master" +fi + +# Get current branch +CURRENT_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "") + +# Determine what to diff against +if [ -n "$DEFAULT_BRANCH" ] && [ -n "$CURRENT_BRANCH" ] && [ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" ]; then + # On a feature branch: show all changes from branch point + git diff --src-prefix=a/`+repoName+`/ --dst-prefix=b/`+repoName+`/ ${DEFAULT_BRANCH}...HEAD +else + # On default branch or detached HEAD: show only uncommitted changes + git diff --src-prefix=a/`+repoName+`/ --dst-prefix=b/`+repoName+`/ HEAD +fi + +# Always show untracked files git ls-files --others --exclude-standard | while IFS= read -r file; do if [ -n "$file" ]; then git diff --no-index --src-prefix=a/`+repoName+`/ --dst-prefix=b/`+repoName+`/ /dev/null "$file" 2>/dev/null || true diff --git a/handlers_test.go b/handlers_test.go index 918cb82..e0c2635 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -283,3 +283,165 @@ func TestServeDiffsText_NonGitDirectory(t *testing.T) { // Should return empty response since there are no git repos // This tests that the handler completes successfully even with no repos } + +func TestServeDiffsText_FeatureBranchShowsAllChanges(t *testing.T) { + tmpDir := t.TempDir() + + setupTestGitRepo(t, tmpDir) + + // Create initial commit on master + testFile := filepath.Join(tmpDir, "initial.txt") + if err := os.WriteFile(testFile, []byte("initial\n"), 0644); err != nil { + t.Fatalf("failed to write test file: %v", err) + } + + cmd := exec.Command("git", "add", "initial.txt") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to git add: %v", err) + } + + cmd = exec.Command("git", "commit", "-m", "initial commit") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to commit: %v", err) + } + + // Create feature branch + cmd = exec.Command("git", "checkout", "-b", "feature") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to create feature branch: %v", err) + } + + // Add committed change on feature branch + committedFile := filepath.Join(tmpDir, "committed.txt") + if err := os.WriteFile(committedFile, []byte("committed on feature\n"), 0644); err != nil { + t.Fatalf("failed to write committed file: %v", err) + } + + cmd = exec.Command("git", "add", "committed.txt") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to git add: %v", err) + } + + cmd = exec.Command("git", "commit", "-m", "committed change on feature") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to commit: %v", err) + } + + // Add uncommitted change on feature branch + uncommittedFile := filepath.Join(tmpDir, "uncommitted.txt") + if err := os.WriteFile(uncommittedFile, []byte("uncommitted on feature\n"), 0644); err != nil { + t.Fatalf("failed to write uncommitted file: %v", err) + } + + oldDir, _ := os.Getwd() + defer os.Chdir(oldDir) + + if err := os.Chdir(tmpDir); err != nil { + t.Fatalf("failed to chdir: %v", err) + } + + req := httptest.NewRequest("GET", "/", nil) + req.Header.Set("Accept", "text/x-diff") + + w := httptest.NewRecorder() + diffsHandler(w, req) + + resp := w.Result() + if resp.StatusCode != http.StatusOK { + t.Errorf("expected status 200, got %d", resp.StatusCode) + } + + body := w.Body.String() + + // Should show both committed and uncommitted changes + if !strings.Contains(body, "committed.txt") { + t.Errorf("expected committed.txt in diff (committed change from branch), got: %s", body) + } + if !strings.Contains(body, "uncommitted.txt") { + t.Errorf("expected uncommitted.txt in diff (uncommitted change), got: %s", body) + } +} + +func TestServeDiffsText_MasterBranchShowsOnlyUncommitted(t *testing.T) { + tmpDir := t.TempDir() + + setupTestGitRepo(t, tmpDir) + + // Create initial commit on master + testFile := filepath.Join(tmpDir, "initial.txt") + if err := os.WriteFile(testFile, []byte("initial\n"), 0644); err != nil { + t.Fatalf("failed to write test file: %v", err) + } + + cmd := exec.Command("git", "add", "initial.txt") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to git add: %v", err) + } + + cmd = exec.Command("git", "commit", "-m", "initial commit") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to commit: %v", err) + } + + // Add another committed change on master + committedFile := filepath.Join(tmpDir, "committed.txt") + if err := os.WriteFile(committedFile, []byte("committed on master\n"), 0644); err != nil { + t.Fatalf("failed to write committed file: %v", err) + } + + cmd = exec.Command("git", "add", "committed.txt") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to git add: %v", err) + } + + cmd = exec.Command("git", "commit", "-m", "committed change on master") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Fatalf("failed to commit: %v", err) + } + + // Add uncommitted change on master + uncommittedFile := filepath.Join(tmpDir, "uncommitted.txt") + if err := os.WriteFile(uncommittedFile, []byte("uncommitted on master\n"), 0644); err != nil { + t.Fatalf("failed to write uncommitted file: %v", err) + } + + oldDir, _ := os.Getwd() + defer os.Chdir(oldDir) + + if err := os.Chdir(tmpDir); err != nil { + t.Fatalf("failed to chdir: %v", err) + } + + req := httptest.NewRequest("GET", "/", nil) + req.Header.Set("Accept", "text/x-diff") + + w := httptest.NewRecorder() + diffsHandler(w, req) + + resp := w.Result() + if resp.StatusCode != http.StatusOK { + t.Errorf("expected status 200, got %d", resp.StatusCode) + } + + body := w.Body.String() + + // Should NOT show committed changes (committed.txt was committed, so should not appear in diff) + // Look for "a/./committed.txt" or "b/./committed.txt" in diff headers + if strings.Contains(body, "a/./committed.txt") || strings.Contains(body, "b/./committed.txt") { + t.Errorf("should not show committed.txt changes on master branch since it was already committed, got: %s", body) + } + // Should show uncommitted changes + if !strings.Contains(body, "uncommitted.txt") { + t.Errorf("expected uncommitted.txt in diff (uncommitted change), got: %s", body) + } +} +