/ase-repo-import
Import a change set -- a pull/merge request or commit of GitHub, GitLab, or Gitea, given by its URL or by its number `#<number>`, or a diff/patch file -- into the current Git working copy as unstaged and untracked files, merging it with local changes, resolving conflicts
Claude Code
$ npx -y skills add rse/ase --skill ase-repo-import --agent claude-code
Codex
$ npx skills add rse/ase --skill ase-repo-import -a codex -y
Cursor
$ npx skills add rse/ase --skill ase-repo-import -a cursor -y
Gemini CLI
$ npx skills add rse/ase --skill ase-repo-import -a gemini-cli -y
GitHub Copilot
$ npx skills add rse/ase --skill ase-repo-import -a github-copilot -y
OpenCode
$ npx skills add rse/ase --skill ase-repo-import -a opencode -y
Windsurf
$ npx skills add rse/ase --skill ase-repo-import -a windsurf -y
SKILL.md
ase-repo-import.SKILL.mdname: ase-repo-import
argument-hint: "[--help|-h] [--safe|-s] [--interactive|-i] <url>|#<number>|<patch-file>"
description: >
Import a change set -- a pull/merge request or commit of GitHub,
GitLab, or Gitea, given by its URL or by its number `#<number>`, or
a diff/patch file -- into the current Git working copy as unstaged
and untracked files, merging it with local changes, resolving
conflicts semantically, keeping the conflict markers of unresolvable
hunks, reporting them as a TODO, and emitting an IMPORTED, CONFLICT,
or FAILED verdict. Use when the user calls to "import", "fetch", or
"apply" a pull request, merge request, commit, diff, or patch.
user-invocable: true
disable-model-invocation: false
effort: high
allowed-tools:
- "Bash(git *)"
- "Bash(mkdir -p *)"
- "Bash(cp -p *)"
- "Bash(rm -rf *)"
- "Read"
- "Edit"
- "Write"@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md @${CLAUDE_SKILL_DIR}/../../meta/ase-dialog.md @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
<purpose name="ase-repo-import"> Import a Change Set </purpose>
<expand name="getopt" arg1="ase-repo-import" arg2="--safe|-s --interactive|-i"> $ARGUMENTS </expand>
<objective> *Import* a change set into the working copy as *unstaged* and *untracked* files, *merge* it with local changes, *resolve* its conflicts *semantically*, and report the remaining conflicts as the *TODO* and the *import verdict*. </objective>
@${CLAUDE_SKILL_DIR}/../../meta/ase-common-resolve.md
<define name="import-fail"> If <fetched-patch/> is not empty, remove it by running the command `rm -rf "<fetched-patch/>"`. Then only output the following <template/> and then immediately *STOP* processing the entire current skill, as the working copy is still *untouched*:
<template> ⧉ **ASE**: ✪ skill: **ase-repo-import**, ▶ ERROR: <arg1/>, ▶ IMPORT VERDICT: **FAILED** </template> </define>
Procedure ---------
<flow>
1. <step id="STEP 1: Determine Source">
1. Set <fetched-patch></fetched-patch> (empty) and <import-escalations></import-escalations> (empty). Set <source/> to <getopt-arguments/> with any leading and trailing whitespace and any surrounding quotes stripped. If <source/> is empty, expand the following:
<expand name="import-fail" arg1="exactly one source required"></expand>
2. Capture the outputs of the commands `git rev-parse --show-toplevel` and `git rev-parse --absolute-git-dir` (taken exactly as given) into <repo-root/> and <git-dir/>. If a command fails, expand the following:
<expand name="import-fail" arg1="no Git repository"></expand>
3. Run the command `git -C "<repo-root/>" ls-files --unmerged`. If its output is *not* empty, expand the following, as the conflicts of the import could not be told apart from the existing ones:
<expand name="import-fail" arg1="working copy has unresolved conflicts"></expand>
4. Classify <source/> into <source-kind/> by the *first* matching form:
- `#<number/>` (only digits after the `#`): set <source-kind/>
to `request`. The form *always* references the number of the forge and *never* a task id of ASE. Determine the remotes by running the command `git -C "<repo-root/>" remote` and set <remote/> to `upstream` if it exists, else to `origin` if it exists. Otherwise, expand the following:
<expand name="import-fail" arg1="neither remote `upstream` nor `origin` exists"></expand>
- A value starting with `http://` or `https://`: remove any
`?...` and `#...` suffix and match the remainder as `<repo-url/>/<path/>`, where <path/> is one of:
- `commit/<sha/>` or `-/commit/<sha/>`, or
`pull/<number/>/commits/<sha/>` or `pulls/<number/>/commits/<sha/>`: set <source-kind/> to `commit`.
- `pull/<number/>`, `pulls/<number/>`, or
`-/merge_requests/<number/>`, optionally followed by `.diff`, `.patch`, or `/<anything/>`: set <source-kind/> to `request`.
The URL is *valid* only if <repo-url/> matches the regexp `^https?://[A-Za-z0-9.:-]+(/[A-Za-z0-9._~-]+)+$`, <number/> consists of digits only, and <sha/> consists of 7 to 64 hexadecimal digits, which keeps it safe for being passed quoted to the `git` commands. If it is not valid or no form matches, expand the following:
<expand name="import-fail" arg1="unsupported URL: **<source/>**"></expand>
Determine the remotes by running the command `git -C "<repo-root/>" remote -v` and set <remote/> to the first remote whose fetch URL denotes the same host and repository path as <repo-url/> (ignoring the scheme, the user, and a trailing `.git`), so its access credentials are used, or to <repo-url/> otherwise.
- Anything else: set <source-kind/> to `file` and <patch/> to
the absolute path of <source/>, resolved against the current working directory. If this is no readable regular file, expand the following:
<expand name="import-fail" arg1="**<source/>** is neither a supported reference nor a patch file"></expand>
</step>
2. <step id="STEP 2: Prepare Patch">
1. <if condition="<source-kind/> is `request`">
1. Capture the *default branch* of the remote by running the command `git -C "<repo-root/>" fetch --quiet --no-tags "<remote/>" HEAD` and then the output of the command `git -C "<repo-root/>" rev-parse FETCH_HEAD` into <default-commit/>. If a command fails, expand the following:
<expand name=
Read more
name: ase-repo-import
argument-hint: "[--help|-h] [--safe|-s] [--interactive|-i] <url>|#<number>|<patch-file>"
description: >
Import a change set -- a pull/merge request or commit of GitHub,
GitLab, or Gitea, given by its URL or by its number `#<number>`, or
a diff/patch file -- into the current Git working copy as unstaged
and untracked files, merging it with local changes, resolving
conflicts semantically, keeping the conflict markers of unresolvable
hunks, reporting them as a TODO, and emitting an IMPORTED, CONFLICT,
or FAILED verdict. Use when the user calls to "import", "fetch", or
"apply" a pull request, merge request, commit, diff, or patch.
user-invocable: true
disable-model-invocation: false
effort: high
allowed-tools:
- "Bash(git *)"
- "Bash(mkdir -p *)"
- "Bash(cp -p *)"
- "Bash(rm -rf *)"
- "Read"
- "Edit"
- "Write"@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md @${CLAUDE_SKILL_DIR}/../../meta/ase-dialog.md @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
<purpose name="ase-repo-import"> Import a Change Set </purpose>
<expand name="getopt" arg1="ase-repo-import" arg2="--safe|-s --interactive|-i"> $ARGUMENTS </expand>
<objective> *Import* a change set into the working copy as *unstaged* and *untracked* files, *merge* it with local changes, *resolve* its conflicts *semantically*, and report the remaining conflicts as the *TODO* and the *import verdict*. </objective>
@${CLAUDE_SKILL_DIR}/../../meta/ase-common-resolve.md
<define name="import-fail"> If <fetched-patch/> is not empty, remove it by running the command `rm -rf "<fetched-patch/>"`. Then only output the following <template/> and then immediately *STOP* processing the entire current skill, as the working copy is still *untouched*:
<template> ⧉ **ASE**: ✪ skill: **ase-repo-import**, ▶ ERROR: <arg1/>, ▶ IMPORT VERDICT: **FAILED** </template> </define>
Procedure ---------
<flow>
1. <step id="STEP 1: Determine Source">
1. Set <fetched-patch></fetched-patch> (empty) and <import-escalations></import-escalations> (empty). Set <source/> to <getopt-arguments/> with any leading and trailing whitespace and any surrounding quotes stripped. If <source/> is empty, expand the following:
<expand name="import-fail" arg1="exactly one source required"></expand>
2. Capture the outputs of the commands `git rev-parse --show-toplevel` and `git rev-parse --absolute-git-dir` (taken exactly as given) into <repo-root/> and <git-dir/>. If a command fails, expand the following:
<expand name="import-fail" arg1="no Git repository"></expand>
3. Run the command `git -C "<repo-root/>" ls-files --unmerged`. If its output is *not* empty, expand the following, as the conflicts of the import could not be told apart from the existing ones:
<expand name="import-fail" arg1="working copy has unresolved conflicts"></expand>
4. Classify <source/> into <source-kind/> by the *first* matching form:
- `#<number/>` (only digits after the `#`): set <source-kind/>
to `request`. The form *always* references the number of the forge and *never* a task id of ASE. Determine the remotes by running the command `git -C "<repo-root/>" remote` and set <remote/> to `upstream` if it exists, else to `origin` if it exists. Otherwise, expand the following:
<expand name="import-fail" arg1="neither remote `upstream` nor `origin` exists"></expand>
- A value starting with `http://` or `https://`: remove any
`?...` and `#...` suffix and match the remainder as `<repo-url/>/<path/>`, where <path/> is one of:
- `commit/<sha/>` or `-/commit/<sha/>`, or
`pull/<number/>/commits/<sha/>` or `pulls/<number/>/commits/<sha/>`: set <source-kind/> to `commit`.
- `pull/<number/>`, `pulls/<number/>`, or
`-/merge_requests/<number/>`, optionally followed by `.diff`, `.patch`, or `/<anything/>`: set <source-kind/> to `request`.
The URL is *valid* only if <repo-url/> matches the regexp `^https?://[A-Za-z0-9.:-]+(/[A-Za-z0-9._~-]+)+$`, <number/> consists of digits only, and <sha/> consists of 7 to 64 hexadecimal digits, which keeps it safe for being passed quoted to the `git` commands. If it is not valid or no form matches, expand the following:
<expand name="import-fail" arg1="unsupported URL: **<source/>**"></expand>
Determine the remotes by running the command `git -C "<repo-root/>" remote -v` and set <remote/> to the first remote whose fetch URL denotes the same host and repository path as <repo-url/> (ignoring the scheme, the user, and a trailing `.git`), so its access credentials are used, or to <repo-url/> otherwise.
- Anything else: set <source-kind/> to `file` and <patch/> to
the absolute path of <source/>, resolved against the current working directory. If this is no readable regular file, expand the following:
<expand name="import-fail" arg1="**<source/>** is neither a supported reference nor a patch file"></expand>
</step>
2. <step id="STEP 2: Prepare Patch">
1. <if condition="<source-kind/> is `request`">
1. Capture the *default branch* of the remote by running the command `git -C "<repo-root/>" fetch --quiet --no-tags "<remote/>" HEAD` and then the output of the command `git -C "<repo-root/>" rev-parse FETCH_HEAD` into <default-commit/>. If a command fails, expand the following:
<expand name=
Other skills on ase.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about ase-repo-import.
- Which coding agents can use ase-repo-import?
- ase-repo-import installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

