Edit files in the browser
Overview
You can change a repository without cloning it. Edit a file, add one, delete, move or rename one, or make a script executable — then commit the change straight to a branch, or to a new branch with a merge request on top. Several changes can wait in a pending list and land together as one commit.
A commit you write in the browser is a commit like any other. It lands through the same branch rules and push rules as a git push, its author is you, and it starts the same pipelines, sends the same webhooks and moves the same merge requests. Nothing about it marks it as written in the browser.
What you edit is always checked against what is there when you commit. If someone changes a file you are editing in the meantime, your commit is refused rather than overwriting their work, and you are shown what changed so you can bring your edit up to date.
Quick start
Edit a file and commit it
Start at the file's page, under Code.
Choose Edit, and make your change.
Write a commit message saying what changed and why.
Choose Commit to land it on
main— or, if the branch is protected or you want a review first, Commit to a new branch and open a merge request.
Before you start
- Developer on the repository.Committing needs the permission to push, which Developer and above hold. A branch rule can raise the bar on one branch: on a protected branch, only the levels and people the rule names can commit, and everyone else commits to a new branch and opens a merge request. The branch page says before you start whether you can commit to it, and why not if you cannot.
- A token with
commit:create, if you commit through the API or the CLI. Reading files needstree:read; templates need nothing at all. - Files the browser can edit.Text files up to 1 MiB, in UTF-8. A file that is larger, binary, in another encoding, a symbolic link or a submodule is changed with git: the editor says so instead of offering to edit it, because saving it from the browser would change it in ways you did not ask for.
How it works
A commit is checked before it is written
Every change you commit names the version of the file you started from. When you commit, Gitmoap compares each one with the branch as it is now:
- A file someone else changed since you opened it is refused, with
FILE_CHANGED. Bring your edit up to date with theirs, then commit again. - A file someone else deleted is refused with
FILE_NOT_FOUND; a file you are creating that now exists, withFILE_EXISTS. - Unrelated commits do not get in your way. If the branch moved for a reason that does not touch your files, your commit lands on top of it. Only a change to a file you are changing stops you.
The same rules as a push
Your commit meets every rule a git push of the same commit would:
- Branch rules decide who can commit to a protected branch.
- Push rules judge the commit: its message (a required issue reference, a pattern), its author's email, and its files (prohibited names, the size limit). A rule that refuses names itself and the part of your commit it is about.
- Unsigned commits. A commit written in the browser is not signed, so a repository that rejects unsigned commits refuses it. Commit those changes with git, signed.
See what a commit would do first
Before you commit, the commit form shows what would happen: every rule that would refuse it, the files that changed since you opened them, and the pipelines the commit would start. Nothing is written until you commit, and asking costs nothing — so the form can tell you as you type.
Templates
A new file can start from a template: a licence, a .gitignore for your language, a changelog, a contributing guide, a code of conduct, a security policy or a service catalog. A template that needs a value — the year and the copyright holder of a licence, the project's name, a contact address — asks for it before it writes the file. The licences are the ones GitHub's choosealicense.com curates, and the .gitignore files come from github/gitignore.
How to
Edit a file
Open the file under Code and choose Edit. Make your change, write a commit message, and choose where it goes: Commit to the branch you are on, or Commit to a new branch. A protected branch you cannot commit to offers only the new branch.
gitmoap commits create \ --repo-id <id> \ --actions '<json>' \ --branch <branch> \ --message <message>curl -X POST https://api.gitmoap.example/repositories/{repo_id}/commits \ -H "Authorization: Bearer $GITMOAP_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "branch": "<string>", "message": "<string>" }'The commit keeps the file's mode, so an executable script stays executable.
Commit several changes together
Changes you make across several files wait in Pending changes until you commit them. Review them there — each file's diff against the version you started from — then commit them as one commit with one message.
Through the API, a commit is a list of changes: create, update, delete, move and chmod, up to 100 of them, each path changed once. Every change to an existing file carries the blob_sha you read it at, from the file's read.
Add a file from a template
Choose Add file, then From a template. Pick the kind — a licence, a .gitignore, a changelog and the rest — then the template, fill in what it asks for, and commit the new file.
gitmoap templates list-templatescurl -X GET https://api.gitmoap.example/templatesThe repository's overview suggests the files it is missing, and Add next to each one starts from its template.
Start a branch with your commit
Choose Commit to a new branch and give the branch a name. The branch is created from the one you were on, and your commit lands on it, in one step. A name that is taken is refused with BRANCH_EXISTS, and a name a branch rule protects follows that rule like any other branch.
Add the first file to an empty repository
A repository nothing has been pushed to offers Add a README. The commit becomes the repository's first commit and creates its default branch.
Reference
3 endpoints
POST/repositories/{repo_id}/commitscommit:create
Commit file changes to a branch
Token scope
commit:create
Counts against
namespace_storage
Send
Path
- repo_iduuidRepository ID
Query
- dry_runbooleanoptionalSay what the commit would do — every refusal, the files that changed since they were read, the pipelines it would start — and write nothing
Body
- branchstring
- expected_head_shaobjectoptional
- messagestring
- start_branchobjectoptional
Refuses
400Malformed request: an invalid path, a path changed twice, more than 100 changes, content that is not valid base64401Unauthenticated — no credential, or an invalid one403The caller may not push to this repository, or a branch rule protects the branch404Repository not found, or the branch, the start branch or a file the commit changes does not exist409A file changed since it was read, already exists or collides with a directory; the branch moved or already exists; or the repository is empty and the branch is not its default413The request is larger than 16 MiB422A push rule refuses the commit, a change targets a symbolic link, a submodule or a directory, or nothing would change429The commit would take the namespace over its storage limit, or exceeds the per-push size
Receive
- allowedbooleanWhether the commit, sent as it is, would land.
authorobject2 fields
- emailstring
- namestring
- branch_existsbooleanWhether
branchexists. Withstart_branch,falsemeans it will be created. - head_shaobjectoptional
pipelines[]object2 fields
- namestring
- pipeline_idobjectoptional
refusals[]object4 fields
- codeAGENT_REFBRANCH_EXISTSBRANCH_NOT_FOUNDBRANCH_PROTECTEDFILE_CHANGEDFILE_EXISTSFILE_NOT_FOUNDFOREIGN_AUTHORHEAD_MOVEDMR_NOT_OPENNOTHING_TO_COMMITNOT_CONFLICTEDNOT_IN_CONFLICTPATH_CONFLICTPERMISSION_REQUIREDPRIVILEGED_PATHPUSH_RULE_VIOLATIONREPOSITORY_EMPTYSTART_BRANCH_NOT_FOUNDUNRESOLVEDUNSUPPORTED_CONFLICTUNSUPPORTED_ENTRYWhat kind of refusal this is. Closed: a client branches on it.
The wire spelling is the
SCREAMING_SNAKEdomain code that leads an error's message, so a refusal returned as data and the same refusal returned as an error read the same. - fieldobjectoptionalThe part of the request the refusal is about:
message,branch, oractions[i]for the i-th file change. - messagestringWhat is wrong, in a sentence a person can act on.
- ruleobjectoptionalThe push rule that refused, by its setting's name (
require_issue_reference), whencodeisPUSH_RULE_VIOLATION.
- codeAGENT_REFBRANCH_EXISTSBRANCH_NOT_FOUNDBRANCH_PROTECTEDFILE_CHANGEDFILE_EXISTSFILE_NOT_FOUNDFOREIGN_AUTHORHEAD_MOVEDMR_NOT_OPENNOTHING_TO_COMMITNOT_CONFLICTEDNOT_IN_CONFLICTPATH_CONFLICTPERMISSION_REQUIREDPRIVILEGED_PATHPUSH_RULE_VIOLATIONREPOSITORY_EMPTYSTART_BRANCH_NOT_FOUNDUNRESOLVEDUNSUPPORTED_CONFLICTUNSUPPORTED_ENTRYWhat kind of refusal this is. Closed: a client branches on it.
The wire spelling is the
stale[]object3 fields
- current_blob_shaobjectoptional
- last_commitobjectoptional
- pathstring
GET/templatespublic
List file templates
Token scope
None — this one is public
Send
Query
- kindcatalogchangelogcode_of_conductcontributinggitignorelicensesecurityoptionalOnly templates of this kind
Refuses
304The templates have not changed since the validator was issued400`kind` names no kind of template
Receive
items[]object6 fields
- default_pathstringWhere the file usually goes:
LICENSE,.gitignore,.gitmoap/catalog.yaml. - keystringUnique within its kind:
mit,rust,default. - kindcatalogchangelogcode_of_conductcontributinggitignorelicensesecurityWhat a template is for.
- namestring
- spdx_idobjectoptionalA licence's SPDX identifier.
- summaryobjectoptional
- default_pathstringWhere the file usually goes:
GET/templates/{template_kind}/{template_key}public
Get a file template
Token scope
None — this one is public
Send
Path
- template_kindcatalogchangelogcode_of_conductcontributinggitignorelicensesecurityThe kind of template
- template_keystringThe template's key within its kind, e.g.
mit
Refuses
304The template has not changed since the validator was issued404No template of that kind and key
Receive
- contentstringThe file's text, each field written as
{{name}}where its value goes. - default_pathstring
fields[]object2 fields
- labelstringWhat to call it next to the input that fills it in.
- namestringThe placeholder's name —
yearstands for{{year}}.
- keystring
- kindcatalogchangelogcode_of_conductcontributinggitignorelicensesecurityWhat a template is for.
- namestring
- spdx_idobjectoptional
- summaryobjectoptional
Limits
| Limit | Value | What happens |
|---|---|---|
| Changes in one commit | 100 | 400; split the change into several commits |
| A request's size | 16 MiB | 413; commit larger files with git |
| A file the editor opens | 1 MiB of UTF-8 text | The editor offers git instead |
| A file's size in a commit | The repository's max_file_size_mb push rule | 422 PUSH_RULE_VIOLATION, naming the file |
| Storage | Your plan's namespace storage | 429; nothing is written |
Troubleshooting
409 FILE_CHANGED
- Cause
- Someone changed a file you are editing since you opened it
- Fix
- Look at their change, bring yours up to date, and commit again. The commit form shows which files changed and who changed them
404 FILE_NOT_FOUND
- Cause
- A file you are changing was deleted meanwhile
- Fix
- Drop the change, or create the file again
409 FILE_EXISTS
- Cause
- A file you are creating now exists
- Fix
- Edit the existing file instead
403 BRANCH_PROTECTED
- Cause
- A branch rule keeps you from this branch
- Fix
- Commit to a new branch and open a merge request
422 PUSH_RULE_VIOLATIONnaming reject_unsigned_commits
- Cause
- The repository rejects unsigned commits, and a commit written in the browser is unsigned
- Fix
- Commit the change with git, signed
422 PUSH_RULE_VIOLATIONnaming another rule
- Cause
- A push rule refuses the commit — its message, its author or a file
- Fix
- Change what the rule names: the message, or the file
409 HEAD_MOVED
- Cause
- You asked for the commit to land only on the head you saw, and the branch moved
- Fix
- Reload and commit again
422 UNSUPPORTED_ENTRY
- Cause
- A change targets a symbolic link, a submodule or a directory
- Fix
- Change those with git; delete a directory by deleting its files
422 NOTHING_TO_COMMIT
- Cause
- Every change leaves its file as it was
- Fix
- Nothing to do — the branch already has your content
Related
- Repositoriesreading files, history and the repository's profile
- Merge requestsreviewing a change, and resolving conflicts in the browser
- Repository rulesbranch rules and push rules
- Access tokensthe scopes a script needs