{"id":47763774,"url":"https://github.com/alexewerlof/ja","last_synced_at":"2026-04-03T05:57:55.168Z","repository":{"id":35151616,"uuid":"213355036","full_name":"alexewerlof/ja","owner":"alexewerlof","description":"A simple CLI to read files from git repositories","archived":false,"fork":false,"pushed_at":"2023-01-06T02:11:47.000Z","size":707,"stargazers_count":3,"open_issues_count":13,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-29T00:29:59.847Z","etag":null,"topics":["cli","copy-paste","github","github-enterprise"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ja","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexewerlof.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-07T10:31:57.000Z","updated_at":"2025-08-24T05:53:05.000Z","dependencies_parsed_at":"2023-01-15T14:51:51.630Z","dependency_job_id":null,"html_url":"https://github.com/alexewerlof/ja","commit_stats":null,"previous_names":["alexewerlof/ja","userpixel/ja"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/alexewerlof/ja","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexewerlof%2Fja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexewerlof%2Fja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexewerlof%2Fja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexewerlof%2Fja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexewerlof","download_url":"https://codeload.github.com/alexewerlof/ja/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexewerlof%2Fja/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31337802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T04:42:29.251Z","status":"ssl_error","status_checked_at":"2026-04-03T04:42:12.667Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","copy-paste","github","github-enterprise"],"created_at":"2026-04-03T05:57:50.097Z","updated_at":"2026-04-03T05:57:55.158Z","avatar_url":"https://github.com/alexewerlof.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![JA logo](https://docs.google.com/drawings/d/e/2PACX-1vSBUyX71SUQtpisST4EVWQ9h-tXihJpEVQ17D4boeM1l_QaR4s1YXpsGjqO-jIEIEB4M7mww1hS8x_q/pub?w=300)\n\n[![GitHub issues](https://img.shields.io/github/issues/userpixel/ja)](https://github.com/userpixel/ja/issues)\n[![GitHub forks](https://img.shields.io/github/forks/userpixel/ja)](https://github.com/userpixel/ja/network)\n[![GitHub stars](https://img.shields.io/github/stars/userpixel/ja)](https://github.com/userpixel/ja/stargazers)\n[![GitHub license](https://img.shields.io/github/license/userpixel/ja)](https://github.com/userpixel/ja)\n\n# Introduction\n\nA tiny utility for copying a file from a remote repo into the current one.\n\nThink of it as `curl` for Github.\n\n* Supports public/private Github as well as Github Enterprise\n* Lightweight\n* Descriptive error messages\n\n## Use case\n\nEvery repo has a few boilerplate files that can be recycled in other repos as is.\nFor example:\n\n* `.editorconfig`\n* `.gitignore`\n* `.github/issue_template.md`\n* `.github/pull_request_template.md`\n* `.eslintrc`\n* `.eslintignore`\n* `jest.config.js`\n* `...`\n\nUsually these are copy/pasted as needed but then if the source file changes, all these copies need to be updated as well.\n\n**Bugs reproduce by copy/paste and take shelter in human errors. So if you have to copy/paste, at least automate it.**\n\n- `curl` does the job for public Github repos, but what about the private/enterprise ones? \nBesides, if there is more than one file that needs to be copied, that knowledge needs to live somewhere.\n- some people use a monorepo to avoid this duplication and deal with `lerna` or other tools\n- some even use git submodules\n\nSay hello to **ja**: it stands for **just add**!\n\n## Usage\n\n```\n# You can install it globally\n$ npm i -g ja\n\n# Then run it in the destination repo\n$ ja\n\n# You can also run it with npx\n$ npx ja\n```\n\nIt reads its config from a text file named `.ja` in the root of the destination repo.\n\nEach line states the source and optionally the destination.\n\nExample:\n\n```\n# Copy the .gitignore from a remote folder to this one\nhttps://github.com/userpixel/micromustache/blob/master/.gitignore\n# Copy the issue template to the .github folder\nhttps://github.com/userpixel/micromustache/blob/master/.github/ISSUE_TEMPLATE.md \u003e .github/ISSUE_TEMPLATE.md\n```\n\nWhen you run `ja`:\n\n* It'll look for its config file (`.ja`) in the same directory (it'll exit with an error if it cannot find it).\n* It parses the config, and validates it.\n* It tries to figure out the \"raw\" address for each source URL. For example if the source URL looks like `https://github.com/userpixel/ja/blob/master/README.md`, it'll try to fetch it from `https://raw.githubusercontent.com/userpixel/ja/master/README.md`\n* If there was no problem fetching the file, it write the file.\n  - If the destination folder doesn't exist, it creates it\n  - If you already have the destination file, it'll rewrite it. No file permission will be changed. You can see the diff using `git diff` or `git status`. If the overwritten file has exactly the same content, git doesn't consider them to be changed\n  - Obviously if the fetch step fails, it will not write any files.\n  - Currently `ja` only supports **utf-8** format\n\n**Commit all your changes before running `ja` because it'll overwrite the local files.**\n\n## Config file\n\nThe config file is named `.ja`:\n\n* Each line simply contains a URL and a optionally a relative local file path (separated by `\u003e`).\n* Currently you need to specify each file explicitly. It's not possible to fetch a whole directory like `.github`.\n* The local file path is relative to the current directory where the `.ja` file is located and cannot point to a parent directory.\n* For security reasons no absolute path is allowed.\n* For security reasons the local file name *cannot* point to any directory that is the parent of the directory where the `.ja` file is located.\n* Empty lines and lines beginning with `#` will be ignored.\n\n# Token\n\nIf the source is a **Github Enterprise** or a **private repository**, you'll need a token.\n`ja` expects the token in an environment variable named after the host name of the source URL.\n\nFor example the token for fetching a file from a private repo on `github.com`, should be in the `GITHUB_COM_TOKEN` environment variable.\n\nIf your Github Enterprise is hosted under `github.companyname.io`, the env var is `GITHUB_COMPANYNAME_IO_TOKEN`.\n\nThere are many ways to pass an environment variable to an application:\n\n* You can put the token in an `.env` file next to your `.ja` file (`ja` reads `./.env`). This is the smoothest method, plus is localizes the knowledge about the token to the repo that uses it.\n* You can put the token in your `~/.bashrc` (Linux) or `~/.bash_profile` (Mac)\n* You can pass the token directly when running `ja` like this: `GITHUB_COM_TOKEN=328948kksjkafhdskjf ja` (note that this will leave a trace in your terminal history. In Bash you can start the command with one space to skip adding it to the history)\n\n### Generating a token\n\nThis is a one-time process:\n\n1. Click on your github profile and go to [**Settings \u003e Developer settings \u003e Personal access tokens** and click **Generate new token**](https://github.com/settings/tokens/new)\n1. Give your token a name and for the scope, only choose **public_repo** (that's all that is needed)\n1. Press the **Generate token** button. Put this token where `ja` can find it. _Make sure to copy your token to a safe place because it's the last time you see it (don't worry you can always go there and make a new one)_\n\n## Test\n\nWe use [Jest](https://jestjs.io/).\n\n```\n# Install dependencies and run all tests\n$ npm it\n```\n\n## Debug\n\nWe use [Debug](https://www.npmjs.com/package/debug).\n\nRun the CLI showing debug info:\n\n```\n$ DEBUG=* node cli/ja.js\n```\n\n## License\n\nMIT\n\n---\n\n_Made in Sweden 🇸🇪 by [@alexewerlof](https://mobile.twitter.com/alexewerlof)_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexewerlof%2Fja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexewerlof%2Fja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexewerlof%2Fja/lists"}