diff --git a/ext/git/client.go b/ext/git/client.go index ac9dc105..edd89060 100644 --- a/ext/git/client.go +++ b/ext/git/client.go @@ -65,6 +65,7 @@ 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) @@ -384,6 +385,40 @@ func (m *nativeGitClient) Fetch(revision string) error { return err } +func (m *nativeGitClient) shallowFetch(revision string, depth int) error { + var err error + if revision != "" { + err = m.runCredentialedCmd("fetch", "origin", revision, "--force", "--prune", "--depth", strconv.Itoa(depth)) + } else { + err = m.runCredentialedCmd("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 { + if m.OnFetch != nil { + done := m.OnFetch(m.repoURL) + defer done() + } + + err := m.shallowFetch(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() + if err == nil && len(largeFiles) > 0 { + err = m.runCredentialedCmd("lfs", "fetch", "--all") + if err != nil { + return err + } + } + } + + return err +} + // LsFiles lists the local working tree, including only files that are under source control func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) { if enableNewGitFileGlobbing { diff --git a/ext/git/git_test.go b/ext/git/git_test.go index 0eebe354..508ecf8b 100644 --- a/ext/git/git_test.go +++ b/ext/git/git_test.go @@ -322,6 +322,25 @@ func TestVerifyCommitSignature(t *testing.T) { } } +func TestVerifyShallowFetchCheckout(t *testing.T) { + p := t.TempDir() + + client, err := NewClientExt("https://github.com/argoproj/argo-cd.git", p, NopCreds{}, false, false, "") + assert.NoError(t, err) + + err = client.Init() + assert.NoError(t, err) + + err = client.ShallowFetch("HEAD", 1) + assert.NoError(t, err) + + commitSHA, err := client.LsRemote("HEAD") + assert.NoError(t, err) + + err = client.Checkout(commitSHA, true) + assert.NoError(t, err) +} + func TestNewFactory(t *testing.T) { addBinDirToPath := path.NewBinDirToPath() defer addBinDirToPath.Close() diff --git a/ext/git/mocks/Client.go b/ext/git/mocks/Client.go index 87bd3b46..ffe2b91b 100644 --- a/ext/git/mocks/Client.go +++ b/ext/git/mocks/Client.go @@ -192,6 +192,24 @@ func (_m *Client) Fetch(revision string) error { return r0 } +// Fetch provides a mock function with given fields: revision +func (_m *Client) ShallowFetch(revision string, depth int) error { + ret := _m.Called(revision) + + if len(ret) == 0 { + panic("no return value specified for Fetch") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, int) error); ok { + r0 = rf(revision, depth) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Init provides a mock function with given fields: func (_m *Client) Init() error { ret := _m.Called() diff --git a/pkg/argocd/git.go b/pkg/argocd/git.go index f9847908..b2cd8991 100644 --- a/pkg/argocd/git.go +++ b/pkg/argocd/git.go @@ -157,10 +157,6 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis if err != nil { return err } - err = gitC.Fetch("") - if err != nil { - return err - } // Set username and e-mail address used to identify the commiter if wbc.GitCommitUser != "" && wbc.GitCommitEmail != "" { @@ -186,6 +182,10 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis return err } } + err = gitC.ShallowFetch(checkOutBranch, 1) + if err != nil { + return err + } // The push branch is by default the same as the checkout branch, unless // specified after a : separator git-branch annotation, in which case a