@@ -26,8 +26,7 @@ pub enum Subcommands {
2626 /// Publish review requests for active branches in your workspace.
2727 /// By default, publishes reviews for all active branches.
2828 Publish {
29- /// Publish reviews only for the specified branch.
30- #[ clap( long, short = 'b' ) ]
29+ /// Branch name or CliId to publish a review for. If not provided, publishes reviews for all active branches.
3130 branch : Option < String > ,
3231 /// Force push even if it's not fast-forward (defaults to true).
3332 #[ clap( long, short = 'f' , default_value_t = true ) ]
@@ -57,10 +56,15 @@ pub async fn publish_reviews(
5756 let applied_stacks =
5857 but_api:: workspace:: stacks ( project. id , Some ( but_workspace:: StacksFilter :: InWorkspace ) ) ?;
5958 match branch {
60- Some ( branch_name) => {
59+ Some ( branch_input) => {
60+ // Resolve the branch input as a CliId to support both branch names and CliIds
61+ let app_settings = AppSettings :: load_from_default_path_creating ( ) ?;
62+ let ctx = & mut CommandContext :: open ( project, app_settings) ?;
63+ let branch_name = resolve_branch_name ( ctx, branch_input) ?;
64+
6165 handle_specific_branch_publish (
6266 project,
63- branch_name,
67+ & branch_name,
6468 & review_map,
6569 & applied_stacks,
6670 skip_force_push_protection,
@@ -530,3 +534,57 @@ pub fn get_review_numbers(
530534 "" . to_string ( ) . normal ( )
531535 }
532536}
537+
538+ /// Resolve a branch input string to an actual branch name.
539+ ///
540+ /// This function handles both exact branch names and CliId matches (including partial matches).
541+ /// The CliId resolution allows users to specify branches using shortened identifiers similar
542+ /// to how the `rub` command works.
543+ ///
544+ /// # Arguments
545+ /// * `ctx` - The command context used for resolving CliIds
546+ /// * `branch_input` - The branch name or CliId to resolve
547+ ///
548+ /// # Returns
549+ /// * `Ok(String)` - The resolved branch name
550+ ///
551+ /// # Errors
552+ /// * Returns an error if no matches are found
553+ /// * Returns an error if the input is ambiguous (matches multiple entities)
554+ /// * Returns an error if the input resolves to a non-branch entity (e.g., a commit or file)
555+ fn resolve_branch_name ( ctx : & mut CommandContext , branch_input : & str ) -> anyhow:: Result < String > {
556+ // CliId::from_str handles both exact branch names and CliId matches (including partial matches)
557+ let mut cli_ids = crate :: id:: CliId :: from_str ( ctx, branch_input) ?;
558+
559+ if cli_ids. is_empty ( ) {
560+ anyhow:: bail!(
561+ "Branch '{}' not found. If you just performed a Git operation (squash, rebase, etc.), try running 'but status' to refresh the current state." ,
562+ branch_input
563+ ) ;
564+ }
565+
566+ if cli_ids. len ( ) > 1 {
567+ let matches: Vec < String > = cli_ids
568+ . iter ( )
569+ . map ( |id| match id {
570+ crate :: id:: CliId :: Branch { name } => format ! ( "{id} (branch '{name}')" ) ,
571+ _ => format ! ( "{} ({})" , id, id. kind( ) ) ,
572+ } )
573+ . collect ( ) ;
574+ anyhow:: bail!(
575+ "Branch identifier '{}' is ambiguous. Matches: {}. Try using more characters, a longer identifier, or the full branch name to disambiguate." ,
576+ branch_input,
577+ matches. join( ", " )
578+ ) ;
579+ }
580+
581+ // Extract branch name from the resolved CliId
582+ match cli_ids. pop ( ) . unwrap ( ) {
583+ crate :: id:: CliId :: Branch { name } => Ok ( name) ,
584+ other => anyhow:: bail!(
585+ "Expected a branch, but '{}' resolved to {}" ,
586+ branch_input,
587+ other. kind( )
588+ ) ,
589+ }
590+ }
0 commit comments