diff --git a/modules/doctor/heads.go b/modules/doctor/heads.go
index 33efc27a22..b1bfd50b20 100644
--- a/modules/doctor/heads.go
+++ b/modules/doctor/heads.go
@@ -19,11 +19,9 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
 	numReposUpdated := 0
 	err := iterateRepositories(ctx, func(repo *repo_model.Repository) error {
 		numRepos++
-		runOpts := &git.RunOpts{Dir: repo.RepoPath()}
+		_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
 
-		_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(runOpts)
-
-		head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(runOpts)
+		head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
 
 		// what we expect: default branch is valid, and HEAD points to it
 		if headErr == nil && defaultBranchErr == nil && head == repo.DefaultBranch {
@@ -49,7 +47,7 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
 		}
 
 		// otherwise, let's try fixing HEAD
-		err := git.NewCommand(ctx, "symbolic-ref").AddDashesAndList("HEAD", git.BranchPrefix+repo.DefaultBranch).Run(runOpts)
+		err := git.NewCommand(ctx, "symbolic-ref").AddDashesAndList("HEAD", git.BranchPrefix+repo.DefaultBranch).Run(&git.RunOpts{Dir: repo.RepoPath()})
 		if err != nil {
 			logger.Warn("Failed to fix HEAD for %s/%s: %v", repo.OwnerName, repo.Name, err)
 			return nil
@@ -65,7 +63,7 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
 		logger.Info("Out of %d repos, HEADs for %d are now fixed and HEADS for %d are still broken", numRepos, numReposUpdated, numDefaultBranchesBroken+numHeadsBroken-numReposUpdated)
 	} else {
 		if numHeadsBroken == 0 && numDefaultBranchesBroken == 0 {
-			logger.Info("All %d repos have their HEADs in the correct state")
+			logger.Info("All %d repos have their HEADs in the correct state", numRepos)
 		} else {
 			if numHeadsBroken == 0 && numDefaultBranchesBroken != 0 {
 				logger.Critical("Default branches are broken for %d/%d repos", numDefaultBranchesBroken, numRepos)
diff --git a/modules/git/command.go b/modules/git/command.go
index abf40b0cd7..0d94494f11 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -202,8 +202,11 @@ func (c *Command) Run(opts *RunOpts) error {
 	if opts == nil {
 		opts = &RunOpts{}
 	}
-	if opts.Timeout <= 0 {
-		opts.Timeout = defaultCommandExecutionTimeout
+
+	// We must not change the provided options
+	timeout := opts.Timeout
+	if timeout <= 0 {
+		timeout = defaultCommandExecutionTimeout
 	}
 
 	if len(opts.Dir) == 0 {
@@ -238,7 +241,7 @@ func (c *Command) Run(opts *RunOpts) error {
 	if opts.UseContextTimeout {
 		ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
 	} else {
-		ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
+		ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, timeout, desc)
 	}
 	defer finished()
 
@@ -339,9 +342,20 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
 	}
 	stdoutBuf := &bytes.Buffer{}
 	stderrBuf := &bytes.Buffer{}
-	opts.Stdout = stdoutBuf
-	opts.Stderr = stderrBuf
-	err := c.Run(opts)
+
+	// We must not change the provided options as it could break future calls - therefore make a copy.
+	newOpts := &RunOpts{
+		Env:               opts.Env,
+		Timeout:           opts.Timeout,
+		UseContextTimeout: opts.UseContextTimeout,
+		Dir:               opts.Dir,
+		Stdout:            stdoutBuf,
+		Stderr:            stderrBuf,
+		Stdin:             opts.Stdin,
+		PipelineFunc:      opts.PipelineFunc,
+	}
+
+	err := c.Run(newOpts)
 	stderr = stderrBuf.Bytes()
 	if err != nil {
 		return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}