|
#!/usr/bin/env bash |
|
# GWT - Git Worktree Management Utilities |
|
# https://gist.github.com/[will-be-updated] |
|
|
|
# ============================================================================ |
|
# HELPER FUNCTIONS |
|
# ============================================================================ |
|
|
|
# Check if GWT_WORKTREES_ROOT is set (required, no default) |
|
_gwt_check_env() { |
|
if [[ -z "${GWT_WORKTREES_ROOT}" ]]; then |
|
echo "Error: GWT_WORKTREES_ROOT environment variable is not set" |
|
echo "Please set it in your shell profile:" |
|
echo " export GWT_WORKTREES_ROOT=\"\$HOME/worktrees\"" |
|
return 1 |
|
fi |
|
return 0 |
|
} |
|
|
|
# Get repository name from current directory |
|
_gwt_repo_name() { |
|
basename "$(git rev-parse --show-toplevel)" |
|
} |
|
|
|
# Get worktree base path for current repo |
|
_gwt_base_path() { |
|
local repo_name="$(_gwt_repo_name)" |
|
echo "${GWT_WORKTREES_ROOT}/${repo_name}" |
|
} |
|
|
|
# Get full path to specific worktree |
|
_gwt_path() { |
|
local name="$1" |
|
echo "$(_gwt_base_path)/${name}" |
|
} |
|
|
|
# Check if we're in a git repository |
|
_gwt_check_repo() { |
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then |
|
echo "Error: Not in a git repository" |
|
return 1 |
|
fi |
|
return 0 |
|
} |
|
|
|
# Check if branch exists |
|
_gwt_branch_exists() { |
|
local branch="$1" |
|
git show-ref --verify --quiet "refs/heads/${branch}" |
|
} |
|
|
|
# ============================================================================ |
|
# COMMAND FUNCTIONS |
|
# ============================================================================ |
|
|
|
# Show usage and available commands |
|
gwt_help() { |
|
echo "GWT - Git Worktree Management Utilities" |
|
echo "" |
|
echo "Usage: gwt <command> [arguments]" |
|
echo "" |
|
echo "Commands:" |
|
echo " ls List all worktrees for current repository" |
|
echo " new <name> [branch] Create worktree (branch defaults to worktree/<name>)" |
|
echo " --stay: don't auto-navigate to new worktree" |
|
echo " rm <name> Remove worktree (prompts to delete branch)" |
|
echo " cd <name> Navigate to worktree directory" |
|
echo " code <name> Open worktree in new VS Code window" |
|
echo " preview <name> [--merge] Show worktree state in current directory" |
|
echo " Default: replaces current state with worktree's" |
|
echo " --merge: only apply worktree's changes (preserves main)" |
|
echo " revert Undo preview (restores files + removes added files)" |
|
echo " reset <name> Hard reset worktree branch to main (destructive)" |
|
echo " merge <name> Merge worktree into main (run from main branch)" |
|
echo "" |
|
echo "Use 'gwt --help' for detailed documentation (useful for AI agents)" |
|
echo "" |
|
|
|
# Show context if in a git repo |
|
if _gwt_check_repo 2>/dev/null && _gwt_check_env 2>/dev/null; then |
|
local repo_name="$(_gwt_repo_name)" |
|
local base_path="$(_gwt_base_path)" |
|
echo "Current repository: ${repo_name}" |
|
echo "Worktrees location: ${base_path}/" |
|
fi |
|
} |
|
|
|
# Detailed help for AI agents and advanced users |
|
gwt_help_detailed() { |
|
cat << 'EOF' |
|
GWT - Git Worktree Management Utilities |
|
======================================= |
|
|
|
Manages git worktrees in a centralized location defined by GWT_WORKTREES_ROOT. |
|
Worktrees are stored at: $GWT_WORKTREES_ROOT/<repo-name>/<worktree-name> |
|
|
|
COMMANDS |
|
-------- |
|
|
|
gwt ls |
|
List all worktrees for the current repository. |
|
No arguments or flags. |
|
Runs: git worktree list |
|
|
|
gwt new <name> [branch] [--stay] |
|
Create a new worktree. |
|
Arguments: |
|
<name> Required. Directory name for the worktree. |
|
[branch] Optional. Branch to checkout. Defaults to "worktree/<name>". |
|
Flags: |
|
--stay Don't auto-navigate to the new worktree after creation. |
|
Behaviour: |
|
- Creates worktree at $GWT_WORKTREES_ROOT/<repo>/<name> |
|
- If branch exists, checks it out; otherwise creates new branch |
|
- Auto-navigates to new worktree unless --stay is used |
|
|
|
gwt rm <name> |
|
Remove a worktree and optionally delete its branch. |
|
Arguments: |
|
<name> Required. Worktree to remove. |
|
Behaviour: |
|
- Prompts for confirmation before removal |
|
- After removal, prompts to delete the associated branch |
|
- If branch has unmerged changes, prompts for force deletion |
|
|
|
gwt cd <name> |
|
Navigate to a worktree directory. |
|
Arguments: |
|
<name> Required. Worktree to navigate to. |
|
|
|
gwt code <name> |
|
Open a worktree in VS Code. |
|
Arguments: |
|
<name> Required. Worktree to open. |
|
Behaviour: |
|
- Opens in a NEW VS Code window (code -n) |
|
|
|
gwt preview <name> [--merge] |
|
Apply worktree state to current directory for testing/review. |
|
Arguments: |
|
<name> Required. Worktree to preview. |
|
Flags: |
|
--merge, -m Use three-way merge mode instead of replacement mode. |
|
Modes: |
|
DEFAULT (two-dot diff): |
|
Makes current directory look EXACTLY like the worktree. |
|
Any files main has that worktree doesn't will appear as deletions. |
|
Use this when you need to test the exact worktree state locally |
|
(e.g., with local server, database, etc.). |
|
--merge (three-dot diff): |
|
Only applies changes the worktree made since it diverged from main. |
|
Preserves any changes made to main since the branch point. |
|
May have conflicts if both branches modified same files. |
|
Uses git apply --3way for conflict resolution. |
|
Requirements: |
|
- Clean working directory (no uncommitted changes) |
|
Cleanup: |
|
- Records added files in .git/gwt-preview-added |
|
- Use 'gwt revert' to undo |
|
|
|
gwt revert |
|
Undo changes made by gwt preview. |
|
No arguments or flags. |
|
Behaviour: |
|
- Runs 'git checkout .' to restore modified tracked files |
|
- Removes files that were added by the preview (reads from .git/gwt-preview-added) |
|
- Cleans up the added files record |
|
|
|
gwt reset <name> |
|
Hard reset a worktree's branch to main/master. |
|
Arguments: |
|
<name> Required. Worktree to reset. |
|
Behaviour: |
|
- Prompts for confirmation (destructive operation) |
|
- Runs 'git reset --hard main' in the worktree directory |
|
- All committed and uncommitted changes on the worktree branch are lost |
|
- Does NOT affect main branch or the primary repo |
|
|
|
gwt merge <name> |
|
Merge a worktree's branch into main. |
|
Arguments: |
|
<name> Required. Worktree to merge. |
|
Requirements: |
|
- Must be run from the main branch (not from a worktree) |
|
- Clean working directory (no uncommitted changes) |
|
Behaviour: |
|
- Standard git merge (fast-forward if possible, merge commit if needed) |
|
- If conflicts occur, must be resolved manually |
|
|
|
ENVIRONMENT |
|
----------- |
|
GWT_WORKTREES_ROOT Required. Base directory for all worktrees. |
|
Example: export GWT_WORKTREES_ROOT="$HOME/worktrees" |
|
|
|
TYPICAL WORKFLOW |
|
---------------- |
|
1. gwt new feature-x # Create worktree, auto-navigate to it |
|
2. (make changes in worktree) |
|
3. gwt cd main # Go back to main repo (or just cd to it) |
|
4. gwt preview feature-x # See exact worktree state in main dir |
|
5. (test with local server/db) |
|
6. gwt revert # Undo preview |
|
7. gwt merge feature-x # Merge when ready |
|
8. gwt rm feature-x # Clean up worktree and branch |
|
|
|
EOF |
|
} |
|
|
|
# List all worktrees |
|
gwt_list() { |
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local repo_name="$(_gwt_repo_name)" |
|
echo "Worktrees for repository: ${repo_name}" |
|
git worktree list |
|
} |
|
|
|
# Create new worktree |
|
gwt_new() { |
|
# Parse flags |
|
local stay_flag=0 |
|
local args=() |
|
|
|
# Process arguments to separate flags from positional args |
|
while [[ $# -gt 0 ]]; do |
|
case "$1" in |
|
--stay) |
|
stay_flag=1 |
|
shift |
|
;; |
|
*) |
|
args+=("$1") |
|
shift |
|
;; |
|
esac |
|
done |
|
|
|
# Extract positional arguments |
|
local name="${args[0]}" |
|
local branch="${args[1]}" |
|
|
|
# Validate inputs |
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt new <name> [branch] [--stay]" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
# Determine branch name |
|
if [[ -z "$branch" ]]; then |
|
branch="worktree/${name}" |
|
fi |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree already exists |
|
if [[ -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' already exists at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
echo "Creating worktree '${name}'..." |
|
|
|
# Create the base directory if it doesn't exist |
|
local base_path="$(_gwt_base_path)" |
|
mkdir -p "$base_path" |
|
|
|
# Check if branch exists |
|
local branch_action="" |
|
if _gwt_branch_exists "$branch"; then |
|
branch_action="Checked out existing branch" |
|
git worktree add "$worktree_path" "$branch" |
|
else |
|
branch_action="Created new branch" |
|
git worktree add -b "$branch" "$worktree_path" |
|
fi |
|
|
|
if [[ $? -eq 0 ]]; then |
|
echo "✓ ${branch_action}: ${branch}" |
|
echo "✓ Path: ${worktree_path}" |
|
echo "✓ Success! Worktree '${name}' ready on branch '${branch}'" |
|
|
|
# Add post-action to change directory (unless --stay flag is used) |
|
if [[ $stay_flag -eq 0 ]]; then |
|
local temp_file="/tmp/gwt-postaction-$$" |
|
echo "cd:${worktree_path}" > "$temp_file" |
|
fi |
|
else |
|
echo "✗ Failed to create worktree" |
|
return 1 |
|
fi |
|
} |
|
|
|
# Remove worktree |
|
gwt_remove() { |
|
local name="$1" |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt rm <name>" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
# Get branch name from worktree |
|
local branch=$(cd "$worktree_path" && git branch --show-current) |
|
|
|
echo "Removing worktree '${name}'" |
|
echo "Path: ${worktree_path}" |
|
echo "Branch: ${branch}" |
|
|
|
# Prompt for confirmation |
|
read -p "Are you sure? (y/N) " -n 1 -r |
|
echo |
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then |
|
git worktree remove "$worktree_path" |
|
if [[ $? -eq 0 ]]; then |
|
echo "✓ Removed worktree '${name}'" |
|
|
|
# Offer to delete the branch as well |
|
read -p "Also delete branch '${branch}'? (y/N) " -n 1 -r |
|
echo |
|
if [[ $REPLY =~ ^[Yy]$ ]]; then |
|
# Try safe delete first |
|
if git branch -d "$branch" 2>/dev/null; then |
|
echo "✓ Deleted branch '${branch}'" |
|
else |
|
# Branch has unmerged changes |
|
echo "Branch '${branch}' has unmerged changes" |
|
read -p "Force delete anyway? (y/N) " -n 1 -r |
|
echo |
|
if [[ $REPLY =~ ^[Yy]$ ]]; then |
|
git branch -D "$branch" |
|
echo "✓ Force deleted branch '${branch}'" |
|
else |
|
echo "Branch '${branch}' kept" |
|
fi |
|
fi |
|
fi |
|
else |
|
echo "✗ Failed to remove worktree" |
|
return 1 |
|
fi |
|
else |
|
echo "Cancelled" |
|
return 0 |
|
fi |
|
} |
|
|
|
# Change to worktree directory |
|
gwt_cd() { |
|
local name="$1" |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt cd <name>" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
# Use post-action protocol |
|
local temp_file="/tmp/gwt-postaction-$$" |
|
echo "cd:${worktree_path}" > "$temp_file" |
|
} |
|
|
|
# Preview worktree changes in current directory |
|
gwt_preview() { |
|
# Parse flags |
|
local merge_mode=0 |
|
local name="" |
|
|
|
while [[ $# -gt 0 ]]; do |
|
case "$1" in |
|
--merge|-m) |
|
merge_mode=1 |
|
shift |
|
;; |
|
*) |
|
name="$1" |
|
shift |
|
;; |
|
esac |
|
done |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt preview <name> [--merge]" |
|
echo " --merge Use three-way merge (preserves main's changes)" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
# Safety check: require clean working directory |
|
if ! git diff --quiet || ! git diff --cached --quiet; then |
|
echo "Error: Working directory has uncommitted changes" |
|
echo "Please commit or stash your changes first" |
|
return 1 |
|
fi |
|
|
|
# Get branch names |
|
local branch=$(cd "$worktree_path" && git branch --show-current) |
|
local current_branch=$(git branch --show-current) |
|
|
|
# Store in .git so it's repo-specific |
|
local git_dir=$(git rev-parse --git-dir) |
|
local added_files_record="${git_dir}/gwt-preview-added" |
|
|
|
if [[ $merge_mode -eq 1 ]]; then |
|
# Three dots: merge-style (only worktree's changes since divergence) |
|
echo "Applying changes from '${branch}' (merge mode)..." |
|
git diff "${current_branch}...${branch}" --name-status | grep "^A" | cut -f2 > "$added_files_record" |
|
|
|
if git diff "${current_branch}...${branch}" | git apply --3way; then |
|
echo "✓ Changes from '${name}' applied (merge mode)" |
|
echo " Use 'gwt revert' to undo" |
|
else |
|
echo "✗ Failed to apply changes" |
|
echo " Check for conflict markers (<<<<<<) in affected files" |
|
echo " Use 'gwt revert' to undo partial changes" |
|
return 1 |
|
fi |
|
else |
|
# Two dots: replacement-style (make main look exactly like worktree) |
|
echo "Applying '${branch}' state to current directory..." |
|
git diff "${current_branch}..${branch}" --name-status | grep "^A" | cut -f2 > "$added_files_record" |
|
|
|
if git diff "${current_branch}..${branch}" | git apply; then |
|
echo "✓ Now showing '${name}' state" |
|
echo " Use 'gwt revert' to restore main" |
|
else |
|
echo "✗ Failed to apply changes" |
|
rm -f "$added_files_record" |
|
return 1 |
|
fi |
|
fi |
|
} |
|
|
|
# Revert uncommitted changes (undo preview) |
|
gwt_revert() { |
|
_gwt_check_repo || return 1 |
|
|
|
# Store in .git so it's repo-specific |
|
local git_dir=$(git rev-parse --git-dir) |
|
local added_files_record="${git_dir}/gwt-preview-added" |
|
local has_changes=0 |
|
local has_added_files=0 |
|
|
|
# Check for tracked changes |
|
if ! git diff --quiet; then |
|
has_changes=1 |
|
fi |
|
|
|
# Check for added files from preview |
|
if [[ -f "$added_files_record" ]] && [[ -s "$added_files_record" ]]; then |
|
has_added_files=1 |
|
fi |
|
|
|
if [[ $has_changes -eq 0 ]] && [[ $has_added_files -eq 0 ]]; then |
|
echo "Nothing to revert - working directory is clean" |
|
return 0 |
|
fi |
|
|
|
echo "Reverting uncommitted changes..." |
|
|
|
# Revert tracked file changes |
|
if [[ $has_changes -eq 1 ]]; then |
|
git checkout . |
|
fi |
|
|
|
# Remove files that were added by the preview |
|
if [[ $has_added_files -eq 1 ]]; then |
|
while IFS= read -r file; do |
|
if [[ -f "$file" ]]; then |
|
rm "$file" |
|
echo " Removed: $file" |
|
fi |
|
done < "$added_files_record" |
|
rm -f "$added_files_record" |
|
fi |
|
|
|
echo "✓ Working directory restored" |
|
} |
|
|
|
# Hard reset worktree branch to main |
|
gwt_reset() { |
|
local name="$1" |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt reset <name>" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
local branch=$(cd "$worktree_path" && git branch --show-current) |
|
|
|
# Get main branch name (main or master) |
|
local main_branch |
|
if git show-ref --verify --quiet refs/heads/main; then |
|
main_branch="main" |
|
elif git show-ref --verify --quiet refs/heads/master; then |
|
main_branch="master" |
|
else |
|
echo "Error: Could not find main or master branch" |
|
return 1 |
|
fi |
|
|
|
echo "This will hard reset '${branch}' to '${main_branch}'" |
|
echo "All uncommitted and committed changes on '${branch}' will be lost" |
|
read -p "Continue? (y/N) " -n 1 -r |
|
echo |
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then |
|
# Navigate to worktree and perform hard reset |
|
(cd "$worktree_path" && git reset --hard "$main_branch") |
|
echo "✓ Reset '${branch}' to '${main_branch}'" |
|
else |
|
echo "Cancelled" |
|
fi |
|
} |
|
|
|
# Merge worktree branch into main |
|
gwt_merge() { |
|
local name="$1" |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt merge <name>" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
local branch=$(cd "$worktree_path" && git branch --show-current) |
|
local current_branch=$(git branch --show-current) |
|
|
|
# Get main branch name |
|
local main_branch |
|
if git show-ref --verify --quiet refs/heads/main; then |
|
main_branch="main" |
|
elif git show-ref --verify --quiet refs/heads/master; then |
|
main_branch="master" |
|
else |
|
echo "Error: Could not find main or master branch" |
|
return 1 |
|
fi |
|
|
|
# Check we're on main branch |
|
if [[ "$current_branch" != "$main_branch" ]]; then |
|
echo "Error: Must be on '${main_branch}' branch to merge" |
|
echo "Currently on: ${current_branch}" |
|
return 1 |
|
fi |
|
|
|
# Check for clean working directory |
|
if ! git diff --quiet || ! git diff --cached --quiet; then |
|
echo "Error: Working directory has uncommitted changes" |
|
return 1 |
|
fi |
|
|
|
echo "Merging '${branch}' into '${main_branch}'..." |
|
if git merge "$branch"; then |
|
echo "✓ Merged '${branch}' into '${main_branch}'" |
|
else |
|
echo "✗ Merge failed - resolve conflicts manually" |
|
return 1 |
|
fi |
|
} |
|
|
|
# Open worktree in VS Code |
|
gwt_code() { |
|
local name="$1" |
|
|
|
if [[ -z "$name" ]]; then |
|
echo "Error: Worktree name is required" |
|
echo "Usage: gwt code <name>" |
|
return 1 |
|
fi |
|
|
|
_gwt_check_repo || return 1 |
|
_gwt_check_env || return 1 |
|
|
|
local worktree_path="$(_gwt_path "$name")" |
|
|
|
# Check if worktree exists |
|
if [[ ! -d "$worktree_path" ]]; then |
|
echo "Error: Worktree '${name}' not found at: ${worktree_path}" |
|
return 1 |
|
fi |
|
|
|
echo "Opening worktree '${name}' in VS Code..." |
|
echo "Path: ${worktree_path}" |
|
|
|
code -n "$worktree_path" |
|
} |
|
|
|
# ============================================================================ |
|
# MAIN DISPATCHER |
|
# ============================================================================ |
|
|
|
# Get command |
|
cmd="$1" |
|
shift |
|
|
|
# Route to appropriate function |
|
case "$cmd" in |
|
""|"help") |
|
gwt_help |
|
;; |
|
"--help") |
|
gwt_help_detailed |
|
;; |
|
"ls") |
|
gwt_list "$@" |
|
;; |
|
"new") |
|
gwt_new "$@" |
|
|
|
# Process post-actions for new command (when sourced) |
|
temp_file="/tmp/gwt-postaction-$$" |
|
if [[ -f "$temp_file" ]]; then |
|
while IFS=':' read -r action value; do |
|
case "$action" in |
|
"cd") |
|
if [[ -d "$value" ]]; then |
|
cd "$value" || echo "Failed to navigate to: $value" |
|
else |
|
echo "Directory not found: $value" |
|
fi |
|
;; |
|
esac |
|
done < "$temp_file" |
|
rm "$temp_file" |
|
fi |
|
;; |
|
"rm") |
|
gwt_remove "$@" |
|
;; |
|
"cd") |
|
gwt_cd "$@" |
|
|
|
# Process post-actions for cd command (when sourced) |
|
temp_file="/tmp/gwt-postaction-$$" |
|
if [[ -f "$temp_file" ]]; then |
|
while IFS=':' read -r action value; do |
|
case "$action" in |
|
"cd") |
|
if [[ -d "$value" ]]; then |
|
cd "$value" || echo "Failed to navigate to: $value" |
|
else |
|
echo "Directory not found: $value" |
|
fi |
|
;; |
|
esac |
|
done < "$temp_file" |
|
rm "$temp_file" |
|
fi |
|
;; |
|
"code") |
|
gwt_code "$@" |
|
;; |
|
"preview") |
|
gwt_preview "$@" |
|
;; |
|
"revert") |
|
gwt_revert "$@" |
|
;; |
|
"reset") |
|
gwt_reset "$@" |
|
;; |
|
"merge") |
|
gwt_merge "$@" |
|
;; |
|
*) |
|
echo "Error: Unknown command '${cmd}'" |
|
echo "" |
|
gwt_help |
|
exit 1 |
|
;; |
|
esac |