···144144 `P "For each unique repository:";
145145 `I ("1.", "Splits the subtree commits from the monorepo");
146146 `I ("2.", "Fast-forward merges the split commits into the checkout");
147147+ `I
148148+ ( "3.",
149149+ "If --upstream is specified, pushes each checkout to its git remote"
150150+ );
147151 `P
148148- "After running push, you can review the changes in each checkout and \
152152+ "Without --upstream, you can review the changes in each checkout and \
149153 manually push them to the git remotes.";
150154 `P "The operation will fail if any checkout has uncommitted changes.";
151155 ]
152156 in
153157 let info = Cmd.info "push" ~doc ~man in
154154- let run config_file package () =
158158+ let upstream_arg =
159159+ let doc =
160160+ "Also push each checkout to its upstream git remote after extracting \
161161+ changes."
162162+ in
163163+ Arg.(value & flag & info [ "upstream" ] ~doc)
164164+ in
165165+ let run config_file package upstream () =
155166 Eio_main.run @@ fun env ->
156167 with_config env config_file @@ fun config ->
157168 let fs = Eio.Stdenv.fs env in
158169 let proc = Eio.Stdenv.process_mgr env in
159159- match Monopam.push ~proc ~fs ~config ?package () with
170170+ match Monopam.push ~proc ~fs ~config ?package ~upstream () with
160171 | Ok () ->
161172 Fmt.pr "Push completed.@.";
162173 `Ok ()
···165176 `Error (false, "push failed")
166177 in
167178 Cmd.v info
168168- Term.(ret (const run $ config_file_arg $ package_arg $ logging_term))
179179+ Term.(
180180+ ret (const run $ config_file_arg $ package_arg $ upstream_arg $ logging_term))
169181170182(* Add command *)
171183
+9
monopam/lib/git.ml
···181181 let cwd = path_to_eio ~fs path in
182182 run_git_ok ~proc ~cwd [ "commit"; "--allow-empty"; "-m"; message ]
183183 |> Result.map ignore
184184+185185+let push_remote ~proc ~fs ?(remote = "origin") ?branch path =
186186+ let cwd = path_to_eio ~fs path in
187187+ let branch =
188188+ match branch with
189189+ | Some b -> b
190190+ | None -> Option.value ~default:"main" (current_branch ~proc ~fs path)
191191+ in
192192+ run_git_ok ~proc ~cwd [ "push"; remote; branch ] |> Result.map ignore
+13
monopam/lib/git.mli
···225225 (unit, error) result
226226(** [commit_allow_empty ~proc ~fs ~message path] creates a commit, even if there
227227 are no changes. Useful for initializing a repository. *)
228228+229229+val push_remote :
230230+ proc:_ Eio.Process.mgr ->
231231+ fs:Eio.Fs.dir_ty Eio.Path.t ->
232232+ ?remote:string ->
233233+ ?branch:string ->
234234+ Fpath.t ->
235235+ (unit, error) result
236236+(** [push_remote ~proc ~fs ?remote ?branch path] pushes the current branch to
237237+ the remote.
238238+239239+ @param remote Remote name (default: "origin")
240240+ @param branch Branch to push (default: current branch) *)
+35-5
monopam/lib/monopam.ml
···710710 Ok ()
711711 end
712712713713-let push ~proc ~fs ~config ?package () =
713713+let push ~proc ~fs ~config ?package ?(upstream = false) () =
714714 let fs_t = fs_typed fs in
715715 (* Ensure checkouts directory exists before computing status *)
716716 ensure_checkouts_dir ~fs:fs_t ~config;
···737737 let repos = unique_repos pkgs in
738738 Log.info (fun m -> m "Pushing %d unique repos" (List.length repos));
739739 let total = List.length repos in
740740- let rec loop i = function
741741- | [] -> Ok ()
740740+ let rec loop i pushed_repos = function
741741+ | [] -> Ok (List.rev pushed_repos)
742742 | pkg :: rest -> (
743743 Log.info (fun m ->
744744 m "[%d/%d] Processing %s" i total
745745 (Package.subtree_prefix pkg));
746746 match push_one ~proc ~fs ~config pkg with
747747- | Ok () -> loop (i + 1) rest
747747+ | Ok () -> loop (i + 1) (pkg :: pushed_repos) rest
748748 | Error e -> Error e)
749749 in
750750- loop 1 repos
750750+ match loop 1 [] repos with
751751+ | Error e -> Error e
752752+ | Ok pushed_repos ->
753753+ if upstream && pushed_repos <> [] then begin
754754+ Log.info (fun m ->
755755+ m "Pushing %d repos to upstream" (List.length pushed_repos));
756756+ let checkouts_root = Config.Paths.checkouts config in
757757+ let total = List.length pushed_repos in
758758+ let rec push_upstream i = function
759759+ | [] -> Ok ()
760760+ | pkg :: rest -> (
761761+ let checkout_dir =
762762+ Package.checkout_dir ~checkouts_root pkg
763763+ in
764764+ let branch = get_branch ~config pkg in
765765+ Log.info (fun m ->
766766+ m "[%d/%d] Pushing %s to origin" i total
767767+ (Package.repo_name pkg));
768768+ match
769769+ Git.push_remote ~proc ~fs:fs_t ~branch checkout_dir
770770+ with
771771+ | Ok () ->
772772+ Log.app (fun m ->
773773+ m " Pushed %s to origin/%s" (Package.repo_name pkg)
774774+ branch);
775775+ push_upstream (i + 1) rest
776776+ | Error e -> Error (Git_error e))
777777+ in
778778+ push_upstream 1 pushed_repos
779779+ end
780780+ else Ok ()
751781 end
752782 end
753783
+9-5
monopam/lib/monopam.mli
···8585 fs:Eio.Fs.dir_ty Eio.Path.t ->
8686 config:Config.t ->
8787 ?package:string ->
8888+ ?upstream:bool ->
8889 unit ->
8990 (unit, error) result
9090-(** [push ~proc ~fs ~config ?package ()] pushes changes from monorepo to
9191- checkouts.
9191+(** [push ~proc ~fs ~config ?package ?upstream ()] pushes changes from monorepo
9292+ to checkouts.
92939394 For each package (or the specified package) with changes in the monorepo: 1.
9494- Splits the subtree commits 2. Pushes to the individual checkout
9595+ Splits the subtree commits 2. Pushes to the individual checkout 3. If
9696+ [~upstream:true], also pushes each checkout to its git remote
95979696- The user must manually push from checkouts to remotes.
9898+ If [~upstream] is false (the default), the user must manually push from
9999+ checkouts to remotes.
9710098101 Aborts if any checkout has uncommitted changes.
99102100103 @param proc Eio process manager
101104 @param fs Eio filesystem
102105 @param config Monopam configuration
103103- @param package Optional specific package to push *)
106106+ @param package Optional specific package to push
107107+ @param upstream If true, also push checkouts to their git remotes *)
104108105109(** {2 Package Management} *)
106110