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