{"id":13801248,"url":"https://github.com/clj-jgit/clj-jgit","last_synced_at":"2026-02-21T18:03:26.376Z","repository":{"id":1468611,"uuid":"1708155","full_name":"clj-jgit/clj-jgit","owner":"clj-jgit","description":"Clojure wrapper around JGit","archived":false,"fork":false,"pushed_at":"2024-08-22T22:18:47.000Z","size":522,"stargazers_count":258,"open_issues_count":8,"forks_count":58,"subscribers_count":8,"default_branch":"master","last_synced_at":"2026-02-15T11:16:47.045Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clj-jgit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-05-05T20:01:23.000Z","updated_at":"2025-10-20T17:13:02.000Z","dependencies_parsed_at":"2024-01-08T18:03:36.027Z","dependency_job_id":"22033de4-bcc2-4b88-bd98-6f0fc0b1229c","html_url":"https://github.com/clj-jgit/clj-jgit","commit_stats":{"total_commits":266,"total_committers":30,"mean_commits":8.866666666666667,"dds":"0.43609022556390975","last_synced_commit":"ab8689c7c0e44b034bdc505468c5ddac41338bef"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/clj-jgit/clj-jgit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-jgit%2Fclj-jgit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-jgit%2Fclj-jgit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-jgit%2Fclj-jgit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-jgit%2Fclj-jgit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clj-jgit","download_url":"https://codeload.github.com/clj-jgit/clj-jgit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clj-jgit%2Fclj-jgit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29689644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T15:51:39.154Z","status":"ssl_error","status_checked_at":"2026-02-21T15:49:03.425Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":[],"created_at":"2024-08-04T00:01:20.892Z","updated_at":"2026-02-21T18:03:26.303Z","avatar_url":"https://github.com/clj-jgit.png","language":"Clojure","readme":"# clj-jgit\n\nClojure wrapper for using the JGit library to manipulate Git repositories in a \"pure Java\" fashion.\n\nYou can view latest auto-generated API documentation here: [clj-jgit.github.io/clj-jgit](http://clj-jgit.github.io/clj-jgit).\n\n## Installation ##\n\nLast stable version is available on [Clojars](http://clojars.org/clj-jgit).\n\n[![Clojars Project](http://clojars.org/clj-jgit/latest-version.svg)](http://clojars.org/clj-jgit)\n\nNote: If you don't plan on signing commits you may exclude `org.eclipse.jgit/org.eclipse.jgit.gpg.bc`, i.e. for lein:\n\n```\n:dependencies [[clj-jgit \"1.x.x\" :exclusions [org.eclipse.jgit/org.eclipse.jgit.gpg.bc]]]\n```\n\nNote: Java 11 or newer is required since `clj-jgit-1.0.2`\n\n## Quickstart Tutorial ##\n\nThis brief tutorial will show you how to:\n\n1. Clone a remote repository\n2. Create a local branch for your changes\n3. Checkout that branch, and\n4. Add and commit those changes\n5. Manage tags\n\n```clj\n;; First require or use the porcelain namespace, assuming a quick REPL session:\n(use 'clj-jgit.porcelain)\n\n;; Clone a repository into a folder of my choosing and keep the jgit repository object at my-repo\n(def my-repo (git-clone \"https://github.com/clj-jgit/clj-jgit.git\" :dir \"local-folder/clj-jgit\"))\n;=\u003e #'user/my-repo\n\n;; A bit redundant for a fresh repo, but always good to check the repo status\n;; before making any changes\n(git-status my-repo)\n;=\u003e {:added #{}, :changed #{}, :missing #{}, :modified #{}, :removed #{}, :untracked #{}}\n\n;; List existing branches\n(git-branch-list my-repo)\n;=\u003e (\"master\")\n\n;; Create a new local branch to store our changes\n(git-branch-create my-repo \"my-branch\")\n;=\u003e #\u003corg.eclipse.jgit.internal.storage.file.RefDirectory$LooseUnpeeled, Name: refs/heads/my-branch, ...\u003e\n\n;; Prove to ourselves that it was created\n(git-branch-list my-repo)\n;=\u003e (\"master\" \"my-branch\")\n\n;; Check out our new branch\n\n(git-checkout my-repo \"my-branch\")\n;=\u003e #\u003corg.eclipse.jgit.internal.storage.file.RefDirectory$LooseUnpeeled, Name: refs/heads/my-branch, ...\u003e\n\n;; Now go off and make your changes.\n;; For example, let's say we added a file \"foo.txt\" at the base of the project.\n(git-status my-repo)\n;=\u003e {:added #{}, :changed #{}, :missing #{}, :modified #{}, :removed #{}, :untracked #{\"foo.txt\"}}\n\n;; Add the file to the index\n(git-add my-repo \"foo.txt\")\n;=\u003e #object[org.eclipse.jgit.dircache.DirCache 0x3d9e3c3a \"org.eclipse.jgit.dircache.DirCache@3d9e3c3a\"]\n\n;; Check for status change\n(git-status my-repo)\n;=\u003e {:added #{\"foo.txt\"}, :changed #{}, :missing #{}, :modified #{}, :removed #{}, :untracked #{}}\n\n;; Now commit your changes, specifying author and committer if desired\n(git-commit my-repo \"Add file foo.txt\" :committer {:name \"Daniel Gregoire\" :email \"daniel@example.com\"})\n;=\u003e #object[org.eclipse.jgit.revwalk.RevCommit 0x7283e79c \"commit b6feeb3baab8fa0422390b2d2a737b1e21610401 -----p\"]\n\n;; Status clean\n(git-status my-repo)\n;=\u003e {:added #{}, :changed #{}, :missing #{}, :modified #{}, :removed #{}, :untracked #{}}\n\n(git-clean my-repo :dirs? true, :ignore? true)\n;=\u003e #{}\n\n;; You can also diff any part of the history\n(git-diff repo :old-commit \"ab6fc2\" :new-commit \"HEAD^2\")\n#object[java.io.ByteArrayOutputStream 0x753bc044 \"diff --git ...\n\n;; Blame\n(first (git-blame my-repo \"README.md\"))\n;=\u003e {:author {:name \"Ilya Sabanin\",\n              :email \"ilya@sabanin.com\",\n              :timezone #\u003cZoneInfo ...\u003e},\n     :commit #\u003cRevCommit commit fabdf5cf4abb72231461177238349c21e23fa46a 1352414190 -----p\u003e,\n     :committer {:name \"Ilya Sabanin\",\n                 :email \"ilya@wildbit.com\",\n                 :timezone #\u003cZoneInfo ...\u003e},\n     :line 66,\n     :source-path \"README.md\"}\n\n;; Tagging\n(git-tag-create my-repo \"v2.0.0\")\n;=\u003e #\u003corg.eclipse.jgit.internal.storage.file.RefDirectory$LooseUnpeeled, Name: refs/tags/v2.0.0, ObjectId: ...\n(git-tag-list my-repo)\n;=\u003e (\"v0.0.1\" \"v0.0.2\" \"v0.0.3\" \"v0.8.10\" \"v2.0.0\")\n(git-tag-delete my-repo \"v2.0.0\")\n;=\u003e [\"refs/tags/v2.0.0\"]\n(git-tag-list my-repo)\n;=\u003e (\"v0.0.1\" \"v0.0.2\" \"v0.0.3\" \"v0.8.10\")\n```\n\n## Detailed Usage ##\n\nCurrently, this library leverages the \"porcelain\" API exposed by JGit, which allows the use of methods/functions similar\nto the ones available on the command-line when using Git for \"basic\" purposes. If enough interest arises, this tool will\nwrap more of the lower-level functions in the future, but for now it acts as a basic Java replacement for the\ncommand-line version of Git.\n\n### Cloning a Repository ###\n\n```clj\n(git-clone \"url-to-repo\" :dir \"optional-local-folder\")\n```\n\n### Authentication\n\nPer default JGit expects a standard SSH key setup in `~/.ssh`, things should just work unless your key is password\nprotected. For further configuration any command may be wrapped with the `with-credentials` or `with-identity` macro:\n\n```clj\n;; Use custom SSH key location with key pw, also accept all unknown server keys and add them to `known_hosts` file:\n(with-identity {:name \"my.key\" :key-dir \"/some/path\" pw: \"$ecRet\" :trust-all? true}\n  (git-push my-repo :tags true))\n\n;; Use user/pw auth instead of key based auth\n(with-credentials {:login \"someuser\" :pw \"$ecReT\"}\n  (git-pull my-repo))\n```\n\n### GPG signing of Commits\n\nA working GPG key setup is required for signing:\n\n```\n$ gpg --gen-key\n$ gpg --fingerprint\npub   rsa4096 2019-12-01 [SC]\n      20AB A393 B992 6661 63BE  1346 5022 F878 A751 2BA8 \u003c- the fingerprint\nuid           [ultimate] Foo Bar \u003cfoo@bar.net\u003e\nsub   rsa4096 2018-12-01 [E]\n```\n\nGPG signing is used if:\n\n* enabled per commit: `(git-commit ... :signing? true :signing-key \"A7512BA8\")`\n* git is configured via `commit.gpgSign = true`, i.e.:\n\n```\n(-\u003e my-repo\n    git-config-load\n    (git-config-set \"commit.gpgSign\" true)\n    (git-config-set \"user.signingKey\" \"A7512BA8\")\n    git-config-save)\n```\n\nNote: You may use as few as 2 digits of the fingerprint as long the id is unique in your keyring, no spaces.\n\nIf GPG-signing a commit is requested but no GpgSigner is installed, an `org.eclipse.jgit.api.errors.ServiceUnavailableException` will be thrown. \n\n### Loading an Existing Repository ###\n\nIn order to use most of the functions in JGit's API, you need to have a repository object to play with. Here are ways to\nload an existing repository:\n\n```clj\n;; Simples method is to point to the folder\n(load-repo \"path-to-git-repo-folder\")\n;; In order to remain consistent with JGit's default behavior,\n;; you can also point directly at the .git folder of the target repo\n(load-repo \"path-to-git-repo-folder/.git\")\n```\n\nThis function throws a `FileNotFoundException` if the directory in question does not exist.\n\n### Querying repository\n\nThis uses internal JGit API, so it may require some additional knowledge of JGit.\n\n```clj\n(ns clj-jgit.porcelain)\n\n;; Log\n(git-log my-repo :max-count 1)\n;=\u003e ({:id #object[org.eclipse.jgit.revwalk.RevCommit], :msg \"fix git-commit docs, typo in readme\", :author ...\n\n;; Log for range\n(git-log my-repo :since \"5a7b97\" :until \"master^1\")\n;=\u003e ...\n```\n\n```clj\n;; This macro allows you to create a universal handler with name \"repo\"\n(with-repo \"/path/to/a/repo\"\n  (git-log repo))\n```\n\n```clj\n;; Notes Add\n(git-notes-add my-repo \"my note\")\n;=\u003e (#object[org.eclipse.jgit.notes.Note 0x1237ddce \"Note[3c14d1f8917761rc71db03170866055ef88b585f -\u003e 10500018fca9b3425b50de67a7258a12cba0c076]\"])\n```\n\n```clj\n;; Notes Append\n(git-notes-add my-repo \"my appended note\")\n;=\u003e (#object[org.eclipse.jgit.notes.Note 0x1237ddce \"Note[3c14d1f8917761rc71db03170866055ef88b585f -\u003e 10500018fca9b3425b50de67a7258a12cba0c076]\"])\n```\n\n```clj\n;; Notes List\n(git-notes my-repo)\n;=\u003e (#object[org.eclipse.jgit.notes.Note 0x1237ddce \"Note[3c14d1f8917761rc71db03170866055ef88b585f -\u003e 10500018fca9b3425b50de67a7258a12cba0c076]\"])\n```\n\n```clj\n;; Notes Show\n(git-notes-show my-repo)\n;=\u003e [\"my note\" \"my appended note\"]\n```\n\n```clj\n(ns clj-jgit.querying)\n\n;; Creates a RevWalk instance needed to traverse the commits for the repo.\n;; Commits found through a RevWalk can be compared and used only with other\n;; commits found with a same RevWalk instance.\n(def rev-walk (new-rev-walk repo))\n\n;; List of pairs of branch refs and RevCommits associated with them\n(branch-list-with-heads repo rev-walk)\n;=\u003e ([#\u003corg.eclipse.jgit.storage.file.RefDirectory$LooseUnpeeled, Name: refs/heads/master, ObjectId: 3b9c98bc151bb4920f9799cfa6c32c536ed64348\u003e\n      #\u003cRevCommit commit 3b9c98bc151bb4920f9799cfa6c32c536ed64348 1339922123 -----p\u003e])\n\n;; Find an ObjectId instance for a repo and given commit-ish, tree-ish or blob\n(def commit-obj-id (resolve-object repo \"38dd57264cf5c05fb77211c8347d1f16e4474623\"))\n;=\u003e #\u003cObjectId AnyObjectId[38dd57264cf5c05fb77211c8347d1f16e4474623]\u003e\n\n;; Show all the branches where commit is present\n(branches-for repo commit-obj-id)\n;=\u003e (\"refs/heads/master\")\n\n;; List of all revision objects in the repository, for all branches\n(rev-list repo)\n;=\u003e #\u003cRevCommitList [commit 3b9c98bc151bb4920f9799cfa6c32c536ed64348 1339922123 ----sp, ... ]\u003e\n```\n\n```clj\n;; Gather information about specific commit\n(commit-info repo (find-rev-commit repo rev-walk \"38dd57264cf\"))\n\n; Returns\n{:repo #\u003cGit org.eclipse.jgit.api.Git@21d306ef\u003e,\n:changed_files [[\".gitignore\" :add]\n                [\"README.md\" :add]\n                [\"project.clj\" :add]\n                [\"src/clj_jgit/core.clj\" :add]\n                [\"src/clj_jgit/util/print.clj\" :add]\n                [\"test/clj_jgit/test/core.clj\" :add]],\n:raw #\u003cRevCommit commit 38dd57264cf5c05fb77211c8347d1f16e4474623 1304645414 ----sp\u003e,\n:author \"Daniel Gregoire\",\n:email \"daniel.l.gregoire@gmail.com\",\n:message \"Initial commit\",\n:branches (\"refs/heads/master\"),\n:merge false,\n:time #\u003cDate Fri May 06 09:30:14 KRAT 2011\u003e,\n:id \"38dd57264cf5c05fb77211c8347d1f16e4474623\"}\n\n;; You can also combine this with Porcelain API, to get a list of all commits in a repo with detailed information\n(with-repo \"/path/to/repo.git\"\n  (map #(commit-info repo %) (git-log repo)))\n\n;; Branches lookup is an expensive operation, especially for repos with many branches.\n;; commit-info spends most of it time trying to detect list of branches commit belongs to.\n\n; If you don't require branches list in commit info, you can use:\n(commit-info-without-branches repo rev-walk rev-commit)\n\n; If you want branches list, but want it to work faster, you can generate commit map that turns\n; commits and branches into a map for fast branch lookups. In real-life this can give 30x-100x speed\n; up when you are traversing lists of commits, depending on amount of branches you have.\n(let [rev-walk (new-rev-walk repo)\n      commit-map (build-commit-map repo rev-walk)\n      commits (git-log repo)]\n  (map (partial commit-info repo rev-walk commit-map) commits))\n```\n### Diffing ###\n\nJGit also has excellent diffing support that can be used without any Git context:\n\n```clj\n(ns clj-jgit.diff)\n\n;; Diff two text files and write a diff-style patch to foo.patch\n(-\u003e (diff-string-formatted (slurp \"foo_org.txt\") (slurp \"foo_new.txt\")\n      :output-stream (clojure.java.io/output-stream \"foo.patch\") :context-lines 4)\n    .close)\n```\n\nSee `clj-jgit.diff` for more advanced use cases.\n\n### Contribute ###\n\nIf you want to contribute just fork the repository, work on the code, cover it with tests and submit a pull request through Github.\n\nAny questions related to clj-jgit can be discussed in the [Google Group](https://groups.google.com/forum/#!forum/clj-jgit).\n\n## Caveat Windows Users\n\nCygwin will cause this library to hang. Make sure to remove `C:\\cygwin\\bin` from your PATH before attempting to use this library.\n\n## License\n\nCopyright (C) 2019 FIXME\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","funding_links":[],"categories":["Version Control Management"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclj-jgit%2Fclj-jgit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclj-jgit%2Fclj-jgit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclj-jgit%2Fclj-jgit/lists"}