# ChatGPT GitHub plugin commits

Use @GitHub to access your GitHub account and read or write repositories.

## Get a local working copy

The GitHub connector cannot clone a repository to the local file system. The connector can supply the repository clone URL. The local `git` command must clone the repository.

The procedure is as follows:

1. Call `get_repo`.

   Give this function the repository name in this format:

   ```text
   owner/repository
   ```

2. Read these values from the result:

   * `clone_url`;
   * `default_branch`.

3. Use the local shell to clone the repository:

   ```bash
   git clone <clone_url>
   cd <repository-directory>
   ```

   The `git clone` command downloads the repository and creates the local working copy.

   The GitHub connector does not perform this operation.

4. Get the current remote branch information:

   ```bash
   git fetch --prune origin
   ```

5. Switch to the target branch:

   ```bash
   git switch <target-branch>
   ```

6. Update the local branch before you make changes:

   ```bash
   git pull --ff-only origin <target-branch>
   ```

7. If the target branch does not exist, call `create_branch`.

   Give this function:

   * the repository name;
   * the new branch name;
   * the base branch name as `base_ref`.

   Then run:

   ```bash
   git fetch --prune origin
   git switch --track origin/<new-branch>
   ```

8. Make all required file changes in the local working copy.

   Add, change, or delete the required files.

The GitHub connector authorization does not automatically authorize the local `git` command. The local environment must also have permission to access the repository.

## Committing multiple files

The GitHub connector does not have one function that makes a commit with multiple files. To make one commit with multiple file changes, it uses the GitHub Git Database API.

### Get the current commit SHA and tree SHA

The new commit needs two values from the current target branch:

* the current commit SHA;
* the tree SHA for that commit.

Get both values from the same remote branch state.

1. Update the local remote references:

   ```bash
   git fetch --prune origin
   ```

2. Get the current commit SHA for the target branch:

   ```bash
   git rev-parse "refs/remotes/origin/<target-branch>^{commit}"
   ```

   Save the returned value as the current commit SHA.

3. Get the tree SHA for the same commit:

   ```bash
   git rev-parse "refs/remotes/origin/<target-branch>^{tree}"
   ```

   Save the returned value as the current tree SHA.

4. Confirm that the local branch is based on the current remote branch:

   ```bash
   git rev-parse HEAD
   git rev-parse "refs/remotes/origin/<target-branch>^{commit}"
   ```

   The two values must be equal.

   If the values are not equal, do not continue. Update the local branch and resolve all conflicts first.

The GitHub connector can also supply the current commit SHA indirectly.

Call `compare_commits` with the target branch as both `base` and `head`:

```text
base = <target-branch>
head = <target-branch>
```

Read `base_commit.sha` from the result.

Do not use `search_commits` to find the branch-tip commit. Its first result is not guaranteed to be the current commit for the target branch.

The current connector does not have a direct function that supplies the tree SHA for a branch-tip commit. Therefore, use local Git to get the tree SHA. It is usually better to use local Git for both SHAs so that both values come from the same fetched branch state.

### Create the commit

1. Identify all local file changes.

   Separate the changes into these groups:

   * new files;
   * changed files;
   * deleted files.

2. For each new or changed file, call `create_blob`.

   Give this function:

   * the repository name;
   * the complete new file content;
   * the content encoding.

   Use `utf-8` for UTF-8 text files.

   Use `base64` for binary file content.

   The function stores the file content and returns a blob SHA.

   Save the blob SHA for each file.

   Do not call `create_blob` for deleted files. A deleted file does not have new content.

3. Call `create_tree` one time.

   Give this function:

   * the repository name;
   * the current tree SHA as `base_tree_sha`;
   * one tree entry for each file change.

   For each new or changed file, the tree entry contains:

   * `path`: the repository file path;
   * `mode`: the Git file mode;
   * `type`: `blob`;
   * `sha`: the new blob SHA.

   For a normal non-executable file, use this mode:

   ```text
   100644
   ```

   For an executable file, use this mode:

   ```text
   100755
   ```

   To delete a file, include a tree entry with:

   * the file path;
   * the SHA set to `null`.

   The `create_tree` function returns the new tree SHA.

4. Call `create_commit` one time.

   Give this function:

   * the repository name;
   * the commit message;
   * the new tree SHA as `tree_sha`;
   * the current commit SHA as `parent_sha`.

   This function creates the new commit.

   The function returns the new commit SHA.

5. Call `update_ref` one time.

   Give this function:

   * the repository name;
   * the target branch name;
   * the new commit SHA;
   * `force` set to `false`.

   This operation moves the target branch to the new commit.

6. If `update_ref` fails because the target branch changed, do not use a forced update.

   Fetch the target branch again.

   Get the new current commit SHA and tree SHA.

   Update the local files as necessary.

   Create a new tree and commit from the new branch state.

The single `create_commit` call creates one commit. The new tree contains all specified file additions, changes, and deletions. Therefore, the commit contains all file changes together.
