Simplify client structure initializations#6254
Merged
Merged
Conversation
In commit d101bdb of PR git-lfs#3244 we extracted the portions of our "lfsapi" package specifically related to HTTP request handling into a new package named "lfshttp". As part of that process, we moved some of the initialization steps formerly performed by the NewClient() function of our "lfsapi" package into a separate NewClient() function in the "lfshttp" package. Both NewClient() functions return an "error" type as their second return value, and at the time of PR git-lfs#3244, the NewClient() function in the "lfsapi" package could encounter an error condition and return a non-nil "error" value. However, none of the initialization steps that we moved to the NewClient() function of the "lfshttp" package could encounter an error condition, so there was no specific need for the function to continue to return an "error" value. As this remains the case, we can simplify the NewClient() function in our "lfshttp" package by just eliminating its "error" return value. We then update all the callers of this function, including those in our Go test functions, as they no longer need to check for an "error" return value from the function.
In PR git-lfs#1839 we first developed our "lfsapi" package, and in commit 31f180b of that PR we introduced the package's NewClient() function to initialize and return a Client structure. At the time, the NewClient() function invoked the ParseNetrc() function, which was located in the same package. As this function parsed a user's "netrc" file, it could encounter error conditions, and so it might return a non-nil "error" value. The NewClient() function checked for this possibility, and in the case of an error, would itself return a non-nil "error" value. However, in commit 1026ff0 of PR git-lfs#3307 we moved the ParseNetrc() function into our "creds" package, and added the netrcCredentialHelper structure in that package. In the same commit we also refactored our handling of "netrc" files so that we now parsed them when we retrieve credentials for an HTTP request, rather than when we initialized a new Client structure in our "lfsapi" package. As a result, none of the remaining initialization steps in the NewClient() function of the "lfsapi" package could encounter an error condition, and so there was no specific need for the function to continue to return an "error" value. As this remains the case, we can simplify the NewClient() function in our "lfsapi" package by just eliminating its "error" return value. We then update all the callers of this function, including those in our Go test functions, as they no longer need to check for an "error" return value from the function.
In PR git-lfs#1769 we first developed our "locking" package, and in commit 4910706 of that PR we introduced the package's NewClient() function to initialize and return a Client structure. At the conclusion of PR git-lfs#1769, the NewClient() function invoked both the NewLockCache() function, which was also located in the "locking" package, and the MkdirAll() function from the "os" package of the Go standard library. The NewClient() function called these functions in order to create the "lockcache.db" file we store in the ".git/lfs" directory. Both the NewLockCache() and MkdirAll() functions could return error conditions, and so might return non-nil "error" values. The NewClient() function checked for these possibilities, and in the case of an error, would itself return a non-nil "error" value. However, in commit a998543 of PR git-lfs#1839 we revised the NewClient() function so that it did not create a lock cache file. Instead, this became the responsibility of a new Client structure method named SetupFileCache(). We also added a function to our "commands" package which first calls the "locking" package's NewClient() function, and then invokes the SetupFileCache() method on the newly initialized Client structure. As a result, none of the remaining initialization steps in the NewClient() function of the "locking" package could encounter an error condition, and so there was no specific need for the function to continue to return an "error" value. As this remains the case, we can simplify the NewClient() function in our "locking" package by just eliminating its "error" return value. We then update all the callers of this function, including those in our Go test functions, as they no longer need to check for an "error" return value from the function.
This comment was marked as off-topic.
This comment was marked as off-topic.
larsxschneider
approved these changes
Apr 30, 2026
larsxschneider
left a comment
Member
There was a problem hiding this comment.
A nice cleanup! Thank you 🙇
(Unless we use it shortly, I would remove the unused Shutdown() method before merging)
As pointed out by larsxschneider on PR review, we inadvertently included a Shutdown() method for the concreteManifest structure in our "tq" package before adding any related functionality. We expect to make use of such a method in a future PR to address the issue reported in git-lfs#6118, but in the context of the current PR this method is unnecessary and so we just remove it for the present.
As suggested by larsxschneider on PR review, we clarify the purpose of the sshAuthClient structure in our "lfshttp" package by adding a comment to describe its use, which is to execute the "git-lfs-authenticate" command over SSH in order to fetch HTTP credentials for the Git LFS Batch API. Co-authored-by: Lars Schneider <larsxschneider@github.com>
chrisd8088
added a commit
that referenced
this pull request
May 21, 2026
In previous commits in this PR, we revised the Git LFS client such that it now always performs a consistent set of cleanup activities when exiting, regardless of the circumstances. In particular, the Cleanup() function in our "commands" package should always be executed before the client halts, and one of the steps this function now takes is to invoke the closeAPIClient() function in the "commands" package. The closeAPIClient() function checks if the "apiClient" global variable has been instantiated. If it has, then it points to a Client structure from our "lfsapi" package, and the closeAPIClient() function calls that structure's Close() method to release any resources associated with the structure. In addition, we updated several other packages in our main Git LFS client program and its Go test functions so that after a Client structure from the "lfsapi" package is instantiated, its Close() method will always be invoked when the structure is no longer in use. For consistency, we now update the three other programs in our project which instantiate Client structures from the "lfsapi" package so that they also always call the Close() method on these structures at the end of their lifetimes. Note that in the case of the "t/git-lfs-test-server-api" program, we also revise the buildManifest() function as it no longer needs to return an "error" value, but does now need to return the Client structure it creates. In commit d40d1b7 of PR #6254 we altered the NewClient() function in the "lfsapi" package so that it does not return an "error" value. At that time we could also have simplified the buildManifest() function in the "t/git-lfs-test-server-api" program to not return an "error" value, as it previously did so only to report any error condition returned by the NewClient() function of the "lfsapi" package. However, we overlooked this potential simplification in PR #6254, so we make it now instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR simplifies all of the factory functions we use to construct new API, HTTP, and locking clients by removing their unused
errorreturn values.For historical reasons, the
NewClient()functions in ourlfsapi,lfshttp, andlockingpackages all return a value with theerrortype, but at present none of the functions could ever actually encounter an error condition and return a non-nilerrorvalue. We can therefore just eliminate these unused return values.This PR will be most easily reviewed on a commit-by-commit basis.
Avoiding Future Deadlocks
One specific advantage of this change is that the
getAPIClient()function in ourcommandspackage will no longer need to include a conditional block which checks theerrorreturn value from thelfsapi.NewClient()constructor function. This block handles the (hypothetical) case of a non-nilerrorreturn value by calling theExitWithError()function, which causes the Git LFS client to exit immediately.In a future PR, we may revise the
ExitWithError()function so that it performs various cleanup operations prior to callingos.Exit()function, but only after first acquiring the sameglobalmutex that thegetAPIClient()function also acquires. With this goal in mind, we need to ensure that thegetAPIClient()function does not invoke theExitWithError()function, since that would result in a deadlock condition.