--- /dev/null
+(ns git
+ (:require [babashka.process :as p]
+ [clojure.java.io :as io]
+ [clojure.string :as str]
+ [lib :refer [run-cmd]]))
+
+; Utilities for git operations
+
+(def default-root ".")
+
+(defn- has-git-repo
+ [dir]
+ (first (filter #(= ".git" %)
+ (map #(.getName %)
+ (filter #(.isDirectory %) (.listFiles (io/file dir)))))))
+
+(defn- list-dirs
+ [root]
+ (filter #(has-git-repo %)
+ (filter #(.isDirectory %) (.listFiles (io/file root)))))
+
+(defn- git-pull [dir]
+ (p/process ["git" "-C" dir "pull" "--rebase"]))
+
+(defn git-pull-all
+ "Runs `git-pull` on all the git repositories in a directory"
+ [root]
+ (let [dirs (list-dirs root)
+ pulls (->> root
+ list-dirs
+ (map git-pull)
+ doall)
+ outputs (map #(->> %
+ p/check
+ :out
+ slurp)
+ pulls)]
+ ;; Print corresponding directory name when pulling
+ ;; Skip printing already up to date repos
+ (doseq [[dir out] (filter #(not (.contains (second %) "is up to date."))
+ (map vector dirs outputs))]
+ (println (str dir "\n" out)))))
+
+
+(defn git-pull-rebase-branch
+ "Do git pull and rebase branch with master"
+ [dir]
+ (let [current-branch (str/trim (run-cmd ["git" "branch" "--show-current"]))]
+ (git-pull dir)
+ (when (not (contains? #{"master" "main"} current-branch))
+ (run! print
+ (map run-cmd
+ '[["git" "checkout" "master"]
+ ["git" "pull" "--rebase"]
+ ["git" "checkout" "-"]
+ ["git" "rebase" "master"]])))))