Skip to content

Commit dd7b094

Browse files
committed
git: allow pushing to an anonymous remote
Git allows you to push to a remote that isn't defined in your gitconfig: git push https://example.com/foo.git refs/heads/bar:refs/heads/bar The effect of this command is to push to the remote repository at the specified URL, without updating any remote-tracking references corresponding to the reference that was pushed. It would seem that this should be possible with `go-git`, by writing something like r, _ := git.PlainOpen(".") _ = r.Push(&git.PushOptions{ RemoteURL: "https://example.com/foo.git", RefSpecs: []config.RefSpec{"refs/heads/bar:refs/heads/bar"}, }) But `go-git` wasn't handling this correctly: * `PushOptions.Validate()` saw the empty `o.RemoteName` and changed it to `DefaultRemoteName` ("origin"). * If no "origin" remote was defined in the gitconfig, `Repository.Push()` failed entirely with `ErrRemoteNotFound`. * If: an "origin" _was_ defined in the gitconfig, then after the push, remote-tracking references were created for the "origin" remote (e.g., `refs/remotes/origin/foo`), even though the push was probably to a remote that is not related to "origin". Alternatively, if the `PushOptions` were created using `RemoteName: "anonymous"`, the push still failed with `ErrRemoteNotFound` because a remote called "anonymous" was sought in the gitconfig, and that remote:(presumably!) doesn't exist. This commit fixes all three problems: * Change the behavior of `PushOptions.Validate()`: if there is a `RemoteURL` but no `RemoteName`, then set the `RemoteName` to `config.AnonymousRemoteName` rather than setting it to `DefaultRemoteName`. (If neither a `RemoteName` nor a `RemoteURL` is set, then set `RemoteName` to `DefaultRemoteName` as before.) * Change `Remote.updateRemoteReferenceStorage()` to skip updating any remote-tracking references if the remote is anonymous.
1 parent 2633564 commit dd7b094

File tree

4 files changed

+64
-4
lines changed

4 files changed

+64
-4
lines changed

options.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,11 @@ type ForceWithLease struct {
310310
// Validate validates the fields and sets the default values.
311311
func (o *PushOptions) Validate() error {
312312
if o.RemoteName == "" {
313-
o.RemoteName = DefaultRemoteName
313+
if o.RemoteURL != "" {
314+
o.RemoteName = config.AnonymousRemoteName
315+
} else {
316+
o.RemoteName = DefaultRemoteName
317+
}
314318
}
315319

316320
if len(o.RefSpecs) == 0 {

remote.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,18 @@ func (r *Remote) newReferenceUpdateRequest(
354354
return req, nil
355355
}
356356

357+
// updateRemoteReferenceStorage updates the remote references
358+
// corresponding to the references that were just pushed to the
359+
// remote, if needed.
357360
func (r *Remote) updateRemoteReferenceStorage(
358361
req *packp.ReferenceUpdateRequest,
359362
) error {
363+
if r.IsAnonymous() {
364+
// If the remote is anonymous, then there are no
365+
// remote-tracking references corresponding to it.
366+
return nil
367+
}
368+
360369
for _, spec := range r.c.Fetch {
361370
for _, c := range req.Commands {
362371
if !spec.Match(c.Name) {

repository.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,9 +1249,21 @@ func (r *Repository) PushContext(ctx context.Context, o *PushOptions) error {
12491249
return err
12501250
}
12511251

1252-
remote, err := r.Remote(o.RemoteName)
1253-
if err != nil {
1254-
return err
1252+
var remote *Remote
1253+
if o.RemoteName == config.AnonymousRemoteName {
1254+
var err error
1255+
remote, err = r.CreateRemoteAnonymous(
1256+
config.NewAnonymousRemoteConfig(o.RemoteURL),
1257+
)
1258+
if err != nil {
1259+
return err
1260+
}
1261+
} else {
1262+
var err error
1263+
remote, err = r.Remote(o.RemoteName)
1264+
if err != nil {
1265+
return err
1266+
}
12551267
}
12561268

12571269
return remote.PushContext(ctx, o)

repository_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,7 @@ func (s *RepositorySuite) TestCloneWithFilter() {
16801680
s.NotNil(err)
16811681
s.Nil(blob)
16821682
}
1683+
16831684
func (s *RepositorySuite) TestPush() {
16841685
url, err := os.MkdirTemp("", "")
16851686
s.NoError(err)
@@ -1709,6 +1710,40 @@ func (s *RepositorySuite) TestPush() {
17091710
})
17101711
}
17111712

1713+
func (s *RepositorySuite) TestPushAnonymous() {
1714+
url, err := os.MkdirTemp("", "")
1715+
s.NoError(err)
1716+
1717+
server, err := PlainInit(url, true)
1718+
s.NoError(err)
1719+
1720+
// Make sure that there is an "origin" remote. It will _not_ be
1721+
// used, but we want to make sure that its remote-tracking
1722+
// branches are not incorrectly updated by the push.
1723+
c, err := s.Repository.Config()
1724+
s.NoError(err)
1725+
if _, ok := c.Remotes["origin"]; !ok {
1726+
// Create an "origin" remote.
1727+
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
1728+
Name: "origin",
1729+
URLs: []string{filepath.Join(url, "origin-not-used")},
1730+
})
1731+
s.NoError(err)
1732+
}
1733+
1734+
err = s.Repository.Push(&PushOptions{
1735+
RemoteURL: url,
1736+
})
1737+
s.NoError(err)
1738+
1739+
AssertReferences(s.T(), server, map[string]string{
1740+
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1741+
"refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
1742+
})
1743+
1744+
AssertReferences(s.T(), s.Repository, map[string]string{})
1745+
}
1746+
17121747
func (s *RepositorySuite) TestPushContext() {
17131748
url, err := os.MkdirTemp("", "")
17141749
s.NoError(err)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy