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
51 changes: 51 additions & 0 deletions e2e/testdata/sync.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[!exec:git] skip 'git not available'

# Set up a project with a remote that has master + develop branches.
setup-repo develop
setup-project

cd $WORK/project

# Create worktrees for the existing local branches and configure upstream
# tracking explicitly. Using git directly (not `wt add`) keeps the test focused
# on sync behavior with guaranteed upstream setup.
exec git --git-dir=.bare worktree add --relative-paths worktrees/master master
exec git --git-dir=.bare worktree add --relative-paths worktrees/develop develop
exec git -C worktrees/master branch --set-upstream-to=origin/master
exec git -C worktrees/develop branch --set-upstream-to=origin/develop

# Both upstreams resolve cleanly — sync reports up to date with no warnings.
exec wt sync
stderr 'master: up to date'
stderr 'develop: up to date'
! stderr 'could not check upstream'
stderr 'Sync complete: 0 updated, 0 skipped, 0 failed'

# Regression test: configured-but-gone upstream. When branch.<name>.merge points
# at a non-existent remote ref, git's @{upstream} resolution fails with
# "fatal: no such branch: 'HEAD..'". wt sync should treat this as up-to-date
# and not surface a warning.
exec git --git-dir=.bare config branch.develop.merge refs/heads/does-not-exist
exec wt sync
stderr 'develop: up to date'
! stderr 'could not check upstream'
! stderr 'no such branch'

# Restore develop's upstream, push a new commit to remote develop, and verify
# wt sync detects the lag and pulls.
exec git --git-dir=.bare config branch.develop.merge refs/heads/develop

cd $WORK/remote
exec git checkout develop
cp $WORK/newfile.txt newfile.txt
exec git add newfile.txt
exec git commit -m 'add newfile'

cd $WORK/project
exec wt sync
stderr 'develop: pulling 1 commit'
stderr 'Sync complete: 1 updated'
exists worktrees/develop/newfile.txt

-- newfile.txt --
hello
21 changes: 13 additions & 8 deletions internal/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,26 +361,31 @@ func (r *Runner) GetLastCommitAge(ctx context.Context, worktreePath string) (str
}

func (r *Runner) GetBehindCount(ctx context.Context, worktreePath string) (int, error) {
args := []string{"-C", worktreePath, "rev-list", "--count", "HEAD..@{upstream}"}
cmdStr := "git " + strings.Join(args, " ")
checkArgs := []string{"-C", worktreePath, "rev-parse", "--verify", "--quiet", "@{upstream}"}
checkStr := "git " + strings.Join(checkArgs, " ")

if r.DryRun {
ui.DryRunNotice(cmdStr)
ui.DryRunNotice(checkStr)
ui.DryRunNotice("git -C " + worktreePath + " rev-list --count HEAD..@{upstream}")
return 0, nil
}

ui.Command(checkStr)
if err := exec.CommandContext(ctx, "git", checkArgs...).Run(); err != nil {
return 0, nil
}

args := []string{"-C", worktreePath, "rev-list", "--count", "HEAD..@{upstream}"}
cmdStr := "git " + strings.Join(args, " ")

ui.Command(cmdStr)
cmd := exec.CommandContext(ctx, "git", args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

if err := cmd.Run(); err != nil {
stderrStr := stderr.String()
if strings.Contains(stderrStr, "no upstream") || strings.Contains(stderrStr, "unknown revision") {
return 0, nil
}
return 0, fmt.Errorf("%s: %w\n%s", cmdStr, err, stderrStr)
return 0, fmt.Errorf("%s: %w\n%s", cmdStr, err, stderr.String())
}

return parseBehindCount(stdout.String()), nil
Expand Down