Help and docs
Sign in

grindlemire/dotfiles code browser

master 8526099
Bash · 162 lines · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
_wt_require_repo() {
    local cmd="$1"
    if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        echo "${cmd}: not inside a git repository" >&2
        return 1
    fi
}

_wt_repo_root() {
    git rev-parse --show-toplevel 2>/dev/null
}

_wt_default_dir() {
    local root
    root=$(_wt_repo_root) || return 1
    local parent
    parent=$(dirname "$root")
    local name
    name=$(basename "$root")
    printf "%s/.worktrees" "$root"
}

_wt_lookup_path() {
    local target="$1"
    git worktree list --porcelain | awk -v target="$target" '
        BEGIN { RS=""; FS="\n" }
        {
            path=""; branch="";
            for (i=1; i<=NF; i++) {
                if ($i ~ /^worktree /) {
                    path=substr($i,10)
                } else if ($i ~ /^branch /) {
                    branch=substr($i,8)
                    sub(/^refs\/heads\//,"",branch)
                }
            }
            if (path == target || branch == target) {
                print path
                exit
            }
        }
    '
}

wtc() {
    _wt_require_repo wtc || return 1

    if [ -z "$1" ]; then
        echo "usage: wtc <branch> [path]" >&2
        return 1
    fi

    local branch="$1"
    local worktree_path="$2"
    local default_parent
    default_parent=$(_wt_default_dir) || return 1

    if [ -z "$worktree_path" ]; then
        worktree_path="${default_parent}/${branch}"
    fi

    if [ -e "$worktree_path" ]; then
        echo "wtc: target path already exists: $worktree_path" >&2
        return 1
    fi

    local parent_dir
    parent_dir=$(dirname "$worktree_path")
    mkdir -p "$parent_dir" || return 1

    if git show-ref --verify --quiet "refs/heads/${branch}"; then
        git worktree add "$worktree_path" "$branch" || return 1
    else
        git worktree add -b "$branch" "$worktree_path" || return 1
    fi

    cd "$worktree_path" || return 1
}

wtd() {
    _wt_require_repo wtd || return 1

    local force_flag=0
    case "$1" in
        -f|--force)
            force_flag=1
            shift
            ;;
    esac

    if [ -z "$1" ]; then
        echo "usage: wtd [-f|--force] <path-or-branch>" >&2
        return 1
    fi

    local target="$1"
    local worktree_path=""

    if [ -d "$target" ]; then
        worktree_path="$target"
    else
        worktree_path=$(_wt_lookup_path "$target")

        if [ -z "$worktree_path" ]; then
            local default_parent
            default_parent=$(_wt_default_dir) || return 1
            local candidate="${default_parent}/${target}"
            if [ -d "$candidate" ]; then
                worktree_path="$candidate"
            fi
        fi
    fi

    if [ -z "$worktree_path" ]; then
        echo "wtd: no worktree found for '$target'" >&2
        return 1
    fi

    # If we're currently in the worktree or a subdirectory of it, cd to repo root
    if [ -n "$worktree_path" ] && [ -d "$worktree_path" ]; then
        local current_pwd="$(pwd)"
        # Check if current directory is the worktree or a subdirectory of it
        if [[ "$current_pwd" == "$worktree_path" || "$current_pwd" == "$worktree_path"/* ]]; then
            local repo_root
            repo_root=$(_wt_lookup_path main)
            if [ -n "$repo_root" ]; then
                cd "$repo_root"
            fi
        fi
    fi

    if [ "$force_flag" -eq 1 ]; then
        git worktree remove --force "$worktree_path"
    else
        git worktree remove "$worktree_path"
    fi
}

wtl() {
    _wt_require_repo wtl || return 1

    git worktree list --porcelain | awk '
        BEGIN { RS=""; FS="\n" }
        {
            path=""; head=""; branch="";
            for (i=1; i<=NF; i++) {
                if ($i ~ /^worktree /) {
                    path=substr($i,10)
                } else if ($i ~ /^HEAD /) {
                    head=substr($i,6)
                } else if ($i ~ /^branch /) {
                    branch=substr($i,8)
                    sub(/^refs\/heads\//,"",branch)
                }
            }
            if (branch == "") {
                branch="(detached)"
            }
            printf "%-40s %-25s %s\n", path, branch, head
        }
    '
}