Skip to content

bash function git alias tab completion #994

@Daviid-P

Description

@Daviid-P

I wanted to create an alias to rebase many branch in order so I wrote this function

[alias]
	multibase = "!sorted_multi_rebase() { \
		if [ \"$#\" -lt 2 ]; then \
			echo \"Usage: $0 [--dry-run] base branch1 branch2 ...\"; \
			exit 1; \
		fi; \
		DRY_RUN=0; \
		if [ \"$1\" = \"--dry-run\" ]; then \
			DRY_RUN=1; \
			shift; \
		fi; \
		BASE=$1; \
		shift; \
		PREV=$BASE; \
		for BRANCH in \"$@\"; do \
			if ! git show-ref --verify --quiet refs/heads/$BRANCH; then \
				echo \"Branch '$BRANCH' does not exist locally, skipping...\"; \
				continue; \
			fi; \
			echo \"=== Planning to rebase $BRANCH onto $PREV ===\"; \
			if git merge-base --is-ancestor \"$PREV\" \"$BRANCH\"; then \
				echo \"$BRANCH is already up-to-date with $PREV, skipping...\"; \
			else \
				if [ $DRY_RUN -eq 1 ]; then \
					echo \"[DRY-RUN] Would run: git rebase $PREV $BRANCH\"; \
				else \
					echo \"Rebasing $BRANCH onto $PREV...\"; \
					git switch \"$BRANCH\" && git rebase \"$PREV\" || { \
						echo \"Rebase failed for $BRANCH. Resolve conflicts and run 'git rebase --continue', then retry the command.\"; \
						exit 1; \
					}; \
				fi; \
			fi; \
			PREV=$BRANCH; \
		done; \
		echo \"Rebase sequence completed.\"; \
	}; sorted_multi_rebase"

But I was having trouble with autocompleting branch names

In the end I had to modify posh-git.psd1 and posh-git.psm1 to export GitTabExpansionInternal and then, to avoid expanding multibase to the function and instead act as if it was rebase I created this

        # Store the original function's definition
        $OriginalGitTabExpansionInternal = $originalCommand.ScriptBlock

        # Redefine GitTabExpansionInternal to override the original
        function global:GitTabExpansionInternal {
            param($lastBlock, $GitStatus = $null)

            # Custom logic to handle 'multibase' as 'rebase'
            if ($lastBlock -match "^git\s+(?<cmd>\S+)(?<args>.*)$") {
                if ($Matches['cmd'] -eq 'multibase') {
                    # Replace 'multibase' with 'rebase' for tab completion
                    $lastBlock = "git rebase$($Matches['args'] -replace '^\s*multibase', '')"
                    Write-Verbose "Intercepted 'multibase', converting to '$lastBlock'"
                }
            }

            # Invoke the original function using its ScriptBlock
            & $OriginalGitTabExpansionInternal $lastBlock $GitStatus
        }

This works, but it feels like I've overcomplicated things, is there an easier way to do this?

If not, could we have some sort of hook system or translation to not expand specific aliases and instead treat them as X base git command?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions