Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

remote: add Push #178

Merged
merged 3 commits into from
Dec 19, 2016
Merged

remote: add Push #178

merged 3 commits into from
Dec 19, 2016

Conversation

smola
Copy link
Collaborator

@smola smola commented Dec 12, 2016

  • add Push method to Remote.
  • add method Push to Repository.
  • examples: add push example.

@codecov-io
Copy link

codecov-io commented Dec 12, 2016

Current coverage is 76.96% (diff: 70.88%)

Merging #178 into master will decrease coverage by 0.88%

@@             master       #178   diff @@
==========================================
  Files            92         92          
  Lines          5793       5940   +147   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           4510       4572    +62   
- Misses          810        882    +72   
- Partials        473        486    +13   

Powered by Codecov. Last update ff449c6...1bdce69

)

func main() {
if len(os.Args) != 4 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I created a helper function for the args parse:

CheckArgs("<directory>", "<remote-url>", "<refspec>")
directory := os.Args[1]
remoteUrl := os.Args[2]

}

repo, err := git.NewFilesystemRepository(repoPath)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

The err are checked using CheckIfError(err)

panic(err)
}

if err := repo.Push(&git.PushOptions{
Copy link
Contributor

Choose a reason for hiding this comment

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

And is supposed to illustrate the code with his homologue at git
Info("git clone %s %s", url, directory)


// Remote represents a connection to a remote repository
type Remote struct {
c *config.RemoteConfig
r *Repository
Copy link
Contributor

Choose a reason for hiding this comment

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

if you add the Repository then remove the Storer

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it will not be present in the next version (after rebase).

// Connect with the endpoint
func (r *Remote) Connect() error {
// ConnectFetch connects to the remote and starts a fetch session.
func (r *Remote) ConnectFetch() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

make private this methods

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

they are gone after the next rebase

return fmt.Errorf("no refspec given")
}

if err := o.Validate(); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

the validation should be the first thing, doesn't worth to make any operation if the o are not valid

return err
}

if err := iter.ForEach(func(ref *plumbing.Reference) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer not having the if and the ForEach with the closure in the same line

Copy link
Contributor

Choose a reason for hiding this comment

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

I find hard to understand at a glance what operation are we doing on each element in the collection.

Can we define the function separately, give it a good name, and call it here instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

@@ -318,10 +511,19 @@ func (r *Remote) References() (storer.ReferenceIter, error) {
return r.refs.IterReferences()
}

// Disconnect from the remote and save the config
// Disconnect from the remote server. Calling Disconnect on a disconnected
// remote has no effect.
func (r *Remote) Disconnect() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

make it private

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not until we make Fetch atomic, which currently it is not.

}

// Validate validate the fields and set the default values
func (o *PushOptions) Validate() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to have invalid PushOptions values around in our program?, if not, I would make PushOptions fields private, provide a ctor for it (that checks for validity) and add some getters (if they are needed).

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is Validate not used in the example?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See the above comment, I'm using the same conventions for Validate as in the rest of the code base. The example doesn't use Validate, the user doesn't need to call it, since it's always called by porcelain methods when they get options.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

panic(err)
}

if _, err := repo.CreateRemote(&config.RemoteConfig{
Copy link
Contributor

Choose a reason for hiding this comment

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

I find this confusing: Why pushing to a remote repository creates a remote in the current repository?

Should this be a different (an optional) operation from pushing?, it is a nasty side effect.

In other words, can we push to a repository that is not a remote? why not?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, I'm changing the example to do a more standard/intuitive thing.

// PushOptions describe how a push should be performed.
type PushOptions struct {
// RemoteName is the name of the remote to be pushed to.
RemoteName string
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a URL, not a remote, I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

git-push supports both, either getting a remote name or getting a URL directly (i.e. push to a repository without adding a remote). However, at the moment, we implent only pull/push by remote name.

Adding support for direct URL would be good (for clone/pull/push/fetch), but it seems work for a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

s Storer
p sideband.Progress

// cache fields, there during the connection is open
endpoint transport.Endpoint
client transport.Client
fetchSession transport.FetchPackSession
sendSession transport.SendPackSession
session transport.Session
Copy link
Contributor

Choose a reason for hiding this comment

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

can you explain the difference between session and the other two (sendSession and fetchSession)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

session can be either fetchSession / sendSession. It's used for some common operations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This will go away if we merge #185 first.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

// TODO: Support pushing tags.
// TODO: Check if force update is given, otherwise reject non-fast forward.
func (r *Remote) Push(o *PushOptions) (err error) {
if o.RemoteName == "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

I though PushOptions.Validate didn't allow for empty strings in the remote name. I'm confused.

Copy link
Collaborator Author

@smola smola Dec 13, 2016

Choose a reason for hiding this comment

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

It is allowed to pass empty remote directly to Remote, since the name is already set in the remote itself and it cannot push to a different Remote.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

return err
}

if err := iter.ForEach(func(ref *plumbing.Reference) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

I find hard to understand at a glance what operation are we doing on each element in the collection.

Can we define the function separately, give it a good name, and call it here instead?

@@ -294,6 +423,70 @@ func (r *Remote) buildFetchedTags() error {
})
}

func (r *Remote) getHaves(refs memory.ReferenceStorage) []plumbing.Hash {
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this a method of Remote instead of a free function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed.

@@ -275,6 +269,25 @@ func (r *Repository) Pull(o *PullOptions) error {
return r.createReferences(head)
}

// Push pushes changes to a remote.
func (r *Repository) Push(o *PushOptions) error {
if o.RemoteName == "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, this was supposed to be part of Validate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right.

return err
}

if err := remote.ConnectPush(); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think Connect should not be needed here, unless you want to do other things over the connection in addition to Push.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I did it this way to keep symmetry with the Fetch implementation. Although both should be changed to have atomic operations without Connect/Disconnect at all.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

RefSpecs []config.RefSpec
}

// Validate validate the fields and set the default values
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on its name, I find weird that Validate set anything, I would expect it to have a non-pointer receiver and just return true or false.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm following the same convention that we are using for a lot of objects in go-git (check other Validate methods). We can discuss changing them as a separate issue, not related to this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍


"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/config"
. "gopkg.in/src-d/go-git.v4/examples"
Copy link
Contributor

Choose a reason for hiding this comment

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

missing space

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

why? they are all internal imports.

Copy link
Contributor

Choose a reason for hiding this comment

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

oops, you're right, I just saw the period and i thought that was go-check or something... 👍

@smola smola added this to the v4 milestone Dec 14, 2016
@mcuadros
Copy link
Contributor

@smola rebase

@smola smola changed the title [WIP][RFC] remote: implement push [WIP][RFC] remote: add Push Dec 15, 2016
@smola smola changed the title [WIP][RFC] remote: add Push remote: add Push Dec 19, 2016
@@ -20,6 +25,16 @@ var args = map[string][]string{
"clone": []string{defaultURL, tempFolder()},
"progress": []string{defaultURL, tempFolder()},
"open": []string{filepath.Join(cloneRepository(defaultURL, tempFolder()), ".git")},
"push": []string{
Copy link
Contributor

Choose a reason for hiding this comment

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

can you create a function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

setRemote(local, fmt.Sprintf("file://%s", remote))
return local
}(),
"origin",
Copy link
Contributor

Choose a reason for hiding this comment

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

the default RemoteName is "origin" should to omit this arg to simplify the example?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done, reduced to just push origin with default refspec.

RemoteName string
// RefSpecs specify what destination ref to update with what source
// object. A refspec with empty src can be used to delete a reference.
RefSpecs []config.RefSpec
Copy link
Contributor

Choose a reason for hiding this comment

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

We can have a default RefSpec?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes: refs/heads/:refs/heads/. I've just added it. Note that git has different behaviours for default push refspec depending on config.

@@ -221,6 +376,27 @@ func getWants(spec []config.RefSpec, localStorer Storer, remoteRefs storer.Refer
return result, nil
}

func (r *Remote) referenceNeedsUpdate(wantTags bool, specs []config.RefSpec,
Copy link
Contributor

Choose a reason for hiding this comment

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

function not tested, or codecov failing

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's not in use.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

removed, leftover from refactor

@@ -345,6 +345,20 @@ func (r *Repository) Fetch(o *FetchOptions) error {
return remote.Fetch(o)
}

// Push pushes changes to a remote.
func (r *Repository) Push(o *PushOptions) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

function not tested

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done.

* add Push method to Remote.
* add method Push to Repository.
* examples: add push example.
@mcuadros mcuadros merged commit f599ee3 into src-d:master Dec 19, 2016
mcuadros pushed a commit that referenced this pull request Jan 31, 2017
* remote: add Push.

* add Push method to Remote.
* add method Push to Repository.
* examples: add push example.

* requested changes

* add tests, fixes
gsalingu-ovhus pushed a commit to gsalingu-ovhus/go-git that referenced this pull request Mar 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants