{"id":20585691,"url":"https://github.com/chronoxor/gil","last_synced_at":"2025-08-21T08:30:33.667Z","repository":{"id":57434314,"uuid":"162496450","full_name":"chronoxor/gil","owner":"chronoxor","description":"Gil is a git links tool to manage complex recursive repositories dependencies with cross references and cycles","archived":false,"fork":false,"pushed_at":"2025-07-15T19:13:10.000Z","size":465,"stargazers_count":75,"open_issues_count":6,"forks_count":11,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-26T05:39:29.115Z","etag":null,"topics":["dependency-links","devops-tools","git","git-addons","submodule","subtree"],"latest_commit_sha":null,"homepage":"","language":"Python","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/chronoxor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-12-19T22:14:38.000Z","updated_at":"2025-07-15T19:13:13.000Z","dependencies_parsed_at":"2023-11-17T23:07:24.173Z","dependency_job_id":"46628c25-793b-4b43-a4c8-fe006300b815","html_url":"https://github.com/chronoxor/gil","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/chronoxor/gil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2Fgil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2Fgil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2Fgil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2Fgil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chronoxor","download_url":"https://codeload.github.com/chronoxor/gil/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2Fgil/sbom","scorecard":{"id":281659,"data":{"date":"2025-08-11","repo":{"name":"github.com/chronoxor/gil","commit":"eff887cd410311cc265455b5af2be0b3e7e9ecb7"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":1,"reason":"2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-linux-clang.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-linux-clang.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-linux-clang.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-linux-clang.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-linux-gcc.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-linux-gcc.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-linux-gcc.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-linux-gcc.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-macos.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-macos.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-macos.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-macos.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-windows-cygwin.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-cygwin.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-windows-cygwin.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-cygwin.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-windows-mingw.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-mingw.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-windows-msys2.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-msys2.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-windows-msys2.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-msys2.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-windows-vs.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-vs.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-windows-vs.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/build-windows-vs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/doxygen.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/chronoxor/gil/doxygen.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/build-linux-clang.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/build-linux-gcc.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/build-macos.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/doxygen.yml:30","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 third-party GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build-linux-clang.yml:1","Warn: no topLevel permission defined: .github/workflows/build-linux-gcc.yml:1","Warn: no topLevel permission defined: .github/workflows/build-macos.yml:1","Warn: no topLevel permission defined: .github/workflows/build-windows-cygwin.yml:1","Warn: no topLevel permission defined: .github/workflows/build-windows-mingw.yml:1","Warn: no topLevel permission defined: .github/workflows/build-windows-msys2.yml:1","Warn: no topLevel permission defined: .github/workflows/build-windows-vs.yml:1","Warn: no topLevel permission defined: .github/workflows/doxygen.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T16:00:57.780Z","repository_id":57434314,"created_at":"2025-08-17T16:00:57.780Z","updated_at":"2025-08-17T16:00:57.780Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271449010,"owners_count":24761582,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["dependency-links","devops-tools","git","git-addons","submodule","subtree"],"created_at":"2024-11-16T07:08:59.144Z","updated_at":"2025-08-21T08:30:33.343Z","avatar_url":"https://github.com/chronoxor.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Gil (git links) tool\n\n[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n[![Release](https://img.shields.io/github/release/chronoxor/gil.svg?sort=semver)](https://github.com/chronoxor/gil/releases)\n\u003cbr/\u003e\n[![Linux (clang)](https://github.com/chronoxor/gil/actions/workflows/build-linux-clang.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-linux-clang.yml)\n[![Linux (gcc)](https://github.com/chronoxor/gil/actions/workflows/build-linux-gcc.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-linux-gcc.yml)\n[![MacOS](https://github.com/chronoxor/gil/actions/workflows/build-macos.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-macos.yml)\n\u003cbr/\u003e\n[![Windows (Cygwin)](https://github.com/chronoxor/gil/actions/workflows/build-windows-cygwin.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-windows-cygwin.yml)\n[![Windows (MSYS2)](https://github.com/chronoxor/gil/actions/workflows/build-windows-msys2.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-windows-msys2.yml)\n[![Windows (MinGW)](https://github.com/chronoxor/gil/actions/workflows/build-windows-mingw.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-windows-mingw.yml)\n[![Windows (Visual Studio)](https://github.com/chronoxor/gil/actions/workflows/build-windows-vs.yml/badge.svg)](https://github.com/chronoxor/gil/actions/workflows/build-windows-vs.yml)\n\nGil is a git links tool to manage complex recursive repositories dependencies\nwith cross references and cycles.\n\nThis tool provides a solution to the [git recursive submodules dependency problem](https://github.com/chronoxor/gil#recursive-submodules-problem).\n\n# Contents\n  * [Requirements](#requirements)\n  * [Setup](#setup)\n  * [Sample](#sample)\n  * [Usage](#usage)\n  * [Motivation: git submodules vs git links](#motivation-git-submodules-vs-git-links)\n    * [Git submodules management](#git-submodules-management)\n    * [Recursive submodules problem](#recursive-submodules-problem)\n  * [Motivation: git subtrees vs git links](#motivation-git-subtrees-vs-git-links)\n    * [Git subtrees management](#git-subtrees-management)\n    * [Subtrees manual management problem](#subtrees-manual-management-problem)\n\n# Requirements\n* Linux\n* MacOS\n* Windows\n* [git](https://git-scm.com)\n* [python3](https://www.python.org)\n\n# Setup\n\n```shell\nsudo pip3 install --prefix /usr/local gil\n```\n\n# Sample\nConsider we have the following git repository dependency graph:\n\n![gil sample](https://github.com/chronoxor/gil/raw/master/images/sample.png)\n\nWhere:\n* Blue nodes are third-party components\n* Green nodes are components that we develop\n* Edges show components dependency with a branch\n\n### Root .gitlinks file\nIn order to describe the sample model with git links we have to define root\n.gitlinks file in your sample repository with a following content:\n```shell\n# Projects\nCppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master\nCppCommon CppCommon https://github.com/chronoxor/CppCommon.git master\nCppLogging CppLogging https://github.com/chronoxor/CppLogging.git master\n\n# Modules\nCatch2 modules/Catch2 https://github.com/catchorg/Catch2.git master\ncpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master\nfmt modules/fmt https://github.com/fmtlib/fmt.git master\nHdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master\nzlib modules/zlib https://github.com/madler/zlib.git master\n\n# Scripts\nbuild scripts/build https://github.com/chronoxor/CppBuildScripts.git master\ncmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master\n```\n\nEach line describe git link in the following format:\n1. Unique name of the repository\n2. Relative path of the repository (started from the path of .gitlinks file)\n3. Git repository which will be used in `git clone` command\n4. Repository branch to checkout\n5. (Optional) Relative path in the base repository\n6. (Optional) Relative path in the target repository\n\nEmpty line or line started with `#` are not parsed (treated as comment).\n\n### CppBenchmark .gitlinks file\nCppBenchmark .gitlinks file should be committed into the CppBenchmark project\nand have the following content:\n```shell\n# Modules\nCatch2 modules/Catch2 https://github.com/catchorg/Catch2.git master\ncpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master\nHdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master\nzlib modules/zlib https://github.com/madler/zlib.git master\n\n# Scripts\nbuild build https://github.com/chronoxor/CppBuildScripts.git master\ncmake cmake https://github.com/chronoxor/CppCMakeScripts.git master\n```\n\n### CppCommon .gitlinks file\nCppCommon .gitlinks file should be committed into the CppCommon project and\nhave the following content:\n```shell\n# Modules\nCatch2 modules/Catch2 https://github.com/catchorg/Catch2.git master\nCppBenchmark modules/CppBenchmark https://github.com/chronoxor/CppBenchmark.git master\nfmt modules/fmt https://github.com/fmtlib/fmt.git master\n\n# Scripts\nbuild build https://github.com/chronoxor/CppBuildScripts.git master\ncmake cmake https://github.com/chronoxor/CppCMakeScripts.git master\n```\n\n### CppLogging .gitlinks file\nCppLogging .gitlinks file should be committed into the CppLogging project and\nhave the following content:\n```shell\n# Modules\nCatch2 modules/Catch2 https://github.com/catchorg/Catch2.git master\ncpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master\nCppBenchmark modules/CppBenchmark https://github.com/chronoxor/CppBenchmark.git master\nCppCommon modules/CppCommon https://github.com/chronoxor/CppCommon.git master\nzlib modules/zlib https://github.com/madler/zlib.git master\n\n# Scripts\nbuild build https://github.com/chronoxor/CppBuildScripts.git master\ncmake cmake https://github.com/chronoxor/CppCMakeScripts.git master\n```\n\n### Update the repository\nFinally you have to update your root sample repository:\n```shell\n# Clone and link all git links dependencies from .gitlinks file\ngil clone\ngil link\n\n# The same result with a single command\ngil update\n```\n\nAs the result you'll clone all required projects and link them to each other\nin a proper way:\n```shell\nWorking path: ~/gil/sample\n...\nUpdating git links: ~/gil/sample/.gitlinks\nUpdating git links: ~/gil/sample/CppBenchmark/.gitlinks\nUpdate git link: ~/gil/sample/modules/Catch2 -\u003e ~/gil/sample/CppBenchmark/modules/Catch2\nUpdate git link: ~/gil/sample/modules/cpp-optparse -\u003e ~/gil/sample/CppBenchmark/modules/cpp-optparse\nUpdate git link: ~/gil/sample/modules/HdrHistogram -\u003e ~/gil/sample/CppBenchmark/modules/HdrHistogram\nUpdate git link: ~/gil/sample/modules/zlib -\u003e ~/gil/sample/CppBenchmark/modules/zlib\nUpdate git link: ~/gil/sample/scripts/build -\u003e ~/gil/sample/CppBenchmark/build\nUpdate git link: ~/gil/sample/scripts/cmake -\u003e ~/gil/sample/CppBenchmark/cmake\nUpdating git links: ~/gil/sample/CppCommon/.gitlinks\nUpdate git link: ~/gil/sample/modules/Catch2 -\u003e ~/gil/sample/CppCommon/modules/Catch2\nUpdate git link: ~/gil/sample/CppBenchmark -\u003e ~/gil/sample/CppCommon/modules/CppBenchmark\nUpdate git link: ~/gil/sample/modules/fmt -\u003e ~/gil/sample/CppCommon/modules/fmt\nUpdate git link: ~/gil/sample/scripts/build -\u003e ~/gil/sample/CppCommon/build\nUpdate git link: ~/gil/sample/scripts/cmake -\u003e ~/gil/sample/CppCommon/cmake\nUpdating git links: ~/gil/sample/CppLogging/.gitlinks\nUpdate git link: ~/gil/sample/modules/Catch2 -\u003e ~/gil/sample/CppLogging/modules/Catch2\nUpdate git link: ~/gil/sample/modules/cpp-optparse -\u003e ~/gil/sample/CppLogging/modules/cpp-optparse\nUpdate git link: ~/gil/sample/CppBenchmark -\u003e ~/gil/sample/CppLogging/modules/CppBenchmark\nUpdate git link: ~/gil/sample/CppCommon -\u003e ~/gil/sample/CppLogging/modules/CppCommon\nUpdate git link: ~/gil/sample/modules/zlib -\u003e ~/gil/sample/CppLogging/modules/zlib\nUpdate git link: ~/gil/sample/scripts/build -\u003e ~/gil/sample/CppLogging/build\nUpdate git link: ~/gil/sample/scripts/cmake -\u003e ~/gil/sample/CppLogging/cmake\n```\n\nAll repositories will be checkout to required branches.\n\nIf content of any .gitlinks changes it is required to run `gil update` command\nto re-update git links - new repositories will be cloned and linked properly!\n\n### Commit, push, pull\nYou can work and change any files in your repositories and perform all git\noperations for any repository to commit and contribute your changes.\n\nIf you want to commit all changes in some repository with all changes in\nchild linked repositories you can do it with a single command:\n```shell\ngil commit -a -m \"Some big update\"\n```\n\nThis command will visit the current and all child repositories and perform\nthe corresponding `git commit` command with provided arguments.\n\nPlease note that gil command visit only child repositories that are described\nin .gitlinks file no parent dependencies will be processed. For this reason\nif you want to commit, pull or push all repositories the corresponding command\nshould be run in the root directory where root .gitlinks is placed.\n\nPull, push commands works in a similar way:\n```shell\ngil pull\ngil push\n```\n\n### Build\nPlease investigate and follow links in the sample repository in order to\nunderstand the logic how gil (git links) tool manages dependencies.\n\nFinally you can build sample projects with provided build scripts:\n* `~/gil/sample/CppBenchmark/build`\n* `~/gil/sample/CppCommon/build`\n* `~/gil/sample/CppLogging/build`\n\nAdditionally each module can be cloned and successfully build without root\nrepository. In this case local .gitlinks file will be used to resolve all\ndependencies!\n\n# Usage\nGil (git links) tool supports the following commands:\n```\nusage: gil command arguments\nSupported commands:\n        help - show this help\n        version - show version\n        context - show git links context\n        clone [args] - clone git repositories\n        link - link git repositories\n        update - update git repositories (clone \u0026 link)\n        pull [args] - pull git repositories\n        push [args] - push git repositories\n        commit [args] - commit git repositories\n        status [args] - show status of git repositories\n```\n\n* `gil context` - command will show the current git link context of the current directory;\n* `gil clone [args]` - clone all repositories that are missed in the current context;\n* `gil link` - link all repositories that are missed in the current context;\n* `gil update` - clone and link in a single operation;\n* `gil pull [args]` - pull all repositories in the current directory;\n* `gil push [args]` - push all repositories in the current directory;\n* `gil commit [args]` - commit all repositories in the current directory;\n* `gil status [args]` - show status of all repositories in the current directory;\n\n# Motivation: git submodules vs git links\nGit submodules allow to get the same idea of repositories dependency, but with\na serious limitation - git submodules degrade to tree-like recursive structure\nwith repositories duplication.\n\n## Git submodules management\nGit submodules provides several operations to manage repositories dependency.\n\n### Add submodule dependency\n```shell\n# Add git submodule of 'master' branch into the relative directory 'modules/zlib'\ngit submodule add -b master https://github.com/madler/zlib.git modules/zlib\n```\n\n### Initialize submodules\n```shell\n# Update all submodules in the current repository\ngit submodule update --init --recursive --remote\n```\n\n### Refresh submodules from remote repositories\n```shell\ngit pull\ngit submodule update --init --recursive --remote\ngit pull --recurse-submodules\ngit submodule foreach \"(git checkout master; git pull)\"\n```\n\n### Synchronize submodules with remote repositories\n```shell\ngit pull\ngit submodule update --init --recursive --remote\ngit pull --recurse-submodules\ngit submodule foreach \"(git checkout master; git pull)\"\ngit add --all\ngit commit -m \"Submodule Sync\"\ngit push\n```\n\n### Remove submodule dependency\n```shell\n# Remove git submodule from the relative directory 'modules/zlib'\ngit submodule deinit -f -- modules/zlib\nrm -rf .git/modules/modules/zlib\ngit rm -f modules/zlib\n```\n\n## Recursive submodules problem\nGit submodules representation of the described sample repository is the\nfollowing:\n```shell\n~/gil/sample/CppBenchmark\n~/gil/sample/CppBenchmark/build\n~/gil/sample/CppBenchmark/cmake\n~/gil/sample/CppBenchmark/modules/Catch2\n~/gil/sample/CppBenchmark/modules/cpp-optparse\n~/gil/sample/CppBenchmark/modules/HdrHistogram\n~/gil/sample/CppBenchmark/modules/zlib\n~/gil/sample/CppCommon\n~/gil/sample/CppCommon/build - DUPLICATE!\n~/gil/sample/CppCommon/cmake - DUPLICATE!\n~/gil/sample/CppCommon/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/build - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/cmake - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/modules/cpp-optparse - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/modules/HdrHistogram - DUPLICATE!\n~/gil/sample/CppCommon/modules/CppBenchmark/modules/zlib - DUPLICATE!\n~/gil/sample/CppCommon/modules/fmt\n~/gil/sample/CppLogging\n~/gil/sample/CppLogging/build - DUPLICATE!\n~/gil/sample/CppLogging/cmake - DUPLICATE!\n~/gil/sample/CppLogging/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppLogging/modules/cpp-optparse - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/build - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/cmake - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/modules/cpp-optparse - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/modules/HdrHistogram - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark/modules/zlib - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/build - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/cmake - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/build - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/cmake - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/modules/Catch2 - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/modules/cpp-optparse - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/modules/HdrHistogram - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark/modules/zlib - DUPLICATE!\n~/gil/sample/CppLogging/modules/zlib - DUPLICATE!\n```\n\nOnly 10 of 41 repositories are unique. Other duplicates each other multiple\ntimes. Moreover some nested repositories included recursively! CppLogging\nproject has the third level of nesting (`CppLogging -\u003e CppCommon -\u003e CppBenchmark`).\n\nEach new level heavily increases the rate of duplication. As the result all\nsubmodule management operations becomes slow and requires multiple executions\nof synchronize script to pass changes from top level to the bottom. The count\nof synchronizations in the worst case equals to recursive levels count.\n\nAll this issues are solved with gil (git links) tool which allows to link all\nrequired repositories together avoiding duplication. The tool also provides\noperations to manage changes in all repositories with a [simple easy to use\ncommands](https://github.com/chronoxor/gil#usage).\n\n# Motivation: git subtrees vs git links\nGit subtrees is an easy to use alternative to git submodules. It allows to nest\none repository inside another as a sub-directory.\n\nFrom the one side git subtrees are very lightweight with simple workflow. They\ndon't add any metadata files like git submodule does (i.e., .gitmodule) and\nsub-project's code is available right after the clone of the super project is\ndone. Contents of the module can be modified without having a separate\nrepository copy of the dependency somewhere else.\n\nHowever they have several drawbacks. Contributing code back upstream for the\nsub-projects is slightly more complicated. And developer should be very careful\nof not mixing super and sub-project code in commits.\n\nGit subtrees requires precise manual management in case use have complicated\nprojects structure and lots of upstream commits to dependent projects.\n\n## Git subtrees management\nGit subtrees provides several operations to manage repositories dependency.\n\n### Add subtree dependency\n```shell\n# Add git subtree of 'master' branch into the relative directory 'modules/zlib'\ngit subtree add -P modules/zlib https://github.com/madler/zlib.git master --squash\n```\n\n### Update subtree from the upstream remote repository\n```shell\ngit subtree pull -P modules/zlib https://github.com/madler/zlib.git master --squash\n```\n\n### Contribute changes from subtree back to the upstream remote repository\n```shell\ngit subtree push -P modules/zlib https://github.com/madler/zlib.git master\n```\n\n### Remove subtree dependency\n```shell\n# Remove git subtree from the relative directory 'modules/zlib'\ngit rm -f modules/zlib\n```\n\n## Subtrees manual management problem\nInitially git subtrees lack of the same [repository duplicate problem](#recursive-submodules-problem)\nwhich git submodules have. Therefore all repositories with multiple dependencies\nwill be duplicated and require manual and careful management.\n\nFor instance `CppBenchmark` repository presented four times in our [sample](#sample):\n```shell\n~/gil/sample/CppBenchmark\n~/gil/sample/CppCommon/modules/CppBenchmark - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppBenchmark - DUPLICATE!\n~/gil/sample/CppLogging/modules/CppCommon/modules/CppBenchmark - DUPLICATE!\n```\n\nThe first problem if you updated `CppBenchmark` and want to get the fix in all\ndependent repositories you have to update them manually with the set of\n`git subtree pull` commands:\n```shell\n# Commit and push changes in CppBenchmark repository\ncd CppBenchmark\ngit commit -a -m \"Bugfix in CppBenchmark\"\ngit push\ncd ..\n\n# Update CppCommon repository\ncd CppCommon\ngit subtree pull --prefix modules/CppBenchmark https://github.com/chronoxor/test-CppBenchmark.git main --squash\ngit push\ncd ..\n\n# Update CppLogging repository\ncd CppLogging\ngit subtree pull --prefix modules/CppBenchmark https://github.com/chronoxor/test-CppBenchmark.git main --squash\ngit subtree pull --prefix modules/CppCommon https://github.com/chronoxor/test-CppCommon.git main --squash\ngit push\ncd ..\n```\n\nThe second problem if you found a bug in `CppBenchmark` while debugging\n`CppLogging` and want to fix it in place, push the changes and update all\nrepositories properly. In this case you need to make the following steps:\n```shell\n# Commit and push changes in CppBenchmark but from CppLogging repository\ncd CppLogging\ngit commit -a -m \"Bugfix in CppBenchmark (found in CppLogging repository)\"\ngit push\ngit subtree push --prefix modules/CppBenchmark https://github.com/chronoxor/test-CppBenchmark.git main --squash\ncd ..\n\n# Update CppBenchmark repository\ncd CppBenchmark\ngit pull\ncd ..\n\n# Update CppCommon repository\ncd CppCommon\ngit subtree pull --prefix modules/CppBenchmark https://github.com/chronoxor/test-CppBenchmark.git main --squash\ngit push\ncd ..\n\n# Update CppLogging repository\ncd CppLogging\ngit subtree pull --prefix modules/CppBenchmark https://github.com/chronoxor/test-CppBenchmark.git main --squash\ngit subtree pull --prefix modules/CppCommon https://github.com/chronoxor/test-CppCommon.git main --squash\ngit push\ncd ..\n```\n\nAs the result too much manual work should be done to make all repositories up\nto date. Definitely all commands should be stored into scripts with care. And\nthis job requires some efforts and testing because it is very easy to make a\nmistake. Git subtrees are good and easy to use for small repositories without\ncomplicated hierarchy. But working with huge complicated repositories using\ngit subtrees is a big challenge as git subtrees do not suppot recursing\npull/push/update commands.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronoxor%2Fgil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchronoxor%2Fgil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronoxor%2Fgil/lists"}