# Git Integration

> Your whole API Maker project in Git - branches, pull, push with a commit, status and diff of every change, revert, secrets kept out, migration scripts run after a pull, and deployment hooks for CI.

Source: https://docs.apimaker.dev/v4/docs/Git/git.html

Everything you build in API Maker is text : schemas, custom APIs, hooks, events, schedulers, settings, groups, test cases… API Maker keeps it in a Git repository of yours, branch by branch, and pulls it back on any other server.

| | |
|---|---|
| Set up | **Connect a repository** on the Git page, or Profile → **User info** : the Git URL with credentials, and the email of the commit user. |
| Branch | **Branches** on the Git page : a click makes a branch the **working branch**, the one commits go to and pulls come from. **New branch** from another one ; delete one from its row. |
| Pull | Replaces the code of the account with the branch, then runs the [migration scripts](https://docs.apimaker.dev/v4/docs/features/database-migration.html) not yet executed here. |
| Push | Shows the status, lets you compare and revert, then commits with your message. Pull requests are raised in your Git host. |
| Never in Git | Secrets. |

> Diagram : From a branch to live : pull request, pull, one transaction, migration scripts
>
> A change goes live through Git : it is committed to a branch and reviewed in a pull request, then pulled on the environment from the Git panel or a deployment hook. The pull replaces the items of the account in one MongoDB transaction, so a pull which fails changes nothing. The migration scripts not yet run on this environment run after it, in order, and the change is live.

## What goes to Git

- One folder per kind in `src`, one folder per item in it, the item as YAML and its code in a file of its language : `.ts` for TypeScript, `.py` for Python, `.php`, `.cs` for C#, `.go`, `.rs` for Rust, `.java`, `.kt` for Kotlin.
- Settings are always a `.ts` file, whatever language the code is written in : the Basic Info of a custom API, the settings of the APIs of a table and of a system API and a schema (`<name>.config.ts`), the texts of internationalization and what a token generator is (`<name>.ts`). See [settings are always TypeScript](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info).
- The sandboxes of the account : `src/admin_user/data.yaml` holds the runtimes, versions, packages and variables of each language, and the Dockerfile written for a language is `src/admin_user/sandbox/<language>/Dockerfile`.
- Secrets never leave the server. Each environment keeps its own, which is the point : the same code runs against another database because the secret differs.
- The folder is what the [local client](https://docs.apimaker.dev/v4/docs/getting-started/local-run.html#your-code-in-your-editor-the-local-client) syncs to your disk, so the same files open in your editor.
- `AGENTS.md` at the root is the guide of API Maker for AI agents (Codex, Claude Code, Cursor, Copilot) : where everything is, how code is written, the rules of security and how to fix the findings of the security report. Every commit writes its block again ; what you write around the block stays. See [AGENTS.md in your repository](https://docs.apimaker.dev/v4/docs/ai/llms.html#agents-md).

**A repository with a custom API in TypeScript, one in Go and a scheduler in Python**

```text
AGENTS.md                            the guide for AI agents
package.json  tsconfig.json          TypeScript
go.mod  am/am.go  am/methods.go      Go : the module "apimaker" and the package your code imports
pyproject.toml                       Python
src/
  custom_apis/
    orders/
      orders.yaml                    the item : name, versions, hooks (no code)
      orders.ts                      its code
      orders.config.ts               its settings (path, method, access) : TypeScript in every language
      pre-hooks/check_stock.ts       a hook before it
    stock/
      stock.yaml
      stock.go                       package of its own : src/custom_apis/stock
      stock.config.ts
      pre-hooks/audit/audit.go       a hook of Go is a package of its own too
  schedulers/
    Daily_report/
      Daily_report.yaml              name: Daily report
      Daily_report.py
  collection_hooks/
    Row_scope-customers/
      Row_scope-customers.yaml       the hook : its table, before or after the APIs, its place there (no code)
      Row_scope-customers.ts         its code
    Check_access/
    Check_access--orders/            a second hook named "Check access" : its table tells it apart
  schemas/  instances/  events/  web_socket_events/  utility_classes/  test_cases/  …
  admin_user/data.yaml
```

### The names of the folders

| What | Its folder | Example |
|---|---|---|
| A kind | Its name in small letters, `_` for a space | `custom_apis`, `schemas`, `instances`, `instance_api_settings`, `instance_api_hooks`, `instance_hooks`, `database_hooks`, `collection_hooks`, `system_api_settings`, `system_api_hooks`, `events`, `web_socket_events`, `schedulers`, `process_initializers`, `database_migrations`, `utility_classes`, `test_cases`, `auth_providers`, `i18ns`, `groups`, `api_users`, `log_profiles`, `api_testing_states`, `api_security_report`, `auto_increments`, `admin_user` |
| An item, and the files in it | Its name ; what is no letter, digit, `.`, `-` or `_` is written `_` | The scheduler `Daily report` is `src/schedulers/Daily_report/Daily_report.py` |
| A hook of an instance, a database, a table, an API of a table, a system API | A folder of its own, named by the hook | `src/collection_hooks/Row_scope-customers/Row_scope-customers.ts`, see [Hooks](https://docs.apimaker.dev/v4/docs/Git/git.html#hooks) |
| A hook of a custom API, a version, a listener | The same rule, in the folder of the item | `pre-hooks/check_stock.ts`, `versions/2/Faster.ts`, `listeners/send_a_mail/send_a_mail.py` |

- No folder has a space in its name : the tools of every language take the repository as it is (a folder is a package in Go, and its name is part of what code imports).
- The name itself is in the YAML of the item (`name: Daily report`). Nothing is read back from the name of a folder, so two names are never mixed up by it.
- Renaming an item shows as its files deleted and added under the new name.

### Hooks

The hooks of an instance, a database, a table, an API of a table and a system API are a folder each, named by the name you gave the hook : `instance_hooks/`, `database_hooks/`, `collection_hooks/`, `instance_api_hooks/`, `system_api_hooks/`. The folder holds the code of the hook in its language and its YAML.

**src/collection_hooks/Row_scope-customers/Row_scope-customers.yaml**

```yaml
_id: 6a39057e8e907bb90f6971e7        # the hook
active: true
collectionName: customers            # where it runs : instanceName, databaseName, collectionName, apiId
databaseName: shop
groupNames: [shop_app]
guid: 01M5RRJ7P2SVB20TX2QA4HE78R     # the hooks of the table are kept together under this guid
hookType: pre                        # pre : before the APIs, post : after them
instanceName: mongodb
isActive: true
name: Row scope - customers
order: 1                             # its place among the pre hooks of the table
```

- **Two hooks of one name.** The oldest keeps the name, the next one gets what tells it apart, then a number : `Check_access`, `Check_access--orders` (its table), `Check_access--orders--2`. A hook of a database is told apart by its database, of an instance by its instance, of an API by its table and its API (`Check_access--orders--GEN_GET_ALL`), of a system API by the API (`Check_access--GET_TOKEN`). Names are compared without case, as the disk of Windows or macOS does. A hook which is added never takes the folder of another one.
- **The order** of the hooks of a list is `order` : change it there, or with the arrows of the list in API Testing.
- **On your disk.** Write a folder with its YAML and its code, and the local client adds the hook to its table, at its `order` ; a YAML without `_id` is a new hook. Delete the folder of a hook and the hook goes ; a table, a database, an instance or an API whose last hook goes has no row of hooks left. Rename a hook in its YAML and the local client gets every file again : its folder moved.
- A table (or any place) without hooks has no folder.

### A project of every language

Besides `package.json` and `tsconfig.json`, a commit writes the file each language you use needs, with the packages of its environment in [Sandbox settings](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html) as its dependencies, and what your code imports of API Maker as source. Open the repository in your editor and the code resolves, completes and compiles as it does in a sandbox.

| Language | Written at the root | Check it yourself |
|---|---|---|
| TypeScript | `package.json`, `tsconfig.json`, `am-types/` | `npx tsc --noEmit` |
| Python | `pyproject.toml` | `python -m compileall src` |
| PHP | `composer.json` | `composer validate`, `php -l <file>` |
| Go | `go.mod`, `am/am.go`, `am/methods.go` | `go build ./...`, `go vet ./...` |
| Rust | `Cargo.toml`, `am/rust/` (the crate `am`, and `project.rs` which names every `.rs` file as a module) | `cargo check` |
| C# | `ApiMaker.csproj`, `am/dotnet/` | `dotnet build` |
| Java | `settings.gradle.kts`, `am/java/build.gradle.kts`, `am/jvm/am/` (what the code imports of API Maker : `G`, `Json`, `AmErrors`…) | `gradle check` |
| Kotlin | `settings.gradle.kts`, `am/kotlin/build.gradle.kts`, `am/jvm/am/` | `gradle check` |

- **Go : a package per folder.** Each piece of Go code is alone in its folder. Where a folder would hold two (the hooks of a list, the functions of a token generator), each is in a folder named as its file : `pre-hooks/audit/audit.go`, `users_tg/users_tg.tg/users_tg.tg.go`. The code a new item starts with says `package code` ; the sandbox builds it as a plugin whatever its package is named. A file is never named as Go reads names : `orders_test` is written `orders_test_.go`.
- **C# : `file static class Api`.** A class marked `file` is known in its file only, so every file can have its own `Api` and they still compile as one project. The code a new item starts with is written that way.
- **Rust** needs no care : every file is a module of the library `am/rust/project.rs` lists.
- **Java and Kotlin : a folder per piece of code, a build of Gradle.** The files of a folder are compiled together, and every piece of code has its `main` (in Java, its class `Api` too). So a file which is not the only code of its folder is in a folder named as the file, as in Go : `pre-hooks/check/check.java`, `users_tg/users_tg.tg/users_tg.tg.kt`. Each folder of code is a source set of its own in the project of its language, compiled on its own with the utility classes, as a sandbox compiles it. `settings.gradle.kts` finds the projects there are : an account with code in both languages has both, and one `am/jvm/am/`. When the settings name a version of the JDK, the Java project compiles for it (`options.release`); the Kotlin project uses the plugin of Kotlin `2.4.20`, the compiler of the sandboxes.
- **Utility classes resolve as in a sandbox.** A [utility class](https://docs.apimaker.dev/v4/docs/languages/index.html#utility-classes) is `src/utility_classes/<folder>---<name>/<name>.<extension>` (`utils---Tax/Tax.py` for the class `Tax` of the folder `utils/`), and the file of the project of its language makes the code find it by the name it imports :

    | Language | What the commit writes for the classes | The code |
    |---|---|---|
    | TypeScript | `tsconfig.json` : a path `utils/Tax` for each class | `import * as tax from 'utils/Tax';` |
    | Python | `pyproject.toml` : the folders of the classes for Pyright / Pylance, pytest and mypy | `from Tax import add` |
    | PHP | `composer.json` : the files of the classes under `autoload.files` | `Tax::add(100)` |
    | Rust | `am/rust/project.rs` : `pub mod Tax;` with the path of its file | `use crate::Tax::add;` |
    | Go | nothing : the folder is the package | `import tax "apimaker/src/utility_classes/utils---Tax"` |
    | C# | nothing : one project compiles every file | `Tax.Add(100)` |
    | Java, Kotlin | nothing : the project of Gradle compiles the folders of the classes together (the source set `utilities`), and every piece of code with them | `Tax.add(100)` |
- `.gitignore` gets what those tools build : `/target/`, `/bin/`, `/obj/`, `/vendor/`, `/.venv/`, `__pycache__/`, `/.gradle/`, `/.kotlin/`, `/build/`, `/am/*/build/`.

### Repositories written before

- A repository written by an earlier version has the kinds as they are named (`src/Custom APIs`, `src/Utility classes`) and the items by their names with spaces, and may keep code of every language in `.ts` files. It is **pulled as it is**.
- The **next commit moves each kind you commit** to its folder of today and removes the old one : the status lists the files as deleted and added once. The history of an item goes on across the move.
- Take the `localClient.js` of that commit : the local client of before does not know the new folders.
- **Hooks in the folder of their row.** A branch written before the hooks had a folder each has the hooks of a table (an instance, a database, an API) in one folder, named by its guid or by its place (`src/collection_hooks/01M5RRJ7P2SVB20TX2QA4HE78R/pre-hooks/Row_scope-customers.ts`, `src/Collection hooks/mongodb -- shop -- customers/…`). It is pulled as it is. The status shows a hook which only moved to its own folder as no change, and a hook which changed since as modified, compared with what it was ; the next commit moves them all.
- A file of code made on your disk names its language by its extension : `orders.py` in a new folder of `custom_apis` is a custom API in Python. A file of settings is read as `.ts` only : `orders.config.py` is not the settings of `orders`.

### Repositories and databases of API Maker 3

- A branch API Maker 3 wrote (`src/Custom APIs`…) is pulled as it is. The next commit writes it the way API Maker 4 does (`src/custom_apis`…).
- **Hooks of API Maker 3** (`src/Collection hooks/<guid>/pre-hooks/<name>.ts`, `src/Instance API hooks/…`, `src/System API hooks/<API>/…`) are pulled with their code, their ids, their lists and their order ; a row of hooks without a hook (API Maker 3 kept many) is pulled too, and the next commit writes no folder for it. The next commit gives every hook a [folder of its own](https://docs.apimaker.dev/v4/docs/Git/git.html#hooks).
- **UI Maker and third party APIs are not pulled** : API Maker 4 has neither. The folders `DB masters`, `DB master utils`, `UI maker styles`, `Third party APIs`, `Third party API settings`, and the WebSocket events of third party APIs, stay in the branch and nothing of them is saved. The pull panel lists them once the pull is over, and so does the log of the pull. The next commit removes them from the branch.
- Every sandbox of API Maker 3 had npm packages of its own (`lodash`, `moment`, `crypto-js`…), which code could `require` without listing them. The ones the code of the branch takes become packages of the account, at the version API Maker 3 had. Code marked **Run on native process** finds the packages installed in the folder of the server instead : the log of the pull names the ones to install there (`npm install moment@2.29.4`).
- A third party API installed from the store of API Maker 3 brought npm packages into the sandboxes of the account (`@aws-sdk/client-s3` of `aws-s3-bucket`), and its utility classes are in the branch (`utils/aws-s3-bucket/1.0.0/S3BucketUtility`). The utility classes are pulled with the others, and the packages of the third party API which the code takes become packages of the account, at the version the API had.
- The enums of UI Maker which code of API Maker 3 reads (`EDBMasterFormControl.file_upload` in the `uim` of a schema property) are still there for that code : such a schema saves as it did.
- Two items of a part which give one guid (a folder copied by hand : API Maker 3 could not pull such a branch either) are both pulled : the first keeps the guid, the next one gets its own, the same at every pull. The pull panel and the log of the pull name it, and the next commit writes it to the branch.
- The Dockerfile of an API Maker 3 account (`src/Admin user/Dockerfile`) builds no sandbox in API Maker 4, and the next commit leaves it out. The sandboxes of API Maker 3 ran Alpine, those of API Maker 4 run Debian : a program of the system the code calls (`ping`…) goes in the Dockerfile of the JavaScript environment (`apt-get install -y iputils-ping`).
- A server of API Maker 4 started on the database of an API Maker 3 installation does the same once, for every account : the packages its code takes are listed (those of its third party APIs too), and a WebSocket event whose code is in its versions only gets that code as the code which says who may connect. A pull of API Maker 3 left that code empty, so API Maker 3 never ran it. A database API Maker 3 never ran on is left as it is.

## Pull

1. Make the branch the working branch, click **Pull**. The panel shows the **Steps on the server** and a live log.
2. The items of the branch replace the ones of the account. The tag **last pulled** of a branch, and the line under the working branch, show what the account runs, also when a deployment hook or another browser pulled it.
3. The active migration scripts which never ran on this environment are listed : run them, in order.

- **Pull without secret** (in the menu of the Pull button) : for a repository made on another installation, whose `passDBEncryptDecrypt` differs. The passwords of the API users can not be decrypted, so they are set to read their password from the secret (`common.apiUserPasswords.default`). Add those passwords to your secret.

## Push

1. **Check status** lists every file which differs from the branch : added, modified, deleted. Filter the list, expand all.
2. **Compare** opens one file in the compare editor ; **View all changes in one diff** shows them together.
3. **Tick** the changes to commit. A new status ticks every change except those of Auto Increments, which belong to one environment. The checkbox of a kind of item, of an item, or of the filter bar (every listed change) ticks all of its files ; a filter hides changes without unticking them. The line above the message says what the commit carries : `Commits 9 of 10 changes · Schemas 3 · API users 1 …`.
4. **Revert** puts a file back to the branch, in the account too ; **Revert N selected** puts back the ticked changes. Some files can not be reverted from here : the files written for the editors (`types/db-interfaces.d.ts`, the project files), `AGENTS.md`, the API Security Report and Auto Increments. They stay ticked.
5. Write the message and **Commit to** the working branch : the ticked changes are committed and pushed. The others stay out of the commit, and the next status still lists them.

- Renaming a hook moves its folder : its two files show as deleted and added under the new name.

## The history of one item

- The Git icon in the header of an item (a custom API in API Testing, a schema, a scheduler, an event, a group…) opens its **History** : the version live in the database, then every commit of the working branch which changed the item, with its author and date. **Load older versions** reads further back.
- **Changes** compares the selected version with the **Previous** one, the **Database**, or a version pinned in the list ; **Full version** shows it whole. Each file of the item is a tab.
- **Revert** writes the selected version into the database only : the database version shows **UNCOMMITTED** until it is committed.
- **A hook** (the Git icon of a hook in API Testing, or of the form of a hook) has the history of its folder, and before it had one, of its file in the folder of its row. Its revert takes back that hook only, the other hooks of its table stay as they are. The history of the hooks of an API (the icon of the API) has the folders of all of them.

## Deployment hooks

- A deployment hook is an URL of your server which pulls a branch, for a CI pipeline or the webhook of your Git host. Create it in the Git panel : a name, an access token and a secret, and the IPs allowed to call it. The name and the access token take letters, digits and `_` only ; the secret takes any character.

```text
GET /api/sites/deploy/<user path>/<hook name>?token=<access token>&secret=<secret>&branch=main
```

- `syncMode=SYNC_WITHOUT_SECRET` pulls like the Pull Without Secret button ; `runMigrationScripts=false` skips the migration scripts.
- The last callers are kept, so the panel can show where the deployments came from.

## Related

- [Database migration scripts](https://docs.apimaker.dev/v4/docs/features/database-migration.html) · [Team work](https://docs.apimaker.dev/v4/docs/features/team-work.html) · [Secrets](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Local client](https://docs.apimaker.dev/v4/docs/getting-started/local-run.html)
