@@ -462,15 +462,17 @@ func lsRemote(ctx context.Context, dir, remote string, patterns ...string) ([]by
462462 disableTerminalPrompt (cmd )
463463 out , err := cmd .Output ()
464464 if err != nil {
465- return out , fmt .Errorf ("git ls-remote: %w" , formatGitCommandError (ctx , err ))
465+ return out , fmt .Errorf ("git ls-remote: %w" , formatGitCommandError (ctx , err , remote ))
466466 }
467467 return out , nil
468468}
469469
470470// formatGitCommandError enriches an exec error from git Output() so callers see
471471// useful detail: context deadline expiry by name, and git's stderr (auth denied,
472472// repository not found, DNS) which ExitError otherwise hides behind "exit status N".
473- func formatGitCommandError (ctx context.Context , err error ) error {
473+ // When remote is a URL it may carry credentials that git echoes into stderr;
474+ // those are redacted before the error is returned (same pattern as FetchBlobs).
475+ func formatGitCommandError (ctx context.Context , err error , remote string ) error {
474476 if err == nil {
475477 return nil
476478 }
@@ -480,6 +482,9 @@ func formatGitCommandError(ctx context.Context, err error) error {
480482 var exitErr * exec.ExitError
481483 if errors .As (err , & exitErr ) {
482484 if stderr := strings .TrimSpace (string (exitErr .Stderr )); stderr != "" {
485+ if remote != "" {
486+ stderr = strings .ReplaceAll (stderr , remote , RedactURL (remote ))
487+ }
483488 // Collapse whitespace so multi-line git stderr stays one log/attr value.
484489 stderr = strings .Join (strings .Fields (stderr ), " " )
485490 return fmt .Errorf ("%w (%s)" , err , stderr )
0 commit comments