Repository: argoproj-labs/argocd-image-updater

Issue:
`--logfomat` only works for some log
**Describe the bug**
Set log format json but not works for git command

**To Reproduce**
Steps to reproduce the behavior:

just add cli flag with `--logformat json`

**Expected behavior**
git command also should output with json format

**Additional context**
None
**Version**
v0.17.0

**Logs**
```
time="2025-10-30T05:22:43Z" level=info msg=Trace args="[git remote show origin]" dir=/tmp/git-<some-argocd-application>191239555 operation_name="exec git" time_ms=214.585335
{"application":"<some-argocd-application>","level":"info","msg":"resolved remote default branch to 'main' and using that for operations","time":"2025-10-30T05:22:43Z"}
time="2025-10-30T05:22:43Z" level=info msg="git fetch origin main --force --prune --depth 1" dir=/tmp/git-<some-argocd-application>191239555 execID=a6502
time="2025-10-30T05:22:43Z" level=info msg=Trace args="[git fetch origin main --force --prune --depth 1]" dir=/tmp/git-<some-argocd-application>191239555 operation_name="exec git" time_ms=319.240854
time="2025-10-30T05:22:43Z" level=info msg="git checkout --force main" dir=/tmp/git-<some-argocd-application>191239555 execID=317d3
time="2025-10-30T05:22:43Z" level=info msg=Trace args="[git checkout --force main]" dir=/tmp/git-<some-argocd-application>191239555 operation_name="exec git" time_ms=8.699076999999999
time="2025-10-30T05:22:43Z" level=info msg="git clean -ffdx" dir=/tmp/git-<some-argocd-application>191239555 execID=969e3
time="2025-10-30T05:22:43Z" level=info msg=Trace args="[git clean -ffdx]" dir=/tmp/git-<some-argocd-application>191239555 operation_name="exec git" time_ms=1.294031
{"application":"<some-argocd-application>","level":"info","msg":"updating base /tmp/git-<some-argocd-application>191239555/<kustomize-path>","time":"2025-10-30T05:22:43Z"}
{"application":"<some-argocd-application>","level":"info","msg":"Successfully updated the live application spec","time":"2025-10-30T05:22:43Z"}
{"level":"info","msg":"Processing results: applications=25 images_considered=13 images_skipped=12 images_updated=2 errors=6","time":"2025-10-30T05:22:43Z"}
```


Hints from issue comments:
@chengfang: Thanks for reporting the issue. For git operations, image updater calls argo-cd executil to do the actual git execution, and looks like the image updater logformat setting is not propagated. Will look into that.
https://github.com/argoproj-labs/argocd-image-updater/blob/master-annotation-based/ext/git/client.go#L813

`ext/git` pkg was copied from argo-cd verbatim so we should try to avoid deviating from the source too much.@dkarpele: Hi @incubator4 , I can modify this log and it will look like this. Will it work for you?
Unfortunately "git" log lines are not a part of the main Image Updater context. First 2 lines have more structured information and have information about controller and application.
```
{"application":"argocd-image-updater-e2e/image-updater-007","controller":"imageupdater","controllerGroup":"argocd-image-updater.argoproj.io","controllerKind":"ImageUpdater","imageUpdater_name":"image-updater-007-1","imageUpdater_namespace":"argocd-image-updater-e2e","level":"info","logger":"reconcile","msg":"Committing 1 parameter update(s) for application image-updater-007","time":"2025-10-30T21:07:28+01:00"}
{"application":"argocd-image-updater-e2e/image-updater-007","controller":"imageupdater","controllerGroup":"argocd-image-updater.argoproj.io","controllerKind":"ImageUpdater","imageUpdater_name":"image-updater-007-1","imageUpdater_namespace":"argocd-image-updater-e2e","level":"trace","logger":"reconcile","msg":"targetRevision for update is 'master'","time":"2025-10-30T21:07:28+01:00"}
{"level":"info","msg":"Initializing https://127.0.0.1:30003/testdata.git to /var/folders/2j/0pgmqhq95pv6l80wmfl7fdxc0000gn/T/git-image-updater-0072771200728","time":"2025-10-30T21:07:28+01:00"}
{"dir":"/var/folders/2j/0pgmqhq95pv6l80wmfl7fdxc0000gn/T/git-image-updater-0072771200728","execID":"6ea05","level":"info","msg":"git fetch origin master --force --prune --depth 1","time":"2025-10-30T21:07:28+01:00"}
{"duration":2271134708,"execID":"6ea05","level":"debug","msg":"","time":"2025-10-30T21:07:30+01:00"}
{"args":"[git fetch origin master --force --prune --depth 1]","dir":"/var/folders/2j/0pgmqhq95pv6l80wmfl7fdxc0000gn/T/git-image-updater-0072771200728","level":"info","msg":"Trace","operation_name":"exec git","time":"2025-10-30T21:07:30+01:00","time_ms":2271.219083}
{"dir":"/var/folders/2j/0pgmqhq95pv6l80wmfl7fdxc0000gn/T/git-image-updater-0072771200728","execID":"ef5f0","level":"info","msg":"git checkout --force master","time":"2025-10-30T21:07:30+01:00"}
{"duration":15583375,"execID":"ef5f0","level":"debug","msg":"branch 'master' set up to track 'origin/master'.\n","time":"2025-10-30T21:07:30+01:00"}
```@incubator4: > Hi @incubator4 , I can modify this log and it will look like this. Will it work for you?
> Unfortunately "git" log lines are not a part of the main Image Updater context. First 2 lines have more structured information and have information about controller and application.
> 
> 

Thank you for replying this issue.

Definitely, cause of git might works independently. The flag logformat could not control its behavior.

Our purpose and requirements is to make sure that Loki could format with json.

Modify git command log format would be helpful, but I cannot give opinions about informations on git logs.

Solution patch:
diff --git a/cmd/run.go b/cmd/run.go
index 5cd1579..a1a1355 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -19,6 +19,8 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
 	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
 
+	argocdlog "github.com/argoproj/argo-cd/v3/util/log"
+
 	api "github.com/argoproj-labs/argocd-image-updater/api/v1alpha1"
 	"github.com/argoproj-labs/argocd-image-updater/internal/controller"
 	"github.com/argoproj-labs/argocd-image-updater/pkg/argocd"
@@ -61,6 +63,21 @@ Flags can configure its metrics, health probes, and leader election.
 This enables a CRD-driven approach to automated image updates with Argo CD.
 `,
 		RunE: func(cmd *cobra.Command, args []string) error {
+			// Configure the controller for run once mode
+			if once {
+				cfg.CheckInterval = 0
+				probeAddr = "0"
+				warmUpCache = true
+			}
+
+			// Configure the global logger for vendored argo-cd utilities
+			logLvl, err := logrus.ParseLevel(cfg.LogLevel)
+			if err != nil {
+				return fmt.Errorf("could not parse log level: %w", err)
+			}
+			logrus.SetLevel(logLvl)
+			logrus.SetFormatter(argocdlog.CreateFormatter(cfg.LogFormat))
+
 			if err := log.SetLogLevel(cfg.LogLevel); err != nil {
 				return err
 			}
@@ -75,12 +92,6 @@ This enables a CRD-driven approach to automated image updates with Argo CD.
 				return fmt.Errorf("invalid log format '%s'", cfg.LogFormat)
 			}
 
-			if once {
-				cfg.CheckInterval = 0
-				probeAddr = "0"
-				warmUpCache = true
-			}
-
 			log.SetLogFormat(logFormat)
 
 			ctrl.SetLogger(logrusr.New(log.Log()))
@@ -97,7 +108,7 @@ This enables a CRD-driven approach to automated image updates with Argo CD.
 
 			// Create context with signal handling
 			ctx := ctrl.SetupSignalHandler()
-			err := SetupCommon(ctx, cfg, setupLogger, commitMessagePath, kubeConfig)
+			err = SetupCommon(ctx, cfg, setupLogger, commitMessagePath, kubeConfig)
 			if err != nil {
 				return err
 			}
diff --git a/ext/git/client.go b/ext/git/client.go
index b0f98b0..edbf262 100644
--- a/ext/git/client.go
+++ b/ext/git/client.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"crypto/tls"
 	"fmt"
 	"math"
@@ -24,7 +25,6 @@ import (
 	githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
 	"github.com/go-git/go-git/v5/storage/memory"
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
 	"golang.org/x/crypto/ssh"
 	"golang.org/x/crypto/ssh/knownhosts"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -35,6 +35,8 @@ import (
 	"github.com/argoproj/argo-cd/v3/util/env"
 	executil "github.com/argoproj/argo-cd/v3/util/exec"
 	"github.com/argoproj/argo-cd/v3/util/proxy"
+
+	"github.com/argoproj-labs/argocd-image-updater/registry-scanner/pkg/log"
 )
 
 var ErrInvalidRepoURL = fmt.Errorf("repo URL is invalid")
@@ -62,26 +64,26 @@ type gitRefCache interface {
 // Client is a generic git client interface
 type Client interface {
 	Root() string
-	Init() error
-	Fetch(revision string) error
-	ShallowFetch(revision string, depth int) error
-	Submodule() error
-	Checkout(revision string, submoduleEnabled bool) error
-	LsRefs() (*Refs, error)
-	LsRemote(revision string) (string, error)
-	LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error)
-	LsLargeFiles() ([]string, error)
-	CommitSHA() (string, error)
-	RevisionMetadata(revision string) (*RevisionMetadata, error)
-	VerifyCommitSignature(string) (string, error)
-	IsAnnotatedTag(string) bool
-	ChangedFiles(revision string, targetRevision string) ([]string, error)
-	Commit(pathSpec string, opts *CommitOptions) error
-	Branch(sourceBranch string, targetBranch string) error
-	Push(remote string, branch string, force bool) error
-	Add(path string) error
-	SymRefToBranch(symRef string) (string, error)
-	Config(username string, email string) error
+	Init(ctx context.Context) error
+	Fetch(ctx context.Context, revision string) error
+	ShallowFetch(ctx context.Context, revision string, depth int) error
+	Submodule(ctx context.Context) error
+	Checkout(ctx context.Context, revision string, submoduleEnabled bool) error
+	LsRefs(ctx context.Context) (*Refs, error)
+	LsRemote(ctx context.Context, revision string) (string, error)
+	LsFiles(ctx context.Context, path string, enableNewGitFileGlobbing bool) ([]string, error)
+	LsLargeFiles(ctx context.Context) ([]string, error)
+	CommitSHA(ctx context.Context) (string, error)
+	RevisionMetadata(ctx context.Context, revision string) (*RevisionMetadata, error)
+	VerifyCommitSignature(ctx context.Context, revision string) (string, error)
+	IsAnnotatedTag(ctx context.Context, revision string) bool
+	ChangedFiles(ctx context.Context, revision string, targetRevision string) ([]string, error)
+	Commit(ctx context.Context, pathSpec string, opts *CommitOptions) error
+	Branch(ctx context.Context, sourceBranch string, targetBranch string) error
+	Push(ctx context.Context, remote string, branch string, force bool) error
+	Add(ctx context.Context, path string) error
+	SymRefToBranch(ctx context.Context, symRef string) (string, error)
+	Config(ctx context.Context, username string, email string) error
 }
 
 type EventHandlers struct {
@@ -195,7 +197,9 @@ var (
 //     a client with those certificates in the list of root CAs used to verify
 //     the server's certificate.
 //   - Otherwise (and on non-fatal errors), a default HTTP client is returned.
-func GetRepoHTTPClient(repoURL string, insecure bool, creds Creds, proxyURL string) *http.Client {
+func GetRepoHTTPClient(ctx context.Context, repoURL string, insecure bool, creds Creds, proxyURL string) *http.Client {
+	log := log.LoggerFromContext(ctx)
+
 	// Default HTTP client
 	var customHTTPClient = &http.Client{
 		// 15 second timeout by default
@@ -259,7 +263,9 @@ func GetRepoHTTPClient(repoURL string, insecure bool, creds Creds, proxyURL stri
 	return customHTTPClient
 }
 
-func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) {
+func newAuth(ctx context.Context, repoURL string, creds Creds) (transport.AuthMethod, error) {
+	log := log.LoggerFromContext(ctx)
+
 	switch creds := creds.(type) {
 	case SSHCreds:
 		var sshUser string
@@ -291,7 +297,7 @@ func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) {
 		}
 		return &auth, nil
 	case GitHubAppCreds:
-		token, err := creds.getAccessToken()
+		token, err := creds.getAccessToken(ctx)
 		if err != nil {
 			return nil, err
 		}
@@ -318,7 +324,9 @@ func (m *nativeGitClient) Root() string {
 }
 
 // Init initializes a local git repository and sets the remote origin
-func (m *nativeGitClient) Init() error {
+func (m *nativeGitClient) Init(ctx context.Context) error {
+	log := log.LoggerFromContext(ctx)
+
 	_, err := git.PlainOpen(m.root)
 	if err == nil {
 		return nil
@@ -351,30 +359,30 @@ func (m *nativeGitClient) IsLFSEnabled() bool {
 	return m.enableLfs
 }
 
-func (m *nativeGitClient) fetch(revision string) error {
+func (m *nativeGitClient) fetch(ctx context.Context, revision string) error {
 	var err error
 	if revision != "" {
-		err = m.runCredentialedCmd("fetch", "origin", revision, "--tags", "--force", "--prune")
+		err = m.runCredentialedCmd(ctx, "fetch", "origin", revision, "--tags", "--force", "--prune")
 	} else {
-		err = m.runCredentialedCmd("fetch", "origin", "--tags", "--force", "--prune")
+		err = m.runCredentialedCmd(ctx, "fetch", "origin", "--tags", "--force", "--prune")
 	}
 	return err
 }
 
 // Fetch fetches latest updates from origin
-func (m *nativeGitClient) Fetch(revision string) error {
+func (m *nativeGitClient) Fetch(ctx context.Context, revision string) error {
 	if m.OnFetch != nil {
 		done := m.OnFetch(m.repoURL)
 		defer done()
 	}
 
-	err := m.fetch(revision)
+	err := m.fetch(ctx, revision)
 
 	// When we have LFS support enabled, check for large files and fetch them too.
 	if err == nil && m.IsLFSEnabled() {
-		largeFiles, err := m.LsLargeFiles()
+		largeFiles, err := m.LsLargeFiles(ctx)
 		if err == nil && len(largeFiles) > 0 {
-			err = m.runCredentialedCmd("lfs", "fetch", "--all")
+			err = m.runCredentialedCmd(ctx, "lfs", "fetch", "--all")
 			if err != nil {
 				return err
 			}
@@ -385,7 +393,9 @@ func (m *nativeGitClient) Fetch(revision string) error {
 }
 
 // LsFiles lists the local working tree, including only files that are under source control
-func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {
+func (m *nativeGitClient) LsFiles(ctx context.Context, path string, enableNewGitFileGlobbing bool) ([]string, error) {
+	log := log.LoggerFromContext(ctx)
+
 	if enableNewGitFileGlobbing {
 		// This is the new way with safer globbing
 		err := os.Chdir(m.root)
@@ -415,7 +425,7 @@ func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([
 		return files, nil
 	} else {
 		// This is the old and default way
-		out, err := m.runCmd("ls-files", "--full-name", "-z", "--", path)
+		out, err := m.runCmd(ctx, "ls-files", "--full-name", "-z", "--", path)
 		if err != nil {
 			return nil, err
 		}
@@ -426,8 +436,8 @@ func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([
 }
 
 // LsLargeFiles lists all files that have references to LFS storage
-func (m *nativeGitClient) LsLargeFiles() ([]string, error) {
-	out, err := m.runCmd("lfs", "ls-files", "-n")
+func (m *nativeGitClient) LsLargeFiles(ctx context.Context) ([]string, error) {
+	out, err := m.runCmd(ctx, "lfs", "ls-files", "-n")
 	if err != nil {
 		return nil, err
 	}
@@ -436,30 +446,30 @@ func (m *nativeGitClient) LsLargeFiles() ([]string, error) {
 }
 
 // Submodule embed other repositories into this repository
-func (m *nativeGitClient) Submodule() error {
-	if err := m.runCredentialedCmd("submodule", "sync", "--recursive"); err != nil {
+func (m *nativeGitClient) Submodule(ctx context.Context) error {
+	if err := m.runCredentialedCmd(ctx, "submodule", "sync", "--recursive"); err != nil {
 		return err
 	}
-	if err := m.runCredentialedCmd("submodule", "update", "--init", "--recursive"); err != nil {
+	if err := m.runCredentialedCmd(ctx, "submodule", "update", "--init", "--recursive"); err != nil {
 		return err
 	}
 	return nil
 }
 
 // Checkout checkout specified revision
-func (m *nativeGitClient) Checkout(revision string, submoduleEnabled bool) error {
+func (m *nativeGitClient) Checkout(ctx context.Context, revision string, submoduleEnabled bool) error {
 	if revision == "" || revision == "HEAD" {
 		revision = "origin/HEAD"
 	}
-	if _, err := m.runCmd("checkout", "--force", revision); err != nil {
+	if _, err := m.runCmd(ctx, "checkout", "--force", revision); err != nil {
 		return err
 	}
 	// We must populate LFS content by using lfs checkout, if we have at least
 	// one LFS reference in the current revision.
 	if m.IsLFSEnabled() {
-		if largeFiles, err := m.LsLargeFiles(); err == nil {
+		if largeFiles, err := m.LsLargeFiles(ctx); err == nil {
 			if len(largeFiles) > 0 {
-				if _, err := m.runCmd("lfs", "checkout"); err != nil {
+				if _, err := m.runCmd(ctx, "lfs", "checkout"); err != nil {
 					return err
 				}
 			}
@@ -469,7 +479,7 @@ func (m *nativeGitClient) Checkout(revision string, submoduleEnabled bool) error
 	}
 	if _, err := os.Stat(m.root + "/.gitmodules"); !os.IsNotExist(err) {
 		if submoduleEnabled {
-			if err := m.Submodule(); err != nil {
+			if err := m.Submodule(ctx); err != nil {
 				return err
 			}
 		}
@@ -479,17 +489,19 @@ func (m *nativeGitClient) Checkout(revision string, submoduleEnabled bool) error
 	// `git clean` to delete untracked files and directories, and the second “f”
 	// tells it to clean untractked nested Git repositories (for example a
 	// submodule which has since been removed).
-	if _, err := m.runCmd("clean", "-ffdx"); err != nil {
+	if _, err := m.runCmd(ctx, "clean", "-ffdx"); err != nil {
 		return err
 	}
 	return nil
 }
 
-func (m *nativeGitClient) getRefs() ([]*plumbing.Reference, error) {
+func (m *nativeGitClient) getRefs(ctx context.Context) ([]*plumbing.Reference, error) {
+	log := log.LoggerFromContext(ctx)
+
 	myLockUUID, err := uuid.NewRandom()
 	myLockId := ""
 	if err != nil {
-		log.Debug("Error generating git references cache lock id: ", err)
+		log.Debugf("Error generating git references cache lock id: %v", err)
 	} else {
 		myLockId = myLockUUID.String()
 	}
@@ -534,11 +546,11 @@ func (m *nativeGitClient) getRefs() ([]*plumbing.Reference, error) {
 	if err != nil {
 		return nil, err
 	}
-	auth, err := newAuth(m.repoURL, m.creds)
+	auth, err := newAuth(ctx, m.repoURL, m.creds)
 	if err != nil {
 		return nil, err
 	}
-	res, err := listRemote(remote, &git.ListOptions{Auth: auth}, m.insecure, m.creds, m.proxy)
+	res, err := listRemote(ctx, remote, &git.ListOptions{Auth: auth}, m.insecure, m.creds, m.proxy)
 	if err == nil && m.gitRefCache != nil {
 		if err := m.gitRefCache.SetGitReferences(m.repoURL, res); err != nil {
 			log.Warnf("Failed to store git references to cache: %v", err)
@@ -551,8 +563,10 @@ func (m *nativeGitClient) getRefs() ([]*plumbing.Reference, error) {
 	return res, err
 }
 
-func (m *nativeGitClient) LsRefs() (*Refs, error) {
-	refs, err := m.getRefs()
+func (m *nativeGitClient) LsRefs(ctx context.Context) (*Refs, error) {
+	log := log.LoggerFromContext(ctx)
+
+	refs, err := m.getRefs(ctx)
 
 	if err != nil {
 		return nil, err
@@ -585,9 +599,9 @@ func (m *nativeGitClient) LsRefs() (*Refs, error) {
 // Otherwise, it returns an error indicating that the revision could not be resolved. This method
 // runs with in-memory storage and is safe to run concurrently, or to be run without a git
 // repository locally cloned.
-func (m *nativeGitClient) LsRemote(revision string) (res string, err error) {
+func (m *nativeGitClient) LsRemote(ctx context.Context, revision string) (res string, err error) {
 	for attempt := 0; attempt < maxAttemptsCount; attempt++ {
-		res, err = m.lsRemote(revision)
+		res, err = m.lsRemote(ctx, revision)
 		if err == nil {
 			return
 		} else if apierrors.IsInternalError(err) || apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) ||
@@ -605,12 +619,14 @@ func (m *nativeGitClient) LsRemote(revision string) (res string, err error) {
 	return
 }
 
-func (m *nativeGitClient) lsRemote(revision string) (string, error) {
+func (m *nativeGitClient) lsRemote(ctx context.Context, revision string) (string, error) {
+	log := log.LoggerFromContext(ctx)
+
 	if IsCommitSHA(revision) {
 		return revision, nil
 	}
 
-	refs, err := m.getRefs()
+	refs, err := m.getRefs(ctx)
 
 	if err != nil {
 		return "", err
@@ -660,17 +676,17 @@ func (m *nativeGitClient) lsRemote(revision string) (string, error) {
 }
 
 // CommitSHA returns current commit sha from `git rev-parse HEAD`
-func (m *nativeGitClient) CommitSHA() (string, error) {
-	out, err := m.runCmd("rev-parse", "HEAD")
+func (m *nativeGitClient) CommitSHA(ctx context.Context) (string, error) {
+	out, err := m.runCmd(ctx, "rev-parse", "HEAD")
 	if err != nil {
 		return "", err
 	}
 	return strings.TrimSpace(out), nil
 }
 
-// returns the meta-data for the commit
-func (m *nativeGitClient) RevisionMetadata(revision string) (*RevisionMetadata, error) {
-	out, err := m.runCmd("show", "-s", "--format=%an <%ae>|%at|%B", revision)
+// RevisionMetadata returns the meta-data for the commit
+func (m *nativeGitClient) RevisionMetadata(ctx context.Context, revision string) (*RevisionMetadata, error) {
+	out, err := m.runCmd(ctx, "show", "-s", "--format=%an <%ae>|%at|%B", revision)
 	if err != nil {
 		return nil, err
 	}
@@ -682,7 +698,7 @@ func (m *nativeGitClient) RevisionMetadata(revision string) (*RevisionMetadata,
 	authorDateUnixTimestamp, _ := strconv.ParseInt(segments[1], 10, 64)
 	message := strings.TrimSpace(segments[2])
 
-	out, err = m.runCmd("tag", "--points-at", revision)
+	out, err = m.runCmd(ctx, "tag", "--points-at", revision)
 	if err != nil {
 		return nil, err
 	}
@@ -692,8 +708,8 @@ func (m *nativeGitClient) RevisionMetadata(revision string) (*RevisionMetadata,
 }
 
 // VerifyCommitSignature Runs verify-commit on a given revision and returns the output
-func (m *nativeGitClient) VerifyCommitSignature(revision string) (string, error) {
-	out, err := m.runGnuPGWrapper("git-verify-wrapper.sh", revision)
+func (m *nativeGitClient) VerifyCommitSignature(ctx context.Context, revision string) (string, error) {
+	out, err := m.runGnuPGWrapper(ctx, "git-verify-wrapper.sh", revision)
 	if err != nil {
 		return "", err
 	}
@@ -701,9 +717,9 @@ func (m *nativeGitClient) VerifyCommitSignature(revision string) (string, error)
 }
 
 // IsAnnotatedTag returns true if the revision points to an annotated tag
-func (m *nativeGitClient) IsAnnotatedTag(revision string) bool {
+func (m *nativeGitClient) IsAnnotatedTag(ctx context.Context, revision string) bool {
 	cmd := exec.Command("git", "describe", "--exact-match", revision)
-	out, err := m.runCmdOutput(cmd, runOpts{SkipErrorLogging: true})
+	out, err := m.runCmdOutput(ctx, cmd, runOpts{SkipErrorLogging: true})
 	if out != "" && err == nil {
 		return true
 	} else {
@@ -711,8 +727,8 @@ func (m *nativeGitClient) IsAnnotatedTag(revision string) bool {
 	}
 }
 
-// returns the meta-data for the commit
-func (m *nativeGitClient) ChangedFiles(revision string, targetRevision string) ([]string, error) {
+// ChangedFiles returns the meta-data for the commit
+func (m *nativeGitClient) ChangedFiles(ctx context.Context, revision string, targetRevision string) ([]string, error) {
 	if revision == targetRevision {
 		return []string{}, nil
 	}
@@ -721,7 +737,7 @@ func (m *nativeGitClient) ChangedFiles(revision string, targetRevision string) (
 		return []string{}, fmt.Errorf("invalid revision provided, must be SHA")
 	}
 
-	out, err := m.runCmd("diff", "--name-only", fmt.Sprintf("%s..%s", revision, targetRevision))
+	out, err := m.runCmd(ctx, "diff", "--name-only", fmt.Sprintf("%s..%s", revision, targetRevision))
 	if err != nil {
 		return nil, fmt.Errorf("failed to diff %s..%s: %w", revision, targetRevision, err)
 	}
@@ -735,22 +751,22 @@ func (m *nativeGitClient) ChangedFiles(revision string, targetRevision string) (
 }
 
 // runWrapper runs a custom command with all the semantics of running the Git client
-func (m *nativeGitClient) runGnuPGWrapper(wrapper string, args ...string) (string, error) {
+func (m *nativeGitClient) runGnuPGWrapper(ctx context.Context, wrapper string, args ...string) (string, error) {
 	cmd := exec.Command(wrapper, args...)
 	cmd.Env = append(cmd.Env, fmt.Sprintf("GNUPGHOME=%s", common.GetGnuPGHomePath()), "LANG=C")
-	return m.runCmdOutput(cmd, runOpts{})
+	return m.runCmdOutput(ctx, cmd, runOpts{})
 }
 
 // runCmd is a convenience function to run a command in a given directory and return its output
-func (m *nativeGitClient) runCmd(args ...string) (string, error) {
+func (m *nativeGitClient) runCmd(ctx context.Context, args ...string) (string, error) {
 	cmd := exec.Command("git", args...)
-	return m.runCmdOutput(cmd, runOpts{})
+	return m.runCmdOutput(ctx, cmd, runOpts{})
 }
 
 // runCredentialedCmd is a convenience function to run a git command with username/password credentials
 // nolint:unparam
-func (m *nativeGitClient) runCredentialedCmd(args ...string) error {
-	closer, environ, err := m.creds.Environ()
+func (m *nativeGitClient) runCredentialedCmd(ctx context.Context, args ...string) error {
+	closer, environ, err := m.creds.Environ(ctx)
 	if err != nil {
 		return err
 	}
@@ -766,11 +782,13 @@ func (m *nativeGitClient) runCredentialedCmd(args ...string) error {
 
 	cmd := exec.Command("git", args...)
 	cmd.Env = append(cmd.Env, environ...)
-	_, err = m.runCmdOutput(cmd, runOpts{})
+	_, err = m.runCmdOutput(ctx, cmd, runOpts{})
 	return err
 }
 
-func (m *nativeGitClient) runCmdOutput(cmd *exec.Cmd, ropts runOpts) (string, error) {
+func (m *nativeGitClient) runCmdOutput(ctx context.Context, cmd *exec.Cmd, ropts runOpts) (string, error) {
+	log := log.LoggerFromContext(ctx)
+
 	cmd.Dir = m.root
 	cmd.Env = append(os.Environ(), cmd.Env...)
 	// Set $HOME to nowhere, so we can be execute Git regardless of any external
diff --git a/ext/git/creds.go b/ext/git/creds.go
index c849404..3cba4b2 100644
--- a/ext/git/creds.go
+++ b/ext/git/creds.go
@@ -22,11 +22,13 @@ import (
 	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/text"
 	"github.com/bradleyfalzon/ghinstallation/v2"
-	log "github.com/sirupsen/logrus"
+	"github.com/sirupsen/logrus"
 
 	"github.com/argoproj/argo-cd/v3/common"
 	certutil "github.com/argoproj/argo-cd/v3/util/cert"
 	argoioutils "github.com/argoproj/argo-cd/v3/util/io"
+
+	"github.com/argoproj-labs/argocd-image-updater/registry-scanner/pkg/log"
 )
 
 var (
@@ -73,7 +75,7 @@ type CredsStore interface {
 }
 
 type Creds interface {
-	Environ() (io.Closer, []string, error)
+	Environ(ctx context.Context) (io.Closer, []string, error)
 }
 
 func getGitAskPassEnv(id string) []string {
@@ -105,7 +107,7 @@ var _ Creds = NopCreds{}
 type NopCreds struct {
 }
 
-func (c NopCreds) Environ() (io.Closer, []string, error) {
+func (c NopCreds) Environ(context.Context) (io.Closer, []string, error) {
 	return NopCloser{}, nil, nil
 }
 
@@ -115,7 +117,7 @@ type GenericHTTPSCreds interface {
 	HasClientCert() bool
 	GetClientCertData() string
 	GetClientCertKey() string
-	Environ() (io.Closer, []string, error)
+	Environ(ctx context.Context) (io.Closer, []string, error)
 }
 
 var _ GenericHTTPSCreds = HTTPSCreds{}
@@ -162,7 +164,9 @@ func (c HTTPSCreds) BasicAuthHeader() string {
 
 // Get additional required environment variables for executing git client to
 // access specific repository via HTTPS.
-func (c HTTPSCreds) Environ() (io.Closer, []string, error) {
+func (c HTTPSCreds) Environ(ctx context.Context) (io.Closer, []string, error) {
+	log := log.LoggerFromContext(ctx)
+
 	var env []string
 
 	httpCloser := authFilePaths(make([]string, 0))
@@ -203,7 +207,7 @@ func (c HTTPSCreds) Environ() (io.Closer, []string, error) {
 
 		_, err = certFile.WriteString(c.clientCertData)
 		if err != nil {
-			httpCloser.Close()
+			httpCloser.Close(ctx)
 			return NopCloser{}, nil, err
 		}
 		// GIT_SSL_CERT is the full path to a client certificate to be used
@@ -211,7 +215,7 @@ func (c HTTPSCreds) Environ() (io.Closer, []string, error) {
 
 		_, err = keyFile.WriteString(c.clientCertKey)
 		if err != nil {
-			httpCloser.Close()
+			httpCloser.Close(ctx)
 			return NopCloser{}, nil, err
 		}
 		// GIT_SSL_KEY is the full path to a client certificate's key to be used
@@ -227,7 +231,7 @@ func (c HTTPSCreds) Environ() (io.Closer, []string, error) {
 	env = append(env, getGitAskPassEnv(nonce)...)
 	return argoioutils.NewCloser(func() error {
 		c.store.Remove(nonce)
-		return httpCloser.Close()
+		return httpCloser.Close(ctx)
 	}), env, nil
 }
 
@@ -266,7 +270,9 @@ func (f sshPrivateKeyFile) Close() error {
 
 // Remove a list of files that have been created as temp files while creating
 // HTTPCreds object above.
-func (f authFilePaths) Close() error {
+func (f authFilePaths) Close(ctx context.Context) error {
+	log := log.LoggerFromContext(ctx)
+
 	var retErr error = nil
 	for _, path := range f {
 		err := os.Remove(path)
@@ -278,7 +284,9 @@ func (f authFilePaths) Close() error {
 	return retErr
 }
 
-func (c SSHCreds) Environ() (io.Closer, []string, error) {
+func (c SSHCreds) Environ(ctx context.Context) (io.Closer, []string, error) {
+	log := log.LoggerFromContext(ctx)
+
 	// use the SHM temp dir from util, more secure
 	file, err := os.CreateTemp(argoio.TempDir, "")
 	if err != nil {
@@ -286,7 +294,7 @@ func (c SSHCreds) Environ() (io.Closer, []string, error) {
 	}
 	defer func() {
 		if err = file.Close(); err != nil {
-			log.WithFields(log.Fields{
+			log.WithFields(logrus.Fields{
 				common.SecurityField:    common.SecurityMedium,
 				common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
 			}).Errorf("error closing file %q: %v", file.Name(), err)
@@ -353,8 +361,10 @@ func NewGitHubAppCreds(appID int64, appInstallId int64, privateKey string, baseU
 	return GitHubAppCreds{appID: appID, appInstallId: appInstallId, privateKey: privateKey, baseURL: baseURL, repoURL: repoURL, clientCertData: clientCertData, clientCertKey: clientCertKey, insecure: insecure, proxy: proxy, store: store}
 }
 
-func (g GitHubAppCreds) Environ() (io.Closer, []string, error) {
-	token, err := g.getAccessToken()
+func (g GitHubAppCreds) Environ(ctx context.Context) (io.Closer, []string, error) {
+	log := log.LoggerFromContext(ctx)
+
+	token, err := g.getAccessToken(ctx)
 	if err != nil {
 		return NopCloser{}, nil, err
 	}
@@ -397,7 +407,7 @@ func (g GitHubAppCreds) Environ() (io.Closer, []string, error) {
 
 		_, err = certFile.WriteString(g.clientCertData)
 		if err != nil {
-			httpCloser.Close()
+			httpCloser.Close(ctx)
 			return NopCloser{}, nil, err
 		}
 		// GIT_SSL_CERT is the full path to a client certificate to be used
@@ -405,7 +415,7 @@ func (g GitHubAppCreds) Environ() (io.Closer, []string, error) {
 
 		_, err = keyFile.WriteString(g.clientCertKey)
 		if err != nil {
-			httpCloser.Close()
+			httpCloser.Close(ctx)
 			return NopCloser{}, nil, err
 		}
 		// GIT_SSL_KEY is the full path to a client certificate's key to be used
@@ -416,15 +426,15 @@ func (g GitHubAppCreds) Environ() (io.Closer, []string, error) {
 	env = append(env, getGitAskPassEnv(nonce)...)
 	return argoioutils.NewCloser(func() error {
 		g.store.Remove(nonce)
-		return httpCloser.Close()
+		return httpCloser.Close(ctx)
 	}), env, nil
 }
 
 // getAccessToken fetches GitHub token using the app id, install id, and private key.
 // the token is then cached for re-use.
-func (g GitHubAppCreds) getAccessToken() (string, error) {
+func (g GitHubAppCreds) getAccessToken(ctx context.Context) (string, error) {
 	// Timeout
-	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+	ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
 	defer cancel()
 
 	// Compute hash of creds for lookup in cache
@@ -450,7 +460,7 @@ func (g GitHubAppCreds) getAccessToken() (string, error) {
 	}
 
 	// Create a new GitHub transport
-	c := GetRepoHTTPClient(baseUrl, g.insecure, g, g.proxy)
+	c := GetRepoHTTPClient(ctx, baseUrl, g.insecure, g, g.proxy)
 	itr, err := ghinstallation.New(c.Transport,
 		g.appID,
 		g.appInstallId,
@@ -495,7 +505,7 @@ func NewGoogleCloudCreds(jsonData string, store CredsStore) GoogleCloudCreds {
 	return GoogleCloudCreds{creds, store}
 }
 
-func (c GoogleCloudCreds) Environ() (io.Closer, []string, error) {
+func (c GoogleCloudCreds) Environ(context.Context) (io.Closer, []string, error) {
 	username, err := c.getUsername()
 	if err != nil {
 		return NopCloser{}, nil, fmt.Errorf("failed to get username from creds: %w", err)
diff --git a/ext/git/git.go b/ext/git/git.go
index d5a8652..f9a6327 100644
--- a/ext/git/git.go
+++ b/ext/git/git.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"net/url"
 	"regexp"
 	"strings"
@@ -83,11 +84,11 @@ func IsHTTPURL(url string) bool {
 }
 
 // TestRepo tests if a repo exists and is accessible with the given credentials
-func TestRepo(repo string, creds Creds, insecure bool, enableLfs bool, proxy string) error {
+func TestRepo(ctx context.Context, repo string, creds Creds, insecure bool, enableLfs bool, proxy string) error {
 	clnt, err := NewClient(repo, creds, insecure, enableLfs, proxy)
 	if err != nil {
 		return err
 	}
-	_, err = clnt.LsRemote("HEAD")
+	_, err = clnt.LsRemote(ctx, "HEAD")
 	return err
 }
diff --git a/ext/git/mocks/Client.go b/ext/git/mocks/Client.go
index ffe2b91..3f47b82 100644
--- a/ext/git/mocks/Client.go
+++ b/ext/git/mocks/Client.go
@@ -3,6 +3,8 @@
 package mocks
 
 import (
+	"context"
+
 	git "github.com/argoproj-labs/argocd-image-updater/ext/git"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -13,7 +15,7 @@ type Client struct {
 }
 
 // Add provides a mock function with given fields: path
-func (_m *Client) Add(path string) error {
+func (_m *Client) Add(ctx context.Context, path string) error {
 	ret := _m.Called(path)
 
 	if len(ret) == 0 {
@@ -31,7 +33,7 @@ func (_m *Client) Add(path string) error {
 }
 
 // Branch provides a mock function with given fields: sourceBranch, targetBranch
-func (_m *Client) Branch(sourceBranch string, targetBranch string) error {
+func (_m *Client) Branch(ctx context.Context, sourceBranch string, targetBranch string) error {
 	ret := _m.Called(sourceBranch, targetBranch)
 
 	if len(ret) == 0 {
@@ -49,7 +51,7 @@ func (_m *Client) Branch(sourceBranch string, targetBranch string) error {
 }
 
 // ChangedFiles provides a mock function with given fields: revision, targetRevision
-func (_m *Client) ChangedFiles(revision string, targetRevision string) ([]string, error) {
+func (_m *Client) ChangedFiles(ctx context.Context, revision string, targetRevision string) ([]string, error) {
 	ret := _m.Called(revision, targetRevision)
 
 	if len(ret) == 0 {
@@ -79,7 +81,7 @@ func (_m *Client) ChangedFiles(revision string, targetRevision string) ([]string
 }
 
 // Checkout provides a mock function with given fields: revision, submoduleEnabled
-func (_m *Client) Checkout(revision string, submoduleEnabled bool) error {
+func (_m *Client) Checkout(ctx context.Context, revision string, submoduleEnabled bool) error {
 	ret := _m.Called(revision, submoduleEnabled)
 
 	if len(ret) == 0 {
@@ -97,7 +99,7 @@ func (_m *Client) Checkout(revision string, submoduleEnabled bool) error {
 }
 
 // Commit provides a mock function with given fields: pathSpec, opts
-func (_m *Client) Commit(pathSpec string, opts *git.CommitOptions) error {
+func (_m *Client) Commit(ctx context.Context, pathSpec string, opts *git.CommitOptions) error {
 	ret := _m.Called(pathSpec, opts)
 
 	if len(ret) == 0 {
@@ -115,7 +117,7 @@ func (_m *Client) Commit(pathSpec string, opts *git.CommitOptions) error {
 }
 
 // CommitSHA provides a mock function with given fields:
-func (_m *Client) CommitSHA() (string, error) {
+func (_m *Client) CommitSHA(context.Context) (string, error) {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -143,7 +145,7 @@ func (_m *Client) CommitSHA() (string, error) {
 }
 
 // Config provides a mock function with given fields: username, email
-func (_m *Client) Config(username string, email string) error {
+func (_m *Client) Config(ctx context.Context, username string, email string) error {
 	ret := _m.Called(username, email)
 
 	if len(ret) == 0 {
@@ -175,7 +177,7 @@ func (_m *Client) SigningConfig(signingkey string) error {
 }
 
 // Fetch provides a mock function with given fields: revision
-func (_m *Client) Fetch(revision string) error {
+func (_m *Client) Fetch(ctx context.Context, revision string) error {
 	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
@@ -193,7 +195,7 @@ func (_m *Client) Fetch(revision string) error {
 }
 
 // Fetch provides a mock function with given fields: revision
-func (_m *Client) ShallowFetch(revision string, depth int) error {
+func (_m *Client) ShallowFetch(ctx context.Context, revision string, depth int) error {
 	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
@@ -211,7 +213,7 @@ func (_m *Client) ShallowFetch(revision string, depth int) error {
 }
 
 // Init provides a mock function with given fields:
-func (_m *Client) Init() error {
+func (_m *Client) Init(context.Context) error {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -229,8 +231,8 @@ func (_m *Client) Init() error {
 }
 
 // IsAnnotatedTag provides a mock function with given fields: _a0
-func (_m *Client) IsAnnotatedTag(_a0 string) bool {
-	ret := _m.Called(_a0)
+func (_m *Client) IsAnnotatedTag(ctx context.Context, revision string) bool {
+	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
 		panic("no return value specified for IsAnnotatedTag")
@@ -238,7 +240,7 @@ func (_m *Client) IsAnnotatedTag(_a0 string) bool {
 
 	var r0 bool
 	if rf, ok := ret.Get(0).(func(string) bool); ok {
-		r0 = rf(_a0)
+		r0 = rf(revision)
 	} else {
 		r0 = ret.Get(0).(bool)
 	}
@@ -247,7 +249,7 @@ func (_m *Client) IsAnnotatedTag(_a0 string) bool {
 }
 
 // LsFiles provides a mock function with given fields: path, enableNewGitFileGlobbing
-func (_m *Client) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {
+func (_m *Client) LsFiles(ctx context.Context, path string, enableNewGitFileGlobbing bool) ([]string, error) {
 	ret := _m.Called(path, enableNewGitFileGlobbing)
 
 	if len(ret) == 0 {
@@ -277,7 +279,7 @@ func (_m *Client) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string,
 }
 
 // LsLargeFiles provides a mock function with given fields:
-func (_m *Client) LsLargeFiles() ([]string, error) {
+func (_m *Client) LsLargeFiles(context.Context) ([]string, error) {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -307,7 +309,7 @@ func (_m *Client) LsLargeFiles() ([]string, error) {
 }
 
 // LsRefs provides a mock function with given fields:
-func (_m *Client) LsRefs() (*git.Refs, error) {
+func (_m *Client) LsRefs(context.Context) (*git.Refs, error) {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -337,7 +339,7 @@ func (_m *Client) LsRefs() (*git.Refs, error) {
 }
 
 // LsRemote provides a mock function with given fields: revision
-func (_m *Client) LsRemote(revision string) (string, error) {
+func (_m *Client) LsRemote(ctx context.Context, revision string) (string, error) {
 	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
@@ -365,7 +367,7 @@ func (_m *Client) LsRemote(revision string) (string, error) {
 }
 
 // Push provides a mock function with given fields: remote, branch, force
-func (_m *Client) Push(remote string, branch string, force bool) error {
+func (_m *Client) Push(ctx context.Context, remote string, branch string, force bool) error {
 	ret := _m.Called(remote, branch, force)
 
 	if len(ret) == 0 {
@@ -383,7 +385,7 @@ func (_m *Client) Push(remote string, branch string, force bool) error {
 }
 
 // RevisionMetadata provides a mock function with given fields: revision
-func (_m *Client) RevisionMetadata(revision string) (*git.RevisionMetadata, error) {
+func (_m *Client) RevisionMetadata(ctx context.Context, revision string) (*git.RevisionMetadata, error) {
 	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
@@ -431,7 +433,7 @@ func (_m *Client) Root() string {
 }
 
 // Submodule provides a mock function with given fields:
-func (_m *Client) Submodule() error {
+func (_m *Client) Submodule(context.Context) error {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -449,7 +451,7 @@ func (_m *Client) Submodule() error {
 }
 
 // SymRefToBranch provides a mock function with given fields: symRef
-func (_m *Client) SymRefToBranch(symRef string) (string, error) {
+func (_m *Client) SymRefToBranch(ctx context.Context, symRef string) (string, error) {
 	ret := _m.Called(symRef)
 
 	if len(ret) == 0 {
@@ -477,8 +479,8 @@ func (_m *Client) SymRefToBranch(symRef string) (string, error) {
 }
 
 // VerifyCommitSignature provides a mock function with given fields: _a0
-func (_m *Client) VerifyCommitSignature(_a0 string) (string, error) {
-	ret := _m.Called(_a0)
+func (_m *Client) VerifyCommitSignature(ctx context.Context, revision string) (string, error) {
+	ret := _m.Called(revision)
 
 	if len(ret) == 0 {
 		panic("no return value specified for VerifyCommitSignature")
@@ -487,16 +489,16 @@ func (_m *Client) VerifyCommitSignature(_a0 string) (string, error) {
 	var r0 string
 	var r1 error
 	if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
-		return rf(_a0)
+		return rf(revision)
 	}
 	if rf, ok := ret.Get(0).(func(string) string); ok {
-		r0 = rf(_a0)
+		r0 = rf(revision)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
 	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(_a0)
+		r1 = rf(revision)
 	} else {
 		r1 = ret.Error(1)
 	}
diff --git a/ext/git/mocks/Creds.go b/ext/git/mocks/Creds.go
index 205d4df..a5e9852 100644
--- a/ext/git/mocks/Creds.go
+++ b/ext/git/mocks/Creds.go
@@ -3,6 +3,7 @@
 package mocks
 
 import (
+	"context"
 	io "io"
 
 	mock "github.com/stretchr/testify/mock"
@@ -14,7 +15,7 @@ type Creds struct {
 }
 
 // Environ provides a mock function with given fields:
-func (_m *Creds) Environ() (io.Closer, []string, error) {
+func (_m *Creds) Environ(context.Context) (io.Closer, []string, error) {
 	ret := _m.Called()
 
 	var r0 io.Closer
diff --git a/ext/git/mocks/GenericHTTPSCreds.go b/ext/git/mocks/GenericHTTPSCreds.go
index 6224de7..d813fb6 100644
--- a/ext/git/mocks/GenericHTTPSCreds.go
+++ b/ext/git/mocks/GenericHTTPSCreds.go
@@ -3,6 +3,7 @@
 package mocks
 
 import (
+	"context"
 	io "io"
 
 	mock "github.com/stretchr/testify/mock"
@@ -14,7 +15,7 @@ type GenericHTTPSCreds struct {
 }
 
 // Environ provides a mock function with given fields:
-func (_m *GenericHTTPSCreds) Environ() (io.Closer, []string, error) {
+func (_m *GenericHTTPSCreds) Environ(context.Context) (io.Closer, []string, error) {
 	ret := _m.Called()
 
 	var r0 io.Closer
diff --git a/ext/git/workaround.go b/ext/git/workaround.go
index 4763612..89565ec 100644
--- a/ext/git/workaround.go
+++ b/ext/git/workaround.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"fmt"
 	neturl "net/url"
 
@@ -16,8 +17,8 @@ import (
 // As workaround methods `newUploadPackSession`, `newClient` and `listRemote` were copied from https://github.com/src-d/go-git/blob/master/remote.go and modified to use
 // transport with InsecureSkipVerify flag is verification should be disabled.
 
-func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, creds Creds, proxy string) (transport.UploadPackSession, error) {
-	c, ep, err := newClient(url, insecure, creds, proxy)
+func newUploadPackSession(ctx context.Context, url string, auth transport.AuthMethod, insecure bool, creds Creds, proxy string) (transport.UploadPackSession, error) {
+	c, ep, err := newClient(ctx, url, insecure, creds, proxy)
 	if err != nil {
 		return nil, err
 	}
@@ -25,7 +26,7 @@ func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool,
 	return c.NewUploadPackSession(ep, auth)
 }
 
-func newClient(url string, insecure bool, creds Creds, proxy string) (transport.Transport, *transport.Endpoint, error) {
+func newClient(ctx context.Context, url string, insecure bool, creds Creds, proxy string) (transport.Transport, *transport.Endpoint, error) {
 	ep, err := transport.NewEndpoint(url)
 	if err != nil {
 		return nil, nil, err
@@ -57,11 +58,11 @@ func newClient(url string, insecure bool, creds Creds, proxy string) (transport.
 		return c, ep, nil
 	}
 
-	return http.NewClient(GetRepoHTTPClient(url, insecure, creds, proxy)), ep, nil
+	return http.NewClient(GetRepoHTTPClient(ctx, url, insecure, creds, proxy)), ep, nil
 }
 
-func listRemote(r *git.Remote, o *git.ListOptions, insecure bool, creds Creds, proxy string) (rfs []*plumbing.Reference, err error) {
-	s, err := newUploadPackSession(r.Config().URLs[0], o.Auth, insecure, creds, proxy)
+func listRemote(ctx context.Context, r *git.Remote, o *git.ListOptions, insecure bool, creds Creds, proxy string) (rfs []*plumbing.Reference, err error) {
+	s, err := newUploadPackSession(ctx, r.Config().URLs[0], o.Auth, insecure, creds, proxy)
 	if err != nil {
 		return nil, err
 	}
diff --git a/ext/git/writer.go b/ext/git/writer.go
index 7953447..25171c2 100644
--- a/ext/git/writer.go
+++ b/ext/git/writer.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"fmt"
 	"os/exec"
 	"strconv"
@@ -29,7 +30,9 @@ type CommitOptions struct {
 // used as the commit message, otherwise a default commit message will be used.
 // If signingKey is not the empty string, commit will be signed with the given
 // GPG or SSH key.
-func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error {
+func (m *nativeGitClient) Commit(ctx context.Context, pathSpec string, opts *CommitOptions) error {
+	log := log.LoggerFromContext(ctx)
+
 	defaultCommitMsg := "Update parameters"
 	// Git configuration
 	config := "gpg.format=" + opts.SigningMethod
@@ -59,7 +62,7 @@ func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error {
 		args = append(args, "-m", defaultCommitMsg)
 	}
 
-	out, err := m.runCmd(args...)
+	out, err := m.runCmd(ctx, args...)
 	if err != nil {
 		log.Errorf("%s %v", out, err)
 		return err
@@ -69,15 +72,15 @@ func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error {
 }
 
 // Branch creates a new target branch from a given source branch
-func (m *nativeGitClient) Branch(sourceBranch string, targetBranch string) error {
+func (m *nativeGitClient) Branch(ctx context.Context, sourceBranch string, targetBranch string) error {
 	if sourceBranch != "" {
-		_, err := m.runCmd("checkout", sourceBranch)
+		_, err := m.runCmd(ctx, "checkout", sourceBranch)
 		if err != nil {
 			return fmt.Errorf("could not checkout source branch: %v", err)
 		}
 	}
 
-	_, err := m.runCmd("branch", targetBranch)
+	_, err := m.runCmd(ctx, "branch", targetBranch)
 	if err != nil {
 		return fmt.Errorf("could not create new branch: %v", err)
 	}
@@ -87,13 +90,13 @@ func (m *nativeGitClient) Branch(sourceBranch string, targetBranch string) error
 
 // Push pushes local changes to the remote branch. If force is true, will force
 // the remote to accept the push.
-func (m *nativeGitClient) Push(remote string, branch string, force bool) error {
+func (m *nativeGitClient) Push(ctx context.Context, remote string, branch string, force bool) error {
 	args := []string{"push"}
 	if force {
 		args = append(args, "-f")
 	}
 	args = append(args, remote, branch)
-	err := m.runCredentialedCmd(args...)
+	err := m.runCredentialedCmd(ctx, args...)
 	if err != nil {
 		return fmt.Errorf("could not push %s to %s: %v", branch, remote, err)
 	}
@@ -101,13 +104,13 @@ func (m *nativeGitClient) Push(remote string, branch string, force bool) error {
 }
 
 // Add adds a path spec to the repository
-func (m *nativeGitClient) Add(path string) error {
-	return m.runCredentialedCmd("add", path)
+func (m *nativeGitClient) Add(ctx context.Context, path string) error {
+	return m.runCredentialedCmd(ctx, "add", path)
 }
 
 // SymRefToBranch retrieves the branch name a symbolic ref points to
-func (m *nativeGitClient) SymRefToBranch(symRef string) (string, error) {
-	output, err := m.runCredentialedCmdWithOutput("remote", "show", "origin")
+func (m *nativeGitClient) SymRefToBranch(ctx context.Context, symRef string) (string, error) {
+	output, err := m.runCredentialedCmdWithOutput(ctx, "remote", "show", "origin")
 	if err != nil {
 		return "", fmt.Errorf("error running git: %v", err)
 	}
@@ -124,12 +127,12 @@ func (m *nativeGitClient) SymRefToBranch(symRef string) (string, error) {
 }
 
 // Config configures username and email address for the repository
-func (m *nativeGitClient) Config(username string, email string) error {
-	_, err := m.runCmd("config", "user.name", username)
+func (m *nativeGitClient) Config(ctx context.Context, username string, email string) error {
+	_, err := m.runCmd(ctx, "config", "user.name", username)
 	if err != nil {
 		return fmt.Errorf("could not set git username: %v", err)
 	}
-	_, err = m.runCmd("config", "user.email", email)
+	_, err = m.runCmd(ctx, "config", "user.email", email)
 	if err != nil {
 		return fmt.Errorf("could not set git email: %v", err)
 	}
@@ -141,8 +144,8 @@ func (m *nativeGitClient) Config(username string, email string) error {
 // with username/password credentials while supplying command output to the
 // caller.
 // nolint:unparam
-func (m *nativeGitClient) runCredentialedCmdWithOutput(args ...string) (string, error) {
-	closer, environ, err := m.creds.Environ()
+func (m *nativeGitClient) runCredentialedCmdWithOutput(ctx context.Context, args ...string) (string, error) {
+	closer, environ, err := m.creds.Environ(ctx)
 	if err != nil {
 		return "", err
 	}
@@ -158,34 +161,34 @@ func (m *nativeGitClient) runCredentialedCmdWithOutput(args ...string) (string,
 
 	cmd := exec.Command("git", args...)
 	cmd.Env = append(cmd.Env, environ...)
-	return m.runCmdOutput(cmd, runOpts{})
+	return m.runCmdOutput(ctx, cmd, runOpts{})
 }
 
-func (m *nativeGitClient) shallowFetch(revision string, depth int) error {
+func (m *nativeGitClient) shallowFetch(ctx context.Context, revision string, depth int) error {
 	var err error
 	if revision != "" {
-		err = m.runCredentialedCmd("fetch", "origin", revision, "--force", "--prune", "--depth", strconv.Itoa(depth))
+		err = m.runCredentialedCmd(ctx, "fetch", "origin", revision, "--force", "--prune", "--depth", strconv.Itoa(depth))
 	} else {
-		err = m.runCredentialedCmd("fetch", "origin", "--force", "--prune", "--depth", strconv.Itoa(depth))
+		err = m.runCredentialedCmd(ctx, "fetch", "origin", "--force", "--prune", "--depth", strconv.Itoa(depth))
 	}
 	return err
 }
 
-// Fetch fetches latest updates from origin
-func (m *nativeGitClient) ShallowFetch(revision string, depth int) error {
+// ShallowFetch fetches latest updates from origin
+func (m *nativeGitClient) ShallowFetch(ctx context.Context, revision string, depth int) error {
 	if m.OnFetch != nil {
 		done := m.OnFetch(m.repoURL)
 		defer done()
 	}
 
-	err := m.shallowFetch(revision, depth)
+	err := m.shallowFetch(ctx, revision, depth)
 
 	// When we have LFS support enabled, check for large files and fetch them too.
 	// No shallow fetch is possible here
 	if err == nil && m.IsLFSEnabled() {
-		largeFiles, err := m.LsLargeFiles()
+		largeFiles, err := m.LsLargeFiles(ctx)
 		if err == nil && len(largeFiles) > 0 {
-			err = m.runCredentialedCmd("lfs", "fetch", "--all")
+			err = m.runCredentialedCmd(ctx, "lfs", "fetch", "--all")
 			if err != nil {
 				return err
 			}
diff --git a/pkg/argocd/git.go b/pkg/argocd/git.go
index 3dedd7a..bc0dba8 100644
--- a/pkg/argocd/git.go
+++ b/pkg/argocd/git.go
@@ -186,7 +186,7 @@ func commitChangesGit(ctx context.Context, applicationImages *ApplicationImages,
 	} else {
 		gitC = wbc.GitClient
 	}
-	err = gitC.Init()
+	err = gitC.Init(ctx)
 	if err != nil {
 		return err
 	}
@@ -203,7 +203,7 @@ func commitChangesGit(ctx context.Context, applicationImages *ApplicationImages,
 	}
 	logCtx.Tracef("targetRevision for update is '%s'", checkOutBranch)
 	if checkOutBranch == "" || checkOutBranch == "HEAD" {
-		checkOutBranch, err = gitC.SymRefToBranch(checkOutBranch)
+		checkOutBranch, err = gitC.SymRefToBranch(ctx, checkOutBranch)
 		logCtx.Infof("resolved remote default branch to '%s' and using that for operations", checkOutBranch)
 		if err != nil {
 			return err
@@ -227,26 +227,26 @@ func commitChangesGit(ctx context.Context, applicationImages *ApplicationImages,
 	// If the pushBranch already exists in the remote origin, directly use it.
 	// Otherwise, create the new pushBranch from checkoutBranch
 	if checkOutBranch != pushBranch {
-		fetchErr := gitC.ShallowFetch(pushBranch, 1)
+		fetchErr := gitC.ShallowFetch(ctx, pushBranch, 1)
 		if fetchErr != nil {
-			err = gitC.ShallowFetch(checkOutBranch, 1)
+			err = gitC.ShallowFetch(ctx, checkOutBranch, 1)
 			if err != nil {
 				return err
 			}
 			logCtx.Debugf("Creating branch '%s' and using that for push operations", pushBranch)
-			err = gitC.Branch(checkOutBranch, pushBranch)
+			err = gitC.Branch(ctx, checkOutBranch, pushBranch)
 			if err != nil {
 				return err
 			}
 		}
 	} else {
-		err = gitC.ShallowFetch(checkOutBranch, 1)
+		err = gitC.ShallowFetch(ctx, checkOutBranch, 1)
 		if err != nil {
 			return err
 		}
 	}
 
-	err = gitC.Checkout(pushBranch, false)
+	err = gitC.Checkout(ctx, pushBranch, false)
 	if err != nil {
 		return err
 	}
@@ -276,7 +276,7 @@ func commitChangesGit(ctx context.Context, applicationImages *ApplicationImages,
 
 	// Set username and e-mail address used to identify the commiter
 	if wbc.GitCommitUser != "" && wbc.GitCommitEmail != "" {
-		err = gitC.Config(wbc.GitCommitUser, wbc.GitCommitEmail)
+		err = gitC.Config(ctx, wbc.GitCommitUser, wbc.GitCommitEmail)
 		if err != nil {
 			return err
 		}
@@ -289,11 +289,11 @@ func commitChangesGit(ctx context.Context, applicationImages *ApplicationImages,
 	commitOpts.SigningMethod = wbc.GitCommitSigningMethod
 	commitOpts.SignOff = wbc.GitCommitSignOff
 
-	err = gitC.Commit("", commitOpts)
+	err = gitC.Commit(ctx, "", commitOpts)
 	if err != nil {
 		return err
 	}
-	err = gitC.Push("origin", pushBranch, pushBranch != checkOutBranch)
+	err = gitC.Push(ctx, "origin", pushBranch, pushBranch != checkOutBranch)
 	if err != nil {
 		return err
 	}
@@ -352,7 +352,7 @@ func writeOverrides(ctx context.Context, applicationImages *ApplicationImages, g
 	}
 
 	if !targetExists {
-		err = gitC.Add(targetFile)
+		err = gitC.Add(ctx, targetFile)
 	}
 	return
 }



Test patch:
diff --git a/ext/git/client_test.go b/ext/git/client_test.go
index b9897de..569402c 100644
--- a/ext/git/client_test.go
+++ b/ext/git/client_test.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"os/exec"
@@ -36,33 +37,36 @@ func _createEmptyGitRepo() (string, error) {
 }
 
 func Test_nativeGitClient_Fetch(t *testing.T) {
+	ctx := context.Background()
 	tempDir, err := _createEmptyGitRepo()
 	require.NoError(t, err)
 
 	client, err := NewClient(fmt.Sprintf("file://%s", tempDir), NopCreds{}, true, false, "")
 	require.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	require.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 }
 
 func Test_nativeGitClient_Fetch_Prune(t *testing.T) {
+	ctx := context.Background()
+
 	tempDir, err := _createEmptyGitRepo()
 	require.NoError(t, err)
 
 	client, err := NewClient(fmt.Sprintf("file://%s", tempDir), NopCreds{}, true, false, "")
 	require.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	require.NoError(t, err)
 
 	err = runCmd(tempDir, "git", "branch", "test/foo")
 	require.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 
 	err = runCmd(tempDir, "git", "branch", "-d", "test/foo")
@@ -70,16 +74,18 @@ func Test_nativeGitClient_Fetch_Prune(t *testing.T) {
 	err = runCmd(tempDir, "git", "branch", "test/foo/bar")
 	require.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 }
 
 func Test_IsAnnotatedTag(t *testing.T) {
+	ctx := context.Background()
+
 	tempDir := t.TempDir()
 	client, err := NewClient(fmt.Sprintf("file://%s", tempDir), NopCreds{}, true, false, "")
 	require.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	require.NoError(t, err)
 
 	p := path.Join(client.Root(), "README")
@@ -96,16 +102,16 @@ func Test_IsAnnotatedTag(t *testing.T) {
 	err = runCmd(client.Root(), "git", "commit", "-m", "Initial commit", "-a")
 	require.NoError(t, err)
 
-	atag := client.IsAnnotatedTag("master")
+	atag := client.IsAnnotatedTag(ctx, "master")
 	assert.False(t, atag)
 
 	err = runCmd(client.Root(), "git", "tag", "some-tag", "-a", "-m", "Create annotated tag")
 	require.NoError(t, err)
-	atag = client.IsAnnotatedTag("some-tag")
+	atag = client.IsAnnotatedTag(ctx, "some-tag")
 	assert.True(t, atag)
 
 	// Tag effectually points to HEAD, so it's considered the same
-	atag = client.IsAnnotatedTag("HEAD")
+	atag = client.IsAnnotatedTag(ctx, "HEAD")
 	assert.True(t, atag)
 
 	err = runCmd(client.Root(), "git", "rm", "README")
@@ -114,17 +120,19 @@ func Test_IsAnnotatedTag(t *testing.T) {
 	assert.NoError(t, err)
 
 	// We moved on, so tag doesn't point to HEAD anymore
-	atag = client.IsAnnotatedTag("HEAD")
+	atag = client.IsAnnotatedTag(ctx, "HEAD")
 	assert.False(t, atag)
 }
 
 func Test_ChangedFiles(t *testing.T) {
+	ctx := context.Background()
+
 	tempDir := t.TempDir()
 
 	client, err := NewClientExt(fmt.Sprintf("file://%s", tempDir), tempDir, NopCreds{}, true, false, "")
 	require.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	require.NoError(t, err)
 
 	err = runCmd(client.Root(), "git", "commit", "-m", "Initial commit", "--allow-empty")
@@ -148,32 +156,34 @@ func Test_ChangedFiles(t *testing.T) {
 	err = runCmd(client.Root(), "git", "commit", "-m", "Changes", "-a")
 	require.NoError(t, err)
 
-	previousSHA, err := client.LsRemote("some-tag")
+	previousSHA, err := client.LsRemote(ctx, "some-tag")
 	require.NoError(t, err)
 
-	commitSHA, err := client.LsRemote("HEAD")
+	commitSHA, err := client.LsRemote(ctx, "HEAD")
 	require.NoError(t, err)
 
 	// Invalid commits, error
-	_, err = client.ChangedFiles("0000000000000000000000000000000000000000", "1111111111111111111111111111111111111111")
+	_, err = client.ChangedFiles(ctx, "0000000000000000000000000000000000000000", "1111111111111111111111111111111111111111")
 	require.Error(t, err)
 
 	// Not SHAs, error
-	_, err = client.ChangedFiles(previousSHA, "HEAD")
+	_, err = client.ChangedFiles(ctx, previousSHA, "HEAD")
 	require.Error(t, err)
 
 	// Same commit, no changes
-	changedFiles, err := client.ChangedFiles(commitSHA, commitSHA)
+	changedFiles, err := client.ChangedFiles(ctx, commitSHA, commitSHA)
 	require.NoError(t, err)
 	assert.ElementsMatch(t, []string{}, changedFiles)
 
 	// Different ref, with changes
-	changedFiles, err = client.ChangedFiles(previousSHA, commitSHA)
+	changedFiles, err = client.ChangedFiles(ctx, previousSHA, commitSHA)
 	require.NoError(t, err)
 	assert.ElementsMatch(t, []string{"README"}, changedFiles)
 }
 
 func Test_nativeGitClient_Submodule(t *testing.T) {
+	ctx := context.Background()
+
 	tempDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
@@ -212,17 +222,17 @@ func Test_nativeGitClient_Submodule(t *testing.T) {
 	client, err := NewClient(fmt.Sprintf("file://%s", foo), NopCreds{}, true, false, "")
 	require.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	require.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 
-	commitSHA, err := client.LsRemote("HEAD")
+	commitSHA, err := client.LsRemote(ctx, "HEAD")
 	assert.NoError(t, err)
 
 	// Call Checkout() with submoduleEnabled=false.
-	err = client.Checkout(commitSHA, false)
+	err = client.Checkout(ctx, commitSHA, false)
 	assert.NoError(t, err)
 
 	// Check if submodule url does not exist in .git/config
@@ -230,7 +240,7 @@ func Test_nativeGitClient_Submodule(t *testing.T) {
 	assert.Error(t, err)
 
 	// Call Submodule() via Checkout() with submoduleEnabled=true.
-	err = client.Checkout(commitSHA, true)
+	err = client.Checkout(ctx, commitSHA, true)
 	assert.NoError(t, err)
 
 	// Check if the .gitmodule URL is reflected in .git/config
@@ -245,7 +255,7 @@ func Test_nativeGitClient_Submodule(t *testing.T) {
 	require.NoError(t, err)
 
 	// Call Submodule()
-	err = client.Submodule()
+	err = client.Submodule(ctx)
 	assert.NoError(t, err)
 
 	// Check if the URL change in .gitmodule is reflected in .git/config
diff --git a/ext/git/creds_test.go b/ext/git/creds_test.go
index ea2e795..3f62561 100644
--- a/ext/git/creds_test.go
+++ b/ext/git/creds_test.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"encoding/base64"
 	"fmt"
 	"os"
@@ -42,9 +43,11 @@ func (s *memoryCredsStore) Remove(id string) {
 }
 
 func TestHTTPSCreds_Environ_no_cert_cleanup(t *testing.T) {
+	ctx := context.Background()
+
 	store := &memoryCredsStore{creds: make(map[string]cred)}
 	creds := NewHTTPSCreds("", "", "", "", true, "", store, false)
-	closer, env, err := creds.Environ()
+	closer, env, err := creds.Environ(ctx)
 	require.NoError(t, err)
 	var nonce string
 	for _, envVar := range env {
@@ -59,8 +62,10 @@ func TestHTTPSCreds_Environ_no_cert_cleanup(t *testing.T) {
 }
 
 func TestHTTPSCreds_Environ_insecure_true(t *testing.T) {
+	ctx := context.Background()
+
 	creds := NewHTTPSCreds("", "", "", "", true, "", &NoopCredsStore{}, false)
-	closer, env, err := creds.Environ()
+	closer, env, err := creds.Environ(ctx)
 	t.Cleanup(func() {
 		io.Close(closer)
 	})
@@ -76,8 +81,9 @@ func TestHTTPSCreds_Environ_insecure_true(t *testing.T) {
 }
 
 func TestHTTPSCreds_Environ_insecure_false(t *testing.T) {
+	ctx := context.Background()
 	creds := NewHTTPSCreds("", "", "", "", false, "", &NoopCredsStore{}, false)
-	closer, env, err := creds.Environ()
+	closer, env, err := creds.Environ(ctx)
 	t.Cleanup(func() {
 		io.Close(closer)
 	})
@@ -94,9 +100,10 @@ func TestHTTPSCreds_Environ_insecure_false(t *testing.T) {
 
 func TestHTTPSCreds_Environ_forceBasicAuth(t *testing.T) {
 	t.Run("Enabled and credentials set", func(t *testing.T) {
+		ctx := context.Background()
 		store := &memoryCredsStore{creds: make(map[string]cred)}
 		creds := NewHTTPSCreds("username", "password", "", "", false, "", store, true)
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		defer closer.Close()
 		var header string
@@ -112,9 +119,10 @@ func TestHTTPSCreds_Environ_forceBasicAuth(t *testing.T) {
 		assert.Equal(t, "Authorization: Basic "+b64enc, header)
 	})
 	t.Run("Enabled but credentials not set", func(t *testing.T) {
+		ctx := context.Background()
 		store := &memoryCredsStore{creds: make(map[string]cred)}
 		creds := NewHTTPSCreds("", "", "", "", false, "", store, true)
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		defer closer.Close()
 		var header string
@@ -129,9 +137,10 @@ func TestHTTPSCreds_Environ_forceBasicAuth(t *testing.T) {
 		assert.Empty(t, header)
 	})
 	t.Run("Disabled with credentials set", func(t *testing.T) {
+		ctx := context.Background()
 		store := &memoryCredsStore{creds: make(map[string]cred)}
 		creds := NewHTTPSCreds("username", "password", "", "", false, "", store, false)
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		defer closer.Close()
 		var header string
@@ -147,9 +156,10 @@ func TestHTTPSCreds_Environ_forceBasicAuth(t *testing.T) {
 	})
 
 	t.Run("Disabled with credentials not set", func(t *testing.T) {
+		ctx := context.Background()
 		store := &memoryCredsStore{creds: make(map[string]cred)}
 		creds := NewHTTPSCreds("", "", "", "", false, "", store, false)
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		defer closer.Close()
 		var header string
@@ -166,9 +176,11 @@ func TestHTTPSCreds_Environ_forceBasicAuth(t *testing.T) {
 }
 
 func TestHTTPSCreds_Environ_clientCert(t *testing.T) {
+	ctx := context.Background()
+
 	store := &memoryCredsStore{creds: make(map[string]cred)}
 	creds := NewHTTPSCreds("", "", "clientCertData", "clientCertKey", false, "", store, false)
-	closer, env, err := creds.Environ()
+	closer, env, err := creds.Environ(ctx)
 	require.NoError(t, err)
 	var cert, key string
 	for _, envVar := range env {
@@ -201,12 +213,14 @@ func TestHTTPSCreds_Environ_clientCert(t *testing.T) {
 
 func Test_SSHCreds_Environ(t *testing.T) {
 	for _, insecureIgnoreHostKey := range []bool{false, true} {
+		ctx := context.Background()
+
 		tempDir := t.TempDir()
 		caFile := path.Join(tempDir, "caFile")
 		err := os.WriteFile(caFile, []byte(""), os.FileMode(0600))
 		require.NoError(t, err)
 		creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "")
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		require.Len(t, env, 2)
 
@@ -234,12 +248,14 @@ func Test_SSHCreds_Environ(t *testing.T) {
 
 func Test_SSHCreds_Environ_WithProxy(t *testing.T) {
 	for _, insecureIgnoreHostKey := range []bool{false, true} {
+		ctx := context.Background()
+
 		tempDir := t.TempDir()
 		caFile := path.Join(tempDir, "caFile")
 		err := os.WriteFile(caFile, []byte(""), os.FileMode(0600))
 		require.NoError(t, err)
 		creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "socks5://127.0.0.1:1080")
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		require.Len(t, env, 2)
 
@@ -268,12 +284,14 @@ func Test_SSHCreds_Environ_WithProxy(t *testing.T) {
 
 func Test_SSHCreds_Environ_WithProxyUserNamePassword(t *testing.T) {
 	for _, insecureIgnoreHostKey := range []bool{false, true} {
+		ctx := context.Background()
+
 		tempDir := t.TempDir()
 		caFile := path.Join(tempDir, "caFile")
 		err := os.WriteFile(caFile, []byte(""), os.FileMode(0600))
 		require.NoError(t, err)
 		creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "socks5://user:password@127.0.0.1:1080")
-		closer, env, err := creds.Environ()
+		closer, env, err := creds.Environ(ctx)
 		require.NoError(t, err)
 		require.Len(t, env, 4)
 
@@ -327,6 +345,8 @@ func TestNewGoogleCloudCreds(t *testing.T) {
 }
 
 func TestNewGoogleCloudCreds_invalidJSON(t *testing.T) {
+	ctx := context.Background()
+
 	store := &memoryCredsStore{creds: make(map[string]cred)}
 	googleCloudCreds := NewGoogleCloudCreds(invalidJSON, store)
 	assert.Nil(t, googleCloudCreds.creds)
@@ -339,13 +359,15 @@ func TestNewGoogleCloudCreds_invalidJSON(t *testing.T) {
 	assert.Equal(t, "", username)
 	assert.NotNil(t, err)
 
-	closer, envStringSlice, err := googleCloudCreds.Environ()
+	closer, envStringSlice, err := googleCloudCreds.Environ(ctx)
 	assert.Equal(t, NopCloser{}, closer)
 	assert.Equal(t, []string(nil), envStringSlice)
 	assert.NotNil(t, err)
 }
 
 func TestGoogleCloudCreds_Environ_cleanup(t *testing.T) {
+	ctx := context.Background()
+
 	store := &memoryCredsStore{creds: make(map[string]cred)}
 	staticToken := &oauth2.Token{AccessToken: "token"}
 	googleCloudCreds := GoogleCloudCreds{&google.Credentials{
@@ -354,7 +376,7 @@ func TestGoogleCloudCreds_Environ_cleanup(t *testing.T) {
 		JSON:        []byte(gcpServiceAccountKeyJSON),
 	}, store}
 
-	closer, env, err := googleCloudCreds.Environ()
+	closer, env, err := googleCloudCreds.Environ(ctx)
 	assert.NoError(t, err)
 	var nonce string
 	for _, envVar := range env {
diff --git a/ext/git/git_test.go b/ext/git/git_test.go
index deb7ce5..f15b101 100644
--- a/ext/git/git_test.go
+++ b/ext/git/git_test.go
@@ -1,6 +1,7 @@
 package git
 
 import (
+	"context"
 	"fmt"
 	"io"
 	"net/http"
@@ -118,6 +119,8 @@ func TestSameURL(t *testing.T) {
 }
 
 func TestCustomHTTPClient(t *testing.T) {
+	ctx := context.Background()
+
 	certFile, err := filepath.Abs("../../test/fixture/certs/argocd-test-client.crt")
 	assert.NoError(t, err)
 	assert.NotEqual(t, "", certFile)
@@ -136,7 +139,7 @@ func TestCustomHTTPClient(t *testing.T) {
 
 	// Get HTTPSCreds with client cert creds specified, and insecure connection
 	creds := NewHTTPSCreds("test", "test", string(certData), string(keyData), false, "http://proxy:5000", &NoopCredsStore{}, false)
-	client := GetRepoHTTPClient("https://localhost:9443/foo/bar", false, creds, "http://proxy:5000")
+	client := GetRepoHTTPClient(ctx, "https://localhost:9443/foo/bar", false, creds, "http://proxy:5000")
 	assert.NotNil(t, client)
 	assert.NotNil(t, client.Transport)
 	if client.Transport != nil {
@@ -164,7 +167,7 @@ func TestCustomHTTPClient(t *testing.T) {
 
 	// Get HTTPSCreds without client cert creds, but insecure connection
 	creds = NewHTTPSCreds("test", "test", "", "", true, "", &NoopCredsStore{}, false)
-	client = GetRepoHTTPClient("https://localhost:9443/foo/bar", true, creds, "")
+	client = GetRepoHTTPClient(ctx, "https://localhost:9443/foo/bar", true, creds, "")
 	assert.NotNil(t, client)
 	assert.NotNil(t, client.Transport)
 	if client.Transport != nil {
@@ -197,7 +200,7 @@ func TestCustomHTTPClient(t *testing.T) {
 	err = os.WriteFile(filepath.Join(temppath, "127.0.0.1"), cert, 0666)
 	assert.NoError(t, err)
 	t.Setenv(common.EnvVarTLSDataPath, temppath)
-	client = GetRepoHTTPClient("https://127.0.0.1", false, creds, "")
+	client = GetRepoHTTPClient(ctx, "https://127.0.0.1", false, creds, "")
 	assert.NotNil(t, client)
 	assert.NotNil(t, client.Transport)
 	if client.Transport != nil {
@@ -210,6 +213,8 @@ func TestCustomHTTPClient(t *testing.T) {
 }
 
 func TestLsRemote(t *testing.T) {
+	ctx := context.Background()
+
 	clnt, err := NewClientExt("https://github.com/argoproj/argo-cd.git", "/tmp", NopCreds{}, false, false, "")
 	assert.NoError(t, err)
 	xpass := []string{
@@ -221,13 +226,13 @@ func TestLsRemote(t *testing.T) {
 		//"4e22a3c",
 	}
 	for _, revision := range xpass {
-		commitSHA, err := clnt.LsRemote(revision)
+		commitSHA, err := clnt.LsRemote(ctx, revision)
 		assert.NoError(t, err)
 		assert.True(t, IsCommitSHA(commitSHA))
 	}
 
 	// We do not resolve truncated git hashes and return the commit as-is if it appears to be a commit
-	commitSHA, err := clnt.LsRemote("4e22a3c")
+	commitSHA, err := clnt.LsRemote(ctx, "4e22a3c")
 	assert.NoError(t, err)
 	assert.False(t, IsCommitSHA(commitSHA))
 	assert.True(t, IsTruncatedCommitSHA(commitSHA))
@@ -237,7 +242,7 @@ func TestLsRemote(t *testing.T) {
 		"4e22a3", // too short (6 characters)
 	}
 	for _, revision := range xfail {
-		_, err := clnt.LsRemote(revision)
+		_, err := clnt.LsRemote(ctx, revision)
 		assert.Error(t, err)
 	}
 }
@@ -254,20 +259,21 @@ func TestLFSClient(t *testing.T) {
 	client, err := NewClientExt("https://github.com/argoproj-labs/argocd-testrepo-lfs", tempDir, NopCreds{}, false, true, "")
 	assert.NoError(t, err)
 
-	commitSHA, err := client.LsRemote("HEAD")
+	ctx := context.Background()
+	commitSHA, err := client.LsRemote(ctx, "HEAD")
 	assert.NoError(t, err)
 	assert.NotEqual(t, "", commitSHA)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	assert.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 
-	err = client.Checkout(commitSHA, true)
+	err = client.Checkout(ctx, commitSHA, true)
 	assert.NoError(t, err)
 
-	largeFiles, err := client.LsLargeFiles()
+	largeFiles, err := client.LsLargeFiles(ctx)
 	assert.NoError(t, err)
 	assert.Equal(t, 3, len(largeFiles))
 
@@ -288,27 +294,29 @@ func TestLFSClient(t *testing.T) {
 }
 
 func TestVerifyCommitSignature(t *testing.T) {
+	ctx := context.Background()
+
 	p := t.TempDir()
 
 	client, err := NewClientExt("https://github.com/argoproj/argo-cd.git", p, NopCreds{}, false, false, "")
 	assert.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	assert.NoError(t, err)
 
-	err = client.Fetch("")
+	err = client.Fetch(ctx, "")
 	assert.NoError(t, err)
 
-	commitSHA, err := client.LsRemote("HEAD")
+	commitSHA, err := client.LsRemote(ctx, "HEAD")
 	assert.NoError(t, err)
 
-	err = client.Checkout(commitSHA, true)
+	err = client.Checkout(ctx, commitSHA, true)
 	assert.NoError(t, err)
 
 	// 28027897aad1262662096745f2ce2d4c74d02b7f is a commit that is signed in the repo
 	// It doesn't matter whether we know the key or not at this stage
 	{
-		out, err := client.VerifyCommitSignature("28027897aad1262662096745f2ce2d4c74d02b7f")
+		out, err := client.VerifyCommitSignature(ctx, "28027897aad1262662096745f2ce2d4c74d02b7f")
 		assert.NoError(t, err)
 		assert.NotEmpty(t, out)
 		assert.Contains(t, out, "gpg: Signature made")
@@ -316,28 +324,29 @@ func TestVerifyCommitSignature(t *testing.T) {
 
 	// 85d660f0b967960becce3d49bd51c678ba2a5d24 is a commit that is not signed
 	{
-		out, err := client.VerifyCommitSignature("85d660f0b967960becce3d49bd51c678ba2a5d24")
+		out, err := client.VerifyCommitSignature(ctx, "85d660f0b967960becce3d49bd51c678ba2a5d24")
 		assert.NoError(t, err)
 		assert.Empty(t, out)
 	}
 }
 
 func TestVerifyShallowFetchCheckout(t *testing.T) {
+	ctx := context.Background()
 	p := t.TempDir()
 
 	client, err := NewClientExt("https://github.com/argoproj/argo-cd.git", p, NopCreds{}, false, false, "")
 	assert.NoError(t, err)
 
-	err = client.Init()
+	err = client.Init(ctx)
 	assert.NoError(t, err)
 
-	err = client.ShallowFetch("HEAD", 1)
+	err = client.ShallowFetch(ctx, "HEAD", 1)
 	assert.NoError(t, err)
 
-	commitSHA, err := client.LsRemote("HEAD")
+	commitSHA, err := client.LsRemote(ctx, "HEAD")
 	assert.NoError(t, err)
 
-	err = client.Checkout(commitSHA, true)
+	err = client.Checkout(ctx, commitSHA, true)
 	assert.NoError(t, err)
 }
 
@@ -357,6 +366,7 @@ func TestNewFactory(t *testing.T) {
 		{"GitHub", args{url: "https://github.com/argoproj/argocd-example-apps"}},
 	}
 	for _, tt := range tests {
+		ctx := context.Background()
 
 		if tt.name == "PrivateSSHRepo" {
 			test.Flaky(t)
@@ -366,23 +376,23 @@ func TestNewFactory(t *testing.T) {
 
 		client, err := NewClientExt(tt.args.url, dirName, NopCreds{}, tt.args.insecureIgnoreHostKey, false, "")
 		assert.NoError(t, err)
-		commitSHA, err := client.LsRemote("HEAD")
+		commitSHA, err := client.LsRemote(ctx, "HEAD")
 		assert.NoError(t, err)
 
-		err = client.Init()
+		err = client.Init(ctx)
 		assert.NoError(t, err)
 
-		err = client.Fetch("")
+		err = client.Fetch(ctx, "")
 		assert.NoError(t, err)
 
 		// Do a second fetch to make sure we can treat `already up-to-date` error as not an error
-		err = client.Fetch("")
+		err = client.Fetch(ctx, "")
 		assert.NoError(t, err)
 
-		err = client.Checkout(commitSHA, true)
+		err = client.Checkout(ctx, commitSHA, true)
 		assert.NoError(t, err)
 
-		revisionMetadata, err := client.RevisionMetadata(commitSHA)
+		revisionMetadata, err := client.RevisionMetadata(ctx, commitSHA)
 		assert.NoError(t, err)
 		assert.NotNil(t, revisionMetadata)
 		assert.Regexp(t, "^.*<.*>$", revisionMetadata.Author)
@@ -390,7 +400,7 @@ func TestNewFactory(t *testing.T) {
 		assert.NotEmpty(t, revisionMetadata.Date)
 		assert.NotEmpty(t, revisionMetadata.Message)
 
-		commitSHA2, err := client.CommitSHA()
+		commitSHA2, err := client.CommitSHA(ctx)
 		assert.NoError(t, err)
 
 		assert.Equal(t, commitSHA, commitSHA2)
@@ -398,13 +408,15 @@ func TestNewFactory(t *testing.T) {
 }
 
 func TestListRevisions(t *testing.T) {
+	ctx := context.Background()
+
 	dir := t.TempDir()
 
 	repoURL := "https://github.com/argoproj/argo-cd.git"
 	client, err := NewClientExt(repoURL, dir, NopCreds{}, false, false, "")
 	assert.NoError(t, err)
 
-	lsResult, err := client.LsRefs()
+	lsResult, err := client.LsRefs(ctx)
 	assert.NoError(t, err)
 
 	testBranch := "master"
@@ -417,6 +429,8 @@ func TestListRevisions(t *testing.T) {
 }
 
 func TestLsFiles(t *testing.T) {
+	ctx := context.Background()
+
 	tmpDir1 := t.TempDir()
 	tmpDir2 := t.TempDir()
 
@@ -450,19 +464,19 @@ func TestLsFiles(t *testing.T) {
 
 	// Old and default globbing
 	expectedResult := []string{"a.yaml", "link.yaml", "subdir/b.yaml"}
-	lsResult, err := client.LsFiles("*.yaml", false)
+	lsResult, err := client.LsFiles(ctx, "*.yaml", false)
 	assert.NoError(t, err)
 	assert.Equal(t, lsResult, expectedResult)
 
 	// New and safer globbing, do not return symlinks resolving outside of the repo
 	expectedResult = []string{"a.yaml"}
-	lsResult, err = client.LsFiles("*.yaml", true)
+	lsResult, err = client.LsFiles(ctx, "*.yaml", true)
 	assert.NoError(t, err)
 	assert.Equal(t, lsResult, expectedResult)
 
 	// New globbing, do not return files outside of the repo
 	var nilResult []string
-	lsResult, err = client.LsFiles(filepath.Join(tmpDir2, "*.yaml"), true)
+	lsResult, err = client.LsFiles(ctx, filepath.Join(tmpDir2, "*.yaml"), true)
 	assert.NoError(t, err)
 	assert.Equal(t, lsResult, nilResult)
 }