-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathocd-install.sh
More file actions
executable file
·166 lines (139 loc) · 4.69 KB
/
ocd-install.sh
File metadata and controls
executable file
·166 lines (139 loc) · 4.69 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
163
164
165
166
#!/usr/bin/env bash
# ocd-install.sh - Setup script for minimalistic Git dotfile tracking.
# <https://github.com/nycksw/ocd>
set -e
usage() {
echo "Usage: $0 [-r <REMOTE>] [-c] [-h] [-g] [-H <OCD_HOME>] [-B <OCD_BARE>]"
echo
echo " -r <REMOTE> Set remote repo URL (e.g., git@github.com:USER/REPO.git)."
echo " -c Clobber local dotfiles with the remote version."
echo " -h Install a pre-commit hook to prevent large commits."
echo " -g Fetch a large excludesFile to ignore secrets/junk."
echo
echo " -H <OCD_HOME> Working tree (default: \$HOME)."
echo " -B <OCD_BARE> Bare repo dir (default: \$OCD_HOME/.ocd)."
echo
echo "Examples:"
echo " # Basic usage"
echo " $0 -r git@github.com:USER/REPO.git -c -h -g"
echo
echo " # Custom home and bare repo directory"
echo " $0 -r git@github.com:USER/REPO.git -c -h -g -H /tmp/ocdtest -B /tmp/ocdtest/.ocd"
exit 1
}
while getopts "r:H:B:chg" opt; do
case "$opt" in
r) OCD_REMOTE="$OPTARG" ;;
H) OCD_HOME="$OPTARG" ;;
B) OCD_BARE="$OPTARG" ;;
c) OCD_CLOBBER='y' ;;
h) OCD_HOOK='y' ;;
g) OCD_GITIGNORE='y' ;;
*) usage ;;
esac
done
OCD_HOME="${OCD_HOME:-$HOME}"
OCD_BARE="${OCD_BARE:-$OCD_HOME/.ocd}"
fail_if_not_interactive() {
if [ ! -t 0 ]; then
echo "Non-interactive mode requires -r, -c, -h, and -g flags (no prompts)." >&2
exit 1
fi
}
if [ -d "$OCD_BARE" ]; then
if [[ $OCD_CLOBBER =~ ^[yY] ]]; then
OCD_BACKUP="${OCD_BARE}_backup_$(date +%s)"
mv "$OCD_BARE" "$OCD_BACKUP"
echo "[!] $OCD_BARE -> $OCD_BACKUP"
else
echo "$OCD_BARE already exists." >&2
echo "Move or remove it before re-running, or use -c." >&2
exit 1
fi
fi
cat << 'END'
This will create a bare local repo for managing dotfiles using your
homedir as the work tree and a remote repo for backup/sync.
WARNING! If you use a remote repo with existing dotfiles, local versions
will be overwritten.
END
# Prompt if OCD_REMOTE is missing
while [[ -z "$OCD_REMOTE" ]]; do
fail_if_not_interactive
read -p "Enter Git remote URL (e.g., git@github.com:USER/REPO.git): " \
-r OCD_REMOTE
done
# Prompt if OCD_CLOBBER isn't set.
if [[ -z "$OCD_CLOBBER" ]]; then
fail_if_not_interactive
read -p "Overwrite local dotfiles with $OCD_REMOTE? (y/N): " -r OCD_CLOBBER
[ -z "$OCD_CLOBBER" ] && OCD_CLOBBER='n'
fi
if [[ "$OCD_CLOBBER" =~ ^[nN] ]]; then
echo "This setup overwrites any local dotfiles with those in your remote " \
"repo. Exiting."
exit
else
echo "OCD_CLOBBER='y' => local files may be overwritten."
echo
fi
OCD="git --git-dir=$OCD_BARE --work-tree=$OCD_HOME"
# Clone remote as a bare repo.
git clone --bare "$OCD_REMOTE" "$OCD_BARE"
chmod 700 "$OCD_BARE"
# Local untracked files remain hidden in Git status.
$OCD config --local status.showUntrackedFiles no
# Overwrite local files from remote HEAD.
$OCD reset --hard HEAD
$OCD checkout-index -f -a
echo -e "\n[*] $OCD_REMOTE cloned into $OCD_BARE as a bare repo."
# Optional pre-commit hook.
if [[ -z "$OCD_HOOK" ]]; then
fail_if_not_interactive
read -p "Install pre-commit hook to prevent accidental commits? (Y/n): " \
-r OCD_HOOK
[ -z "$OCD_HOOK" ] && OCD_HOOK='y'
fi
if [[ "$OCD_HOOK" =~ ^[yY] ]]; then
mkdir -p "$OCD_BARE/hooks"
HOOK="$OCD_BARE/hooks/pre-commit"
cat << 'END' > "$HOOK"
#!/usr/bin/env bash
MAX_ALLOWED=20
STAGED_COUNT=$(git diff --cached --name-only | wc -l)
WORK_TREE=$(git rev-parse --work-tree)
if [[ "$STAGED_COUNT" -gt "$MAX_ALLOWED" ]]; then
echo "[!] You are about to commit $STAGED_COUNT files from: $WORK_TREE"
echo "If you really want to do this, use '--no-verify'."
exit 1
fi
END
chmod +x "$HOOK"
echo "[*] Pre-commit hook installed at: $HOOK"
fi
# Optional excludesFile.
if [[ -z "$OCD_GITIGNORE" ]]; then
fail_if_not_interactive
read -p "Fetch a big excludesFile to ignore secrets/junk? (Y/n): " \
-r OCD_GITIGNORE
[ -z "$OCD_GITIGNORE" ] && OCD_GITIGNORE='y'
fi
if [[ "$OCD_GITIGNORE" =~ ^[yY] ]]; then
IGNORE_FILE="$OCD_HOME/.gitignore_ocd"
# Fetch the pre-generated compressed gitignore file.
curl -fsSL "https://raw.githubusercontent.com/nycksw/ocd/main/gitignore_ocd.gz" \
| gunzip > "$IGNORE_FILE"
$OCD config --local core.excludesFile "$IGNORE_FILE"
ls -lh "$IGNORE_FILE"
echo -e "\nTip: Use \"ocd check-ignore -v \$(basename \"$IGNORE_FILE\")\" " \
"to troubleshoot matching rules."
fi
cat << END
[*] All done!
Add an alias in your shell rc:
alias ocd='git --git-dir=\$HOME/.ocd --work-tree=\$HOME'
Then "ocd add", "ocd commit", etc.
One-liner for new machine setup:
curl -fsSL "https://raw.githubusercontent.com/nycksw/ocd/main/ocd-install.sh" \\
| bash -s -- -r "$OCD_REMOTE" -c -h -g
END