NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Git for Laravel

Creating repositories

createRepository() picks its route from the input: a template generates from a template repository (POST /repos/{template}/generate), an owner creates in that organization (POST /orgs/{owner}/repos), and neither creates under the authenticated account (POST /user/repos):

use RoundlyConsulting\Git\Dto\Input\NewRepository;

$repo = Git::github()->createRepository(new NewRepository(
    name: 'widget-for-laravel',
    private: true,
    owner: 'acme',
    template: 'acme/package-template',
));

Initial commit and default branch

Only the template route produces a repository that already has a commit — the other two create an empty one unless you pass autoInit: true, and cloning an empty repository with --branch fails. defaultBranch is honoured by renaming the initial branch after creation, because GitHub accepts no default_branch at creation time; it therefore requires autoInit or a template:

// An empty repository cannot be cloned with --branch — ask for an initial commit:
$repo = Git::github()->createRepository(new NewRepository(
    name: 'widget',
    private: true,
    description: 'Internal widget service',
    autoInit: true,
    defaultBranch: 'develop',   // requires autoInit or a template
));

Organization permissions

Creating in an organization needs the GitHub App to hold organization administration: write — an org owner approves it on the existing installation. Mint the token for it just-in-time and let it fall out of scope:

use RoundlyConsulting\Git\Dto\Credentials\GithubAppToken;
use RoundlyConsulting\Git\Dto\Input\InstallationTokenScope;

$credentials = GithubAppToken::for($appId, $installationId, $privateKey)
    ->forScope(InstallationTokenScope::administrationOnly());

Git::github($credentials)->createRepository(new NewRepository(
    name: 'widget',
    owner: 'acme',
    autoInit: true,
));

When GitHub refuses the creation with a 403 that carries no rate-limit signal, the package throws InvalidCredentialsException naming the missing permission instead of GitHub’s opaque “Resource not accessible by integration”.

On GitLab and Bitbucket

  • GitLab maps owner to a numeric namespace_id (a non-numeric owner throws InvalidArgumentException), autoInit to initialize_with_readme, and takes defaultBranch at creation time.
  • Bitbucket maps owner to the workspace — pass one. It has no initial-commit option, so autoInit or defaultBranch throws FeatureNotSupportedException rather than being dropped.
  • Template generation is GitHub-only and throws FeatureNotSupportedException elsewhere.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.