Thanks to visit codestin.com
Credit goes to github.com

Skip to content

repository: adopt variadic options pattern for Init and PlainInit #1462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: v6-transport
Choose a base branch
from

Conversation

davidalpert
Copy link

This PR refactors the options for the Repository Init and PlainInit methods to accept some variadic style options in the same style as the recently refactored packfile.Parser.

This refactoring for the repository factory functions paves the way for additional options to opt-in to legacy v5 configuration handlings (see #395 and the initial work in #1019)

I am looking for feedback to confirm that this syntax and semantics are going in an aligned direction. Specifically I ran into the similarity between Init and PlainInit args and the fact that Golang does not support two functions named the same of different types (e.g. WithDefaultBranch might become WithPlainInitDefaultBranch but that seems to add no value) so I compromised and introduced a WithInitOptions helper that allows passing initOption helpers into the plainInitOption's inner initOptions

A different approach would be to collapse all the init options into a single struct and remove PlainInit, replacing it with Init and the options that configure a bare repo.

@pjbgf I am looking for some confirmation or direction on this set of changes before I push forward to address the rest of #395

Copy link
Member

@pjbgf pjbgf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidalpert thank you for putting this together. I added a few comments, PTAL.

We may have some additional challenges when expanding the variadic options to Clone, to keep the API simple and avoid the name collision on the With funcs.

options.go Outdated
Comment on lines 794 to 798
type plainInitOptions struct {
initOptions []InitOption

bare bool
objectFormat formatcfg.ObjectFormat
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A different approach would be to collapse all the init options into a single struct and remove PlainInit, replacing it with Init and the options that configure a bare repo.

I like this idea for the long-term. But I think I'd keep PlainInit largely as-is and without additional options for v6. So we abstracted away the complexity from the user by calling Init with sensible defaults. This should provide an easier transition for users using PlainInit in v5.

Potentially we could mark it as deprecated, to be removed at v7. But this would depend on what the API would look like across all the Plain funcs.

Copy link
Author

@davidalpert davidalpert Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in 2407eb47; if approved I can rebase and squash into a single commit.

repository.go Outdated
func InitWithOptions(s storage.Storer, worktree billy.Filesystem, options InitOptions) (*Repository, error) {
if err := initStorer(s); err != nil {
return nil, err
func InitWithOptions(s storage.Storer, worktree billy.Filesystem, opts ...InitOption) (*Repository, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the InitWithOptions func. From the Init func I'd remove the worktree arg (which is optional) and make it part of the variadic options:

func Init(s storage.Storer, opts ...InitOption) (*Repository, error)

This way, an init call with a given storer would look like:

git.Init(storer)

And more advanced options:

git.Init(storer, 
    git.WithWorkTree(fs),
    git.WithObjectFormat(f))

Which would remove the need to pass on nil to an optional arg.

Copy link
Author

@davidalpert davidalpert Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in 2407eb47; if approved I can rebase and squash into a single commit.

@pjbgf pjbgf added this to the v6.0.0 milestone Mar 20, 2025
@davidalpert davidalpert force-pushed the 395-v6-repository-options branch from ef4c87e to 2407eb4 Compare April 16, 2025 21:46
@davidalpert davidalpert requested a review from pjbgf April 16, 2025 21:47
@pjbgf pjbgf added the breaking label Apr 18, 2025
Copy link
Member

@pjbgf pjbgf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidalpert overall LGTM.

One additional change needed is to replace the PlainInitWithOptions from _examples/sha256.

Please squash your commits and rebase (and retarget the PR) against v6-transport branch instead? We already bumped the API version on that branch to v6 so we would be able to merge this right away.

repository.go Outdated
Comment on lines 110 to 116
// WithBare is for backwards compatibility and is the opposite of WithWorkTree; a bare repo sets the worktree to nil.
func WithBare() InitOption {
return func(o *initOptions) {
o.workTree = nil
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the idea behind having something for users to relate to. But it feels largely redundant.

Suggested change
// WithBare is for backwards compatibility and is the opposite of WithWorkTree; a bare repo sets the worktree to nil.
func WithBare() InitOption {
return func(o *initOptions) {
o.workTree = nil
}
}

repository.go Outdated
Comment on lines 103 to 109
// WithWorkTree sets the internal worktree for the new repo.
func WithWorkTree(worktree billy.Filesystem) InitOption {
return func(o *initOptions) {
o.workTree = worktree
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WithWorkTree sets the internal worktree for the new repo.
func WithWorkTree(worktree billy.Filesystem) InitOption {
return func(o *initOptions) {
o.workTree = worktree
}
}
// WithWorkTree sets the worktree filesystem for the repo. If not used, or a `nil` is
// passed as argument, will result in a bare repository.
func WithWorkTree(worktree billy.Filesystem) InitOption {
return func(o *initOptions) {
o.workTree = worktree
}
}

Copy link
Author

@davidalpert davidalpert Apr 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove WithBare(..) and incorporate this comment update in my rebased PR.

given the updated comments on WithWorkTree(..) what is the significance of keeping the isBare argument in

func PlainInit(path string, isBare bool, options ...InitOption) (*Repository, error) {
   ...
}

perhaps it makes sense to remove isBare bool there and leave the signature as

func PlainInit(path string, options ...InitOption) (*Repository, error) {
   ...
}

so that there is one consistent syntax for a repository as both Init and PlainInit default to a bare repo unless a worktree is passed using WithWorkTree(...)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, tests are failing for me locally on the v6-transport branch before I rebase my changes...

❯ make test
running against git version 2.35.1
...
--- FAIL: TestProxyEnvSuite (0.35s)
    --- FAIL: TestProxyEnvSuite/TestCommand (0.34s)
        testing.go:1399: race detected during execution of test
FAIL
FAIL	github.com/go-git/go-git/v6/internal/transport/ssh/test	2.317s
...

repository.go Outdated
}
}

// WithObjectFormat sets the object format when invoking PlainInitWithOptions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WithObjectFormat sets the object format when invoking PlainInitWithOptions.
// WithObjectFormat sets the repository's object format.

Comment on lines +80 to +94
type initOptions struct {
defaultBranch plumbing.ReferenceName
workTree billy.Filesystem
objectFormat formatcfg.ObjectFormat
}

func newInitOptions() initOptions {
return initOptions{
defaultBranch: plumbing.Master,
workTree: nil,
objectFormat: "",
}
}

type InitOption func(*initOptions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purposes of this PR, we can leave this as-is. However, as we expand other parts of the code we may need to amend this so that we can enable the reuse of the same With<Option> across different use cases (e.g. Init, Clone, etc), without having to prefix them.

Let's leave this comment open for future reference.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same thought here, looking ahead to the possibility of future collisions, especially after initially running into them between Init and PlainInit.

One possibility that comes to mind is establishing a policy that all With<Option> functions need to be in a scoped package which helps guide clients into using the right option set for the package, e.g. repo.WithWorkTree(...) rather than git.WithWorkTree(...)

Copy link
Author

@davidalpert davidalpert Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The --bare option is one that may collide, for example, as both git init --bare and git clone --bare are supported by the CLI; although both could be under a common "repo options" it may make more sense to support init options and clone options independently and simply repeat shared options with consistent semantics (e.g. init.WithWorkTree(...) and clone.WithWorkTree(...))

@davidalpert davidalpert force-pushed the 395-v6-repository-options branch from 2407eb4 to 5ed5b8b Compare April 22, 2025 18:02
@davidalpert davidalpert changed the base branch from main to v6-transport April 22, 2025 18:02
@davidalpert
Copy link
Author

davidalpert commented Apr 22, 2025

  • incorporated last round of feedback
  • squashed into a single commit
  • rebased onto v6-transport
  • force-pushed to this branch
  • retargeted this PR against the v6-transport branch

@davidalpert davidalpert requested a review from pjbgf April 23, 2025 15:38
this commit removes InitWithOptions by collapsing it back into
Init(storage, opt...)

NOTE: this is a breaking change for the syntax of calling
      Init as the type of the second option has changed
      and instead of calling Init(storage, worktree) we
      now call Init(storage, WithWorkTree(worktree))
@davidalpert davidalpert force-pushed the 395-v6-repository-options branch from 5ed5b8b to 256f784 Compare April 30, 2025 17:24
@davidalpert
Copy link
Author

rebased again on top of upstream/v6-transport

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants