6 files changed,
59 insertions(+),
4 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-04-24 15:22:00 +0300
Authored at:
2026-04-23 22:30:04 +0300
Change ID:
pnprxulsmlqspvzlttzutlrnpvunwtrw
Parent:
aaf0e5f
M
CHANGELOG.md
路路路 19 19 - `mugit repo default` changes default branch of a repo. 20 20 - `mugit repo sync` syncs specified mirror repo. 21 21 - Mirror status now inclues last sync time(when there were changes fetched) and last checked time. 22 +- Automatically initialize repository on push. 22 23 23 24 ### Bug fixes: 24 25 - Allow downloading only valid and existing refs.
M
internal/git/repo.go
路路路 22 22 ErrEmptyRepo = errors.New("repository has no commits") 23 23 ErrFileNotFound = errors.New("file not found") 24 24 ErrPrivate = errors.New("repository is private") 25 + ErrRepoNotFound = errors.New("repository not found") 25 26 ) 26 27 27 28 type Repo struct { 路路路 37 38 g.path = path 38 39 g.r, err = git.PlainOpen(path) 39 40 if err != nil { 41 + if errors.Is(err, git.ErrRepositoryNotExists) { 42 + return nil, ErrRepoNotFound 43 + } 40 44 return nil, fmt.Errorf("opening %s: %w", path, err) 41 45 } 42 46
M
internal/ssh/ssh.go
路路路 48 48 49 49 repo, err := git.Open(repoPath, "") 50 50 if err != nil { 51 - return s.replyWithGitError(stderr, "repository not found", err) 51 + if !errors.Is(err, git.ErrRepoNotFound) || gitCmd != "git-receive-pack" { 52 + return s.replyWithGitError(stderr, "repository not found", err) 53 + } 54 + 55 + // SSH Git clients display informational messages from stderr; stdout must remain protocol-only for git-receive-pack. 56 + if ierr := s.replyWithGitInfo(stderr, "auto-initializing "+repoName); ierr != nil { 57 + return ierr 58 + } 59 + 60 + if ierr := git.Init(repoPath); ierr != nil { 61 + return s.replyWithGitError(stderr, "failed to init repo", ierr) 62 + } 63 + 64 + repo, err = git.Open(repoPath, "") 65 + if err != nil { 66 + return s.replyWithGitError(stderr, "failed to open initialized repo", err) 67 + } 52 68 } 53 69 54 70 switch gitCmd { 路路路 105 121 } 106 122 107 123 func (s *Shell) replyWithGitError(stderr io.Writer, msg string, cause error) error { 108 - if _, err := fmt.Fprintf(stderr, "fatal: %s\n", msg); err != nil { 124 + if _, err := fmt.Fprintf(stderr, "error: %s\n", msg); err != nil { 109 125 return err 110 126 } 111 127 112 128 return cause 113 129 } 130 + 131 +func (s *Shell) replyWithGitInfo(msgOut io.Writer, msg string) error { 132 + _, err := fmt.Fprintf(msgOut, "info: %s\n", msg) 133 + return err 134 +}
M
testscript/ssh-clone-nonexistent.txtar
路路路 16 16 17 17 # clone non existent repo 18 18 ! exec env GIT_SSH_COMMAND=$SSH_WRAPPER git clone git@localhost:nonexistent.git wont-clone 19 -stderr 'fatal: repository not found' 19 +stderr 'error: repository not found' 20 20 ! stderr 'ERROR mugit' 21 21 22 22
M
testscript/ssh-push.txtar
路路路 12 12 stdout 'hello from ssh' 13 13 14 14 15 +# auto initializing on first push 16 +git init local2 17 +cp file.txt local2/file.txt 18 +git -C local2 add file.txt 19 +git -C local2 commit -m initial 20 + 21 + 22 +exec env GIT_SSH_COMMAND=$SSH_WRAPPER git -C local2 push git@localhost:auto-init master 23 +stderr 'info: auto-initializing auto-init' 24 +exists $REPOS/auto-init.git/HEAD 25 + 26 +# subsequent pushes should not re-initialize 27 +cp file2.txt local2/file2.txt 28 +git -C local2 add file2.txt 29 +git -C local2 commit -m second 30 + 31 +exec env GIT_SSH_COMMAND=$SSH_WRAPPER git -C local2 push git@localhost:auto-init master 32 +! stderr 'auto-initializing auto-init' 33 + 34 + 35 +# verify pushed content is available 36 +exec env GIT_SSH_COMMAND=$SSH_WRAPPER git clone git@localhost:auto-init verify-auto-init 37 +exists verify-auto-init/file.txt 38 +exists verify-auto-init/file2.txt 39 + 40 + 15 41 # should not allow execution of commands 16 42 ! exec $SSH_WRAPPER ignored 'echo hi' 17 43 stderr 'access denied:' 路路路 19 45 20 46 -- file.txt -- 21 47 hello from ssh 48 + 49 +-- file2.txt -- 50 +hello second push