Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/content-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
# source-path, target-articles, etc.) is read from
# src/content-pipelines/config.yml by the update script.
- id: copilot-cli
- id: gh-stack
# - id: mcp-server

steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Remote control requires:
* **The machine must be online**: The CLI session must be actively running in a terminal on a machine with an internet connection. If the machine goes to sleep or loses its connection, remote control is unavailable until the machine is back online. See [Reconnection](#reconnection) later in this article.
* **An interactive session**: Remote access is only available for interactive sessions. It is not available when you use the CLI programmatically with the `--prompt` command-line option, for example when you use the CLI in a script.

Remote control does not require the working directory to contain a Git repository hosted on {% data variables.product.prodname_dotcom_the_website %}. For users whose {% data variables.product.prodname_copilot_short %} seat comes from an enterprise or organization, the applicable enterprise or organization policy, not repository hosting, determines whether remote control is available. See [Administering remote control](#administering-remote-control) later in this article.

## Accessing a session remotely

When you enable remote control for a {% data variables.copilot.copilot_cli_short %} session, you can go to {% data variables.product.prodname_dotcom_the_website %} or {% data variables.product.prodname_mobile %} and find the session in the list of your recent agent sessions. The remote interface is updated in real time, allowing you to monitor ongoing output from the session and respond to prompts and permission requests as they come in.
Expand Down Expand Up @@ -80,4 +82,6 @@ Enterprise and organization owners control whether users can enable remote contr

For remote control to be available, the applicable policy (enterprise-enforced or organization-level) must be set to "View and control."

Enterprise owners can further restrict remote control using the `remoteControl` enterprise managed setting, which applies on top of the "Store local sessions in the Cloud" policy. This setting is applied per device and controls whether a session **hosted on that device** can be remotely controlled: it can require that the controlling client is SSO-authorized for specific organizations, or disable remote control of sessions hosted on that device entirely. It doesn't affect the same user's ability to remotely control sessions hosted on other devices. See [AUTOTITLE](/copilot/reference/enterprise-managed-settings-reference).

For more information, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-organization/manage-policies) and [AUTOTITLE](/copilot/how-tos/copilot-cli/administer-copilot-cli-for-your-enterprise).
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ This article explains how to enable and use remote control. For more conceptual
> [!TIP]
> Use the `/keep-alive` slash command to prevent your machine from going to sleep while you're away. See [Preventing your machine from going to sleep](#preventing-your-machine-from-going-to-sleep).

* The working directory must contain a Git repository hosted on {% data variables.product.prodname_dotcom_the_website %}. If you are not in a {% data variables.product.prodname_dotcom %} repository, the CLI displays: "Remote session disabled: not in a {% data variables.product.github %} repository."
* Remote control does not require a Git repository hosted on {% data variables.product.prodname_dotcom_the_website %}. You can enable remote control from directories that are not themselves Git repositories, including parent directories containing multiple repositories, and from repositories hosted somewhere other than {% data variables.product.prodname_dotcom_the_website %}. Sessions started outside of a {% data variables.product.prodname_dotcom %} repository appear unassociated with any repository ("no repository") and are only listed on your agents page at [github.com/copilot/agents](https://github.com/copilot/agents). Sessions started inside a {% data variables.product.prodname_dotcom %} repository also appear on that repository's **Agents** tab.

In some cases, the CLI may still be unable to resolve the working directory's repository—for example, if a Git remote is configured but inaccessible. When this happens, remote control is disabled and the CLI displays a "Remote session disabled" message.

## Enabling remote control for a session

Expand Down Expand Up @@ -166,6 +168,8 @@ Remote control is disabled by default, but may be enabled in your {% data variab
* **For a single session**: Start the CLI with `--no-remote` to prevent remote control for that session, regardless of your settings file value.
* **Permanently**: Remove the `"remoteSessions": true` setting from `~/.copilot/settings.json`, or set it to `false`.

Enterprise owners can also restrict remote control of sessions hosted on your device using enterprise managed settings, regardless of your personal settings. Depending on the configured policy, remote control of sessions on your device may be disabled entirely, or only available to a controlling client that is SSO-authorized for specific organizations. This doesn't affect your ability to remotely control your own sessions hosted on other devices. See [AUTOTITLE](/copilot/reference/enterprise-managed-settings-reference).

## Further reading

* [{% data variables.copilot.copilot_cli_short %} sessions in {% data variables.product.prodname_vscode %}](https://code.visualstudio.com/docs/copilot/agents/copilot-cli) in the {% data variables.product.prodname_vscode_shortname %} documentation.
12 changes: 12 additions & 0 deletions content/copilot/reference/enterprise-managed-settings-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ When multiple settings sources are present, settings earlier in this list take p
| `extraKnownMarketplaces` | Adds plugin marketplaces that users can access | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| `strictKnownMarketplaces` | Restricts plugin installation to explicitly listed marketplaces | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| `telemetry` | Configures OpenTelemetry export, routing {% data variables.product.prodname_copilot_short %} usage data to a collector of your choice | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} |
| `remoteControl` | Restricts whether sessions hosted on this device can be remotely controlled, based on the controlling client's SSO authorization status for the listed organizations. Doesn't affect the user's ability to remotely control sessions hosted on other devices | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} |

{% endrowheaders %}

Expand Down Expand Up @@ -77,6 +78,10 @@ The following example shows these keys in one managed settings file.
"headers": {
"Authorization": "Bearer TOKEN"
}
},
"remoteControl": {
"mode": "requireSSO",
"githubDotComOrganizations": ["ORG-NAME"]
}
}
```
Expand Down Expand Up @@ -142,3 +147,10 @@ When you set the `telemetry` property, {% data variables.product.prodname_copilo
* `serviceName`: A label for the telemetry service name (for example, `"copilot"`).
* `resourceAttributes`: An object of OpenTelemetry resource attributes to attach to all exported telemetry (for example, `{"deployment.environment": "production"}`).
* `headers`: An object of HTTP headers to include with each telemetry request (for example, an `Authorization` header for your collector).

## `remoteControl`

Restricts whether {% data variables.copilot.copilot_cli_short %} sessions hosted on a device can be remotely controlled. This doesn't affect a user's ability to remotely control their sessions hosted on other devices.

* `mode`: Set to `"disabled"` to prevent remote control of sessions on the device, `"requireSSO"` to only allow remote control from a client that is SSO-authorized for the organizations listed in `githubDotComOrganizations`, or `"enabled"` to allow it unrestricted.
* `githubDotComOrganizations`: An array of organization logins. Required when `mode` is `"requireSSO"`.
1 change: 1 addition & 0 deletions content/copilot/tutorials/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ children:
- /optimize-ai-usage
- /optimize-code-reviews
- /reduce-technical-debt
- /stack-ai-generated-code-in-pull-requests
- /review-ai-generated-code
- /learn-a-new-language
- /modernize-legacy-code
Expand Down
131 changes: 131 additions & 0 deletions content/copilot/tutorials/stack-ai-generated-code-in-pull-requests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
title: Stack AI-generated code in pull requests
shortTitle: Stack AI pull requests
intro: 'Create a stack of small, dependent pull requests that can be quickly reviewed.'
versions:
feature: copilot
contentType: tutorials
category:
- Accelerate PR velocity
- Team collaboration
---

> [!NOTE]
> Stacked pull requests are in {% data variables.release-phases.public_preview %} and subject to change.

Large pull requests are difficult to review and create bottlenecks, especially when AI helps you generate a high volume of code in a short time. Review quality also degrades as pull request size increases. Reviewers may skim the result, miss issues, or procrastinate and leave the pull request until it grows stale and develops merge conflicts.

Stacked pull requests keep large code changes reviewable.

{% data reusables.pull_requests.pr-stack-definition %}

This tutorial walks you through how to use stacked pull requests with agents to build a feature in individually reviewable layers. For our example, we'll consider how to add user authentication to an app. We'll use {% data variables.copilot.copilot_cli %} and the `gh-stack` agent skill.

## Prerequisites

To use the `gh-stack` skill with an agent, you'll first need to install {% data variables.product.prodname_cli %} and the `gh-stack` CLI extension. You'll need the following:

* {% data variables.product.prodname_cli %} (`gh`) 2.90.0 or later, and Git 2.20 or later.
* Authenticate {% data variables.product.prodname_cli %} with `gh auth login`.
* A {% data variables.product.github %} repository you can push to.
* {% data variables.copilot.copilot_cli %} installed and signed in.

In {% data variables.product.prodname_cli %}, install the `gh-stack` extension and skill.

```shell
gh extension install github/gh-stack
gh skill install github/gh-stack
```

> [!NOTE]
> Throughout this tutorial, if you prefer to run stack commands yourself instead of letting {% data variables.product.prodname_copilot_short %} do it, you'll need to use {% data variables.product.prodname_cli %}.

## 1. Design a stack before you generate code

A good stack is like building a house, start with a strong foundation, frame the walls, install wiring, then finish the drywall. Each layer built, dependent on the one below. In the end, a reviewer should be able to read the pull requests from bottom to top and follow the feature coming together.

* Split the feature into layers. Each layer should be a single, coherent change that can be reviewed on its own.
* Keep each layer small enough that its pull request is a quick read. If a layer feels like it needs a long description to review, it is probably too big.
* Decide the boundaries yourself, or work with {% data variables.product.prodname_copilot_short %} on a plan. Either way, you own the shape of the stack.
* Order the layers by dependency. Foundational changes go at the bottom. Anything that depends on them goes higher. For authentication, that might be:
* Layer 1: data model and migration
* Layer 2: CRUD endpoints
* Layer 3: JWT middleware and guards
* Layer 4: integration and unit tests

### Example prompts

* `Propose a layered approach to add user authentication to this app. Order the layers by dependency, keeping each layer independently reviewable.`
* `Review my planned layers and flag any that are too large or that depend on a branch above them.`

## 2. Build the bottom layer first

Start the stack with the foundation. Everything above depends on getting this layer right.

* Inform {% data variables.product.prodname_copilot_short %} you'll be building a stacked pull request and ask it to build the first layer based on your plan. The agent uses the `gh-stack` skill to create the first branch of the stack.
* If you prefer to create the stack yourself, create it directly with `gh stack init`, using a prefix to keep branch names tidy, for example, `gh stack init BRANCH-NAME-1`.
* Review the generated change yourself before moving on. A mistake in the bottom layer propagates to every branch above it, so give it a review before moving on.

### Example prompts

* `Start the pr-stack and build only the first layer: the user data model and migration.`
* `Conduct a review of the generated code and confirm this branch contains only the data model and migration, and nothing that belongs in a later layer.`

## 3. Stack each new code layer on top

With the foundation in place, build the rest of the feature one layer at a time.

* Ask {% data variables.product.prodname_copilot_short %} to add the next layer and implement it in the context of the layers below. The agent will add a branch to the top of the stack and commit the work there.
* If you want to add a branch yourself, use `gh stack add BRANCH-NAME-NEXT`.
* If a layer starts growing too large, consider whether it has drifted outside its plan or if you actually need two layers instead of one.
* Create new branches for each layer as you go, so every branch stays a clean, self-contained diff.
* When you're ready to create pull requests ask {% data variables.product.prodname_copilot_short %} to submit your stack, or if you want to do it yourself, use `gh stack submit`.
* Let each pull request stand on its own. A focused title and a concise, meaningful description of the layer is usually enough.

### Example prompts

* `Add the next layer in a new branch on top: the CRUD endpoints that use the user model from the branch below.`
* `This branch is getting large. Suggest how it could be split into two independently reviewable layers.`

## 4. Review the pull requests yourself before asking for a review

Each layer is small, making self-review easier too. Do a pass on every branch before you involve teammates. Reviewers should receive changes you already trust.

* Run your tests, linters, and code scanning on each branch. Let {% data variables.product.prodname_copilot_short %} help you check each layer against your standards before you request reviews.
* For the techniques to review AI-generated changes thoroughly, see [AUTOTITLE](/copilot/tutorials/review-ai-generated-code).

## 5. Request reviews for the stack, starting at the bottom

With the layers built, reviewers get small diffs instead of a large wall of code.

* If the dependencies are strongly integrated, ask for reviews starting at the bottom of the stack, so you can integrate changes up the stack before subsequent reviews.
* If you need reviews from separate folks for different layers, reviewers can work in parallel. One person can review the data model while another reviews the endpoints, and neither wades through the whole feature.

## 6. Iterate on feedback

Review feedback lands on layers individually, not the whole feature. Stacks let you fix the right layer in place and carry the change upward.

* Ask {% data variables.product.prodname_copilot_short %} to revise the layer a reviewer flagged. The agent moves to the right branch, makes the change, and commits it there. Then, it rebases the layers above so they pick up the fix.
* Keep each fix in the layer it belongs to. A change made on the wrong branch can confuse and create errors upstack.
* As you make fixes, ask {% data variables.product.prodname_copilot_short %} to rebase the branches above and propagate changes.
* If you want to move through the stack yourself, navigate branches with `gh stack down`, `gh stack up`, or `gh stack checkout BRANCH-NAME`. Then, commit your changes and run `gh stack rebase --upstack` to carry changes up the stack.

### Example prompts

* `A reviewer flagged that the auth service doesn't handle expired tokens. Fix that on BRANCH-NAME and test the changes.`
* `I've rebased the layers above onto this fix. Check that the branch with endpoints still works with the change and flag anything that needs updating.`

## 7. Merge from the bottom layer

A stack merges in order, starting from the layer pointing to your main branch. Merge layers all at once, or one-by-one, and GitHub automatically re-targets the next layer to point at main.

* Merge the stack one at a time working from the bottom up, or from anywhere in the stack and all the branches below the pull request you merge will be merged from the bottom up.
* Each layer's diff stays exactly the same relative to its parent, only the base changes, making it easy to merge a layer at a time without affecting in-progress work or reviews.
* Use auto-merge or a merge queue so each layer merges as soon as it is approved and its checks pass. You do not need to wait on the whole stack at once.

Once the top layer merges, the whole feature has landed. Every piece was reviewed more effectively as a small, deliberate change rather than one large pull request.

## Further reading

* [AUTOTITLE](/copilot/tutorials/review-ai-generated-code)
* [AUTOTITLE](/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests)
1 change: 1 addition & 0 deletions content/pull-requests/concepts/deploying-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ After a pull request is merged or closed, its head branch is often no longer nee
## Further reading

* [AUTOTITLE](/pull-requests/how-tos/merge-and-close-pull-requests/merging-a-pull-request)
{% ifversion pr-stacks %}* [AUTOTITLE](/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests){% endif %}
* [AUTOTITLE](/pull-requests/reference/status-checks)
* [AUTOTITLE](/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments)
2 changes: 1 addition & 1 deletion content/pull-requests/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ redirect_from:
- /github/collaborating-with-issues-and-pull-requests/overview
- /github/collaborating-with-pull-requests/getting-started
shortTitle: Concepts
intro: 'Understand the foundational concepts of pull requests, including branches, forks, commits, reviews, and merges to streamline collaboration on {% data variables.product.github %}.'
intro: 'Understand how pull requests help you write code and collaborate effectively on {% data variables.product.github %}.'
versions:
fpt: '*'
ghes: '*'
Expand Down
1 change: 1 addition & 0 deletions content/pull-requests/get-started/about-pull-requests.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Pull requests turn a set of code changes into a conversation. Instead of merging
Pull requests make your changes easy to review and validate. With a pull request, you can:

* Propose changes from a branch or a fork.
{% ifversion pr-stacks %}* {% data reusables.pull_requests.pr-stack-invitation %}{% endif %}
* Discuss and review the proposed changes, line by line.
* Run automated checks, such as tests, builds, and code scanning, against the changes.
* Respond to feedback and update the pull request as it evolves.
Expand Down
Loading
Loading