Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
162 changes: 162 additions & 0 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Loading