GitHub import
Paste a public GitHub repository URL into the import panel and press Fetch, and FileConcat fetches the file tree on demand. It needs no GitHub account, and no server sits in between. The same panel opens GitHub repo to text, next to what 60 public repositories weigh in tokens.
Supported URL shapes
The GitHub adapter at packages/core/src/sources/adapters/github.ts
parses these shapes:
https://github.com/owner/repo
https://github.com/owner/repo/tree/branch
https://github.com/owner/repo/tree/branch/subdirectory
https://github.com/owner/repo/blob/branch/path/to/file.ts
A link copied from the address bar works as it is: www., a trailing
slash, .git, ?tab=readme-ov-file and #readme are all ignored. Any
other page under the repository, such as its issues, imports the
repository itself. The optional branch defaults to the repository's
default branch when omitted. When a subdirectory or a file is included,
only files at or under that path are imported.
A branch name containing a slash does not work. The branch segment
stops at the first slash, so tree/release/2.0 is read as the branch
release with the subdirectory 2.0. The URL itself is ambiguous and
GitHub resolves it on its own servers; FileConcat does not. If a branch
named release also exists you get that branch's 2.0 directory
instead of an error. Import the default branch instead.
Bitbucket import is the one source here that
handles slashed branch names, because it resolves the ref to a commit
before it lists anything.
What one import costs in API requests
One request to api.github.com per import: the recursive file tree,
read at HEAD when the URL names no branch, which is the default
branch.
File contents do not go through that API at all. They stream from
raw.githubusercontent.com, one request per file, twelve at a time
(DEFAULT_DOWNLOAD_CONCURRENCY in
packages/core/src/sources/pooled-map.ts).
GitHub's documented primary rate limit for unauthenticated REST requests is 60 per hour, per IP address (GitHub, Rate limits for the REST API, read September 2026). Because the per-file downloads are served by a different host, the number of files in a repository is not what exhausts that budget. Repeated imports are.
When a request is denied, the message in the import panel comes from
classifyResponseError
(packages/core/src/sources/adapters/_errors.ts). Status 401, 403 and
429 each carry their own wording, so "rate limited" reads differently
from "private repository". When the limit is used up, the message names
the time GitHub says it resets and links GitHub's own ZIP of the
repository. Download it and drop it into FileConcat: a dropped ZIP is
unpacked in the browser and costs no API request.
For private repositories, download the project to your computer and drop the folder into FileConcat instead. Token-authenticated imports are not shipped at the time of writing.
Very large repositories need the ZIP
GitHub caps a recursive tree at 100,000 entries and 7 MB, and sets
truncated on the response when the listing it returned is incomplete
(GitHub, REST API endpoints for Git trees, read September 2026).
FileConcat does not bundle a partial repository. GitHub's archive download does not allow requests from other sites, so a browser tool cannot fetch it on your behalf. The import stops with a message and a link to the repository's ZIP: download it and drop it into FileConcat.
When a download fails
A file that fails to download does not fail the import. Each failure is recorded with its path and reason, and the rest of the bundle is assembled without it. Compare the file count in the result against what you expected.
A 429 whose Retry-After hint fits inside 30 seconds is retried once,
automatically. Anything longer surfaces as an error rather than a long
silent wait.
Raw URLs
Raw file URLs like https://raw.githubusercontent.com/owner/repo/...
are not handled by the GitHub adapter. They go to the URL fallback
adapter instead, which downloads the single file you point it at and
shows it in the result screen. Use this for "give me one file from
GitHub" cases.
Gists
GitHub Gists are handled by a separate adapter that lives next to the others. URL shape:
https://gist.github.com/owner/gistId
The owner segment is required by the regex; bare gist URLs without
the owner part are not matched. Gists are flat (no subdirectories);
every file in the gist comes in together.
The same adapter also matches GitLab Snippet URLs; see GitLab import for those.
See also
- GitLab import and Bitbucket import, which reach the same result through very different request budgets.
- File filtering to narrow the imported tree before assembling the output.
- Token estimation to keep the import inside your model's context window.