{"id":16445762,"url":"https://github.com/mslinn/git_tree","last_synced_at":"2026-02-11T17:31:01.705Z","repository":{"id":160079077,"uuid":"634913973","full_name":"mslinn/git_tree","owner":"mslinn","description":"This Ruby gem installs commands that walk git directory trees and do things to them","archived":false,"fork":false,"pushed_at":"2025-12-05T00:01:20.000Z","size":391,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-14T21:51:52.597Z","etag":null,"topics":["git","ruby","rugged"],"latest_commit_sha":null,"homepage":"https://www.mslinn.com/git/1100-git-tree.html","language":"Ruby","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/mslinn.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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,"zenodo":null}},"created_at":"2023-05-01T14:33:42.000Z","updated_at":"2025-12-05T00:01:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"cc7f20d9-1962-4ad7-9fa3-c7ae518d1d22","html_url":"https://github.com/mslinn/git_tree","commit_stats":null,"previous_names":["mslinn/replicate_git_tree"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/mslinn/git_tree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2Fgit_tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2Fgit_tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2Fgit_tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2Fgit_tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mslinn","download_url":"https://codeload.github.com/mslinn/git_tree/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2Fgit_tree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29339564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T16:14:43.024Z","status":"ssl_error","status_checked_at":"2026-02-11T16:14:15.258Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["git","ruby","rugged"],"created_at":"2024-10-11T09:45:19.761Z","updated_at":"2026-02-11T17:31:01.645Z","avatar_url":"https://github.com/mslinn.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `Git_tree` [![Gem Version](https://badge.fury.io/rb/git_tree.svg)](https://badge.fury.io/rb/git_tree)\n\nThis Ruby gem installs commands that walk a git directory tree and act on each repository.\nDirectories containing a file called `.ignore` are ignored.\nIgnoring a directory means all subdirectories are also ignored.\nMultiple threads are used to dramatically boost performance.\n\n- The `git-commitAll` command commits and pushes all changes to each repository in the tree.\n  Repositories in a detached `HEAD` state are skipped.\n\n- The `git-evars` command writes a script that defines environment variables pointing to each git repository.\n\n- The `git-exec` command executes an arbitrary bash command for each repository.\n\n- The `git-replicate` command writes a script that clones the repos in the tree,\n  and adds any defined remotes.\n\n  - Any git repos that have already been cloned into the target directory tree are skipped.\n    This means you can rerun `git-replicate` as many times as you want, without ill effects.\n\n  - All remotes in each repo are replicated.\n\n- The `git-update` command updates each repository in the tree.\n\nYou can list them by using the `gem specification` command, like this:\n\n```shell\n$ gem specification git_tree executables\n---\n- git-commitAll\n- git-evars\n- git-exec\n- git-replicate\n- git-update\n```\n\n## Installation\n\nType the following at a shell prompt on the machine you are copying the git tree from,\nand on the machine that you are copying the git tree to:\n\n```shell\n$ yes | sudo apt install cmake libgit2-dev libssh2-1-dev pkg-config\n\n$ gem install git_tree\n```\n\nTo register the new commands, either log out and log back in, or open a new console.\n\n\n## Configuration\n\nThe `git_tree` commands can be configured to suit your preferences. Settings are resolved in the following order of precedence,\nwhere items higher in the list override those lower down:\n\n1. **Environment Variables**\n2. **User Configuration File** (`~/.treeconfig.yml`)\n3. **Default values** built into the gem.\n\nThis allows for flexible customization of the gem's behavior.\n\n### Interactive Setup: `git-treeconfig`\n\nThe easiest way to get started is to use the `git-treeconfig` command. This interactive tool will ask you a few questions\nand create a configuration file for you at `~/.treeconfig.yml`.\n\n```shell\n$ git-treeconfig\nWelcome to git-tree configuration.\nThis utility will help you create a configuration file at: /home/user/.treeconfig.yml\nPress Enter to accept the default value in brackets.\n\nGit command timeout in seconds? |300| 600\nDefault verbosity level (0=quiet, 1=normal, 2=verbose)? |1|\nDefault root directories (space-separated)? |sites sitesUbuntu work| dev projects\n\nConfiguration saved to /home/user/.treeconfig.yml\n```\n\n### Configuration File\n\nThe `git-treeconfig` command generates a YAML file (`~/.treeconfig.yml`) that you can also edit manually.\n\nHere is an example:\n\n```yaml\n---\ngit_timeout: 600\nverbosity: 1\ndefault_roots:\n- dev\n- projects\n```\n\n### Environment Variables\n\nFor temporary overrides or use in CI/CD environments, you can use environment variables.\nThey must be prefixed with `GIT_TREE_` and be in uppercase.\n\n- `export GIT_TREE_GIT_TIMEOUT=900`\n- `export GIT_TREE_VERBOSITY=2`\n- `export GIT_TREE_DEFAULT_ROOTS=\"dev projects personal\"` (space-separated string)\n\n\n## Use Cases\n\n### Dependent Gem Maintenance\n\nOne of my directory trees holds Jekyll plugins, packaged as 25 gems.\nThey depend on one another, and must be built in a particular order.\nSometimes an operation must be performed on all of the plugins, and then rebuild them all.\n\nMost operations do not require that the projects be processed in any particular order, however\nthe build process must be invoked on the dependencies first.\nIt is quite tedious to do this 25 times, over and over.\n\nSeveral years ago I wrote a bash script to perform this task, but as its requirements became more complex,\nthe bash script proved difficult to maintain. This use case is now fulfilled by the `git-exec` command\nprovided by the `git_tree` gem.\nSee below for further details.\n\n\n### Replicating Trees of Git Repositories\n\nWhenever I set up an operating system for a new development computer,\none of the tedious tasks that must be performed is to replicate\nthe directory trees of Git repositories.\n\nIt is a bad idea to attempt to copy an entire Git repository between computers,\nbecause the `.git` directories within them can quite large.\nSo large, in fact, that it might much more time to copy than re-cloning.\n\nThe reason is that copying the entire Git repository actually means copying the same information twice:\nfirst the `.git` hidden directory, complete with all the history for the project,\nand then again for the files in the currently checked out branch.\nGit repos store the entire development history of the project in their `.git` directories,\nso as they accumulate history they eventually become much larger than the\ncode that is checked out at any given time.\n\nOne morning I found myself facing the boring task of doing this manually once again.\nInstead, I wrote a bash script that scanned a Git directory tree and\nwrote out another bash script that clones the repos in the tree.\nAny additional remote references are replicated.\n\nTwo years later, I decided to add new features to the script.\nBash is great for short scripts,\nbut it is not conducive to debugging or structured programming.\nI rewrote the bash script in Ruby, using the `rugged` gem.\nMuch better!\n\nTwo years after that I used Google Gemini Code Assist to rewrite it again in Ruby,\nthis time as a multithreaded program.\nPerformance is now lightning-fast for most use cases.\nI was also able to use the same core logic for several of the individual\nGit-related scripts I had written over the years.\nThe result is this Ruby gem.\n\nThis use case is fulfilled by the\n`git-replicate`\nand `git-evars` commands\nprovided by this gem.\n\n\n## Usage\n\n### Single- And Multi-Threading\n\nAll of these commands are inherently multi-threaded.\nThey consume up to 75% of the threads that your CPU can provide.\nYou may notice that your computer's fan gets louder when your run these commands on large numbers of Git repositories.\n\nFor builds and other sequential tasks, however, parallelism is inappropriate.\nInstead, it is necessary to build components in the proper order.\nDoing all the work on a single thread is a straightforward way of ensuring proper task ordering.\n\nUse the `-s/--serial` option when the order that Git projects are processed matters.\nAll of the commands support this option.\nExecution will take much longer that without the option,\nbecause performing most tasks take longer to perform in sequence than performing them in parallel.\nExceptions include old sayings like “Nine women cannot have a baby in one month.”\nFor those exceptions, use the `-s/--serial` option.\n\n### `git-commitAll`\n\n```text\ngit-commitAll - Recursively commits and pushes changes in all git repositories under the specified roots.\nIf no directories are given, uses default roots (sites, sitesUbuntu, work) as roots.\nSkips directories containing a .ignore file, and all subdirectories.\nRepositories in a detached HEAD state are skipped.\n\nOptions:\n  -h, --help                Show this help message and exit.\n  -m, --message MESSAGE     Use the given string as the commit message.\n                            (default: \"-\")\n  -q, --quiet               Suppress normal output, only show errors.\n  -s, --serial              Run tasks serially in a single thread in the order specified.\n  -v, --verbose             Increase verbosity. Can be used multiple times (e.g., -v, -vv).\n\nUsage:\n  git-commitAll [OPTIONS] [DIRECTORY...]\n\nUsage examples:\n  git-commitAll                                # Commit with default message \"-\"\n  git-commitAll -m \"This is a commit message\"  # Commit with a custom message\n  git-commitAll $work $sites                   # Commit in repositories under specific roots\n```\n\n```shell\n$ git commitAll\nProcessing $sites $sitesUbuntu $work\nInitializing 18 worker threads...\n\nAll work is complete.\n```\n\n\n### `git-evars`\n\nThe `git-evars` command writes a script that defines environment variables pointing to each git repository.\nThis command should be run on the target computer.\n\nOnly one parameter is required:\nan environment variable reference, pointing to the top-level directory to replicate.\nThe environment variable reference must be contained within single quotes to prevent expansion by the shell.\n\nThe following appends to any script in the `$work` directory called `.evars`.\nThe script defines environment variables that point to each git repos pointed to by `$work`:\n\n```shell\n$ git-evars '$work' \u003e\u003e $work/.evars\n```\n\n\n#### Generated Script from `git-evars`\n\nFollowing is a sample of environment variable definitions.\nThe `-z`/`--zowee` option generates intermediate environment variable definitions,\nmaking them much easier to work with.\n\n```shell\n$ git-evars -z '$sites'\nexport mnt=/mnt\nexport c=$mnt/c\nexport _6of26=$sites/6of26\nexport computers=$sites/computers.mslinn.com\nexport ebooks=$sites/ebooks\nexport expert=$sites/expert\nexport fonts=$sites/fonts\nexport intranet=$sites/intranet.ancientwarmth.com\nexport intranet_mslinn=$sites/intranet.mslinn.com\nexport jekyllTemplate=$sites/jekyllTemplate\nexport lyrics=$sites/lyrics\nexport metamusic=$sites/metamusic\nexport music=$sites/music.mslinn.com\nexport photos=$sites/photos\nexport supportingLiterature=$sites/supportingLiterature\nexport www=$sites/www.scalacourses.com\n```\n\nThe environment variable definitions are meant to be saved into a file that is `source`d upon boot.\nWhile you could place them in a file like `~/.bashrc`,\nthe author's preference is to instead place them in `$work/.evars`,\nand add the following to `~/.bashrc`:\n\n```shell\nsource \"$work/.evars\"\n```\n\nThus each time you log in, the environment variable definitions will have been re-established.\nYou can therefore change directory to any of the cloned projects, like this:\n\n```shell\n$ cd $git_root\n\n$ cd $my_project\n```\n\n\n### `git-exec` Usage\n\nThe `git-exec` command can be run on any computer.\nThe command requires two parameters.\nThe first parameter indicates the directory or directories to process.\n3 forms are accepted:\n\n  1. A directory name, which may be relative or absolute.\n\n  2. An environment variable reference,\n     which must be contained within single quotes to prevent expansion by the shell.\n\n  3. A list of directory names, which may be relative or absolute, and may contain environment variables.\n\n\n#### Example 1\n\nFor all subdirectories of current directory,\nupdate `Gemfile.lock` and install a local copy of the gem:\n\n```shell\n$ git-exec \\\n  '$jekyll_plugin_logger\n  $jekyll_draft\n  $jekyll_plugin_support\n  $jekyll_all_collections\n  $jekyll_plugin_template\n  $jekyll_flexible_include_plugin\n  $jekyll_href\n  $jekyll_img\n  $jekyll_outline\n  $jekyll_plugin_template\n  $jekyll_pre\n  $jekyll_quote'\n  'bundle \u0026\u0026 bundle update \u0026\u0026 rake install'\n```\n\n#### Example 2\n\nThis example shows how to display the version of projects that\ncreate gems under the directory pointed to by `$my_plugins`.\n\nAn executable script is required on the `PATH`, so `git-exec`\ncan invoke it as it loops through the subdirectories.\nI call this script `version`, and it is written in `bash`,\nalthough the language used is not significant:\n\n```shell\n#!/bin/bash\n\nx=\"$( ls lib/**/version.rb 2\u003e /dev/null )\"\nif [ -f \"$x\" ]; then\n  v=\"$( \\\n    cat \"$x\" | \\\n    grep '=' | \\\n    sed -e s/.freeze// | \\\n    tr -d 'VERSION =\"' | \\\n    tr -d \\\n  )\"\n  echo \"$(basename $PWD) v$v\"\nfi\n```\n\nCall it like this:\n\n```shell\n$ git-exec '$my_plugins' version\njekyll_all_collections v0.3.3\njekyll_archive_create v1.0.2\njekyll_archive_display v1.0.1\njekyll_auto_redirect v0.1.0\njekyll_basename_dirname v1.0.3\njekyll_begin_end v1.0.1\njekyll_bootstrap5_tabs v1.1.2\njekyll_context_inspector v1.0.1\njekyll_download_link v1.0.1\njekyll_draft v1.1.2\njekyll_flexible_include_plugin v2.0.20\njekyll_from_to_until v1.0.3\njekyll_href v1.2.5\njekyll_img v0.1.5\njekyll_nth v1.1.0\njekyll_outline v1.2.0\njekyll_pdf v0.1.0\njekyll_plugin_logger v2.1.1\njekyll_plugin_support v0.7.0\njekyll_plugin_template v0.3.0\njekyll_pre v1.4.1\njekyll_quote v0.4.0\njekyll_random_hex v1.0.0\njekyll_reading_time v1.0.0\njekyll_revision v0.1.0\njekyll_run v1.0.1\njekyll_site_inspector v1.0.0\njekyll_sort_natural v1.0.0\njekyll_time_since v0.1.3\n```\n\n#### Example 3\n\nList the projects under the directory pointed to by `$my_plugins`\nthat have a `demo/` subdirectory:\n\n```shell\n$ git-exec '$my_plugins' \\\n  'if [ -d demo ]; then realpath demo; fi'\n/mnt/c/work/jekyll/my_plugins/jekyll-hello/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_all_collections/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_archive_create/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_download_link/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_draft/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_flexible_include_plugin/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_from_to_until/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_href/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_img/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_outline/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_pdf/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_plugin_support/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_plugin_template/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_pre/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_quote/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_revision/demo\n/mnt/c/work/jekyll/my_plugins/jekyll_time_since/demo\n```\n\n### `git-replicate` Usage\n\nThis command generates a shell script to replicate a tree of git repositories.\nROOTS can be directory names or environment variable references (e.g., '$work').\nMultiple roots can be specified in a single quoted string.\n\n```shell\n$ git-replicate '$work' \u003e work.sh                # Replicate repos under $work\n$ git-replicate '$work $sites' \u003e replicate.sh    # Replicate repos under $work and $sites\n```\n\nThe generated environment variables will all be relative to the\npath pointed to by the expanded environment variable that you provided.\nYou will understand what this means once you look at the generated script.\n\nWhen `git-replicate` completes,\nedit the generated script to suit, then\ncopy it to the target machine and run it.\nThe following example copies the script to `machine2` and runs it:\n\n```shell\n$ scp work.sh machine2:\n\n$ ssh machine2 work.sh\n```\n\n\n#### Generated Script from `git-replicate`\n\nFollowing is a sample of one section, which is repeated for every git repo that is processed:\nYou can edit them to suit.\n\n```shell\nif [ ! -d \"sinatra/sinatras-skeleton/.git\" ]; then\n  mkdir -p 'sinatra'\n  pushd 'sinatra' \u003e /dev/null\n  git clone git@github.com:mslinn/sinatras-skeleton.git\n  git remote add upstream 'https://github.com/simonneutert/sinatras-skeleton.git'\n  popd \u003e /dev/null\nfi\n```\n\n### `git-update`\n\nThe `git-update` command updates each repository in the tree.\n\n\n## Additional Information\n\nMore information is available on\n[Mike Slinn’s website](https://www.mslinn.com/git/1100-git-tree.html).\n\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies.\n\nRun the following to create a directory tree for testing.\n\n```shell\n$ ruby bin/make_test_directory.rb\n```\n\nYou can run `bin/console` for an interactive prompt that will allow you to experiment.\n\n```shell\n$ bin/console\nirb(main):001:0\u003e GitTree::ReplicateCommand.new('$work').run\n```\n\n\n### Build and Install Locally\n\nTo build and install this gem onto your local machine, run:\n\n```shell\n$ bundle exec rake install\n```\n\nExamine the newly built gem:\n\n```shell\n$ gem info git_tree\n\n*** LOCAL GEMS ***\n\ngit_tree (0.3.0)\n    Author: Mike Slinn\n    Homepage: https://www.mslinn.com/git/1100-git-tree.html\n    License: MIT\n    Installed at: /home/mslinn/.rbenv/versions/3.4.6/lib/ruby/gems/3.4.0\n\n    Installs five commands that walk a git directory tree and perform tasks.\n```\n\n\n### Build and Push to RubyGems\n\nTo release a new version:\n\n  1. Update the version number in `version.rb`.\n  2. Commit all changes to git; if you don't the next step might fail with an\n     unexplainable error message.\n  3. Run the following:\n\n     ```shell\n     $ bundle exec rake release\n     ```\n\n     The above creates a git tag for the version, commits the created tag,\n     and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org).\n\n\n## Contributing\n\n1. Fork the project\n2. Create a descriptively named feature branch\n3. Add your feature\n4. Submit a pull request\n\n\n## License\n\nThe gem is available as open source under the terms of the\n[MIT License](https://opensource.org/licenses/MIT).\n\n## Additional Information\n\nMore information is available on\n[Mike Slinn’s website](https://www.mslinn.com/git/1100-git-tree.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmslinn%2Fgit_tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmslinn%2Fgit_tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmslinn%2Fgit_tree/lists"}