Skip to content

Commit 1af2891

Browse files
committed
fix(lazygit): harden autosquash command
Replace the S commits custom command's inline /bin/sh + awk pipeline with explicit shell steps. Handle empty histories with a direct HEAD check, keep target resolution logic in shell for clearer failure modes, and fall back to --root when the oldest autosquash target is the root commit.
1 parent 639e664 commit 1af2891

1 file changed

Lines changed: 91 additions & 46 deletions

File tree

modules/home/programs/terminal/tools/lazygit/custom-commands.nix

Lines changed: 91 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,62 +19,107 @@
1919
{
2020
key = "S";
2121
context = "commits";
22-
command = ''
23-
/bin/sh -lc '
22+
command = /* Bash */ ''
2423
set -eu
2524
26-
rc=0
27-
oldest="$(
28-
git log --reverse --format="%H%x09%s" HEAD | awk -F "\t" "
29-
BEGIN { fixupCount = 0; resolvedCount = 0; nextIdx = 0; }
30-
{
31-
sha = \$1;
32-
subject = \$2;
33-
if (subject ~ /^(fixup! |squash! )/) {
34-
fixupCount++;
35-
targetSubject = subject;
36-
sub(/^(fixup! |squash! )/, \"\", targetSubject);
37-
targetSha = latest[targetSubject];
38-
if (targetSha != \"\") {
39-
resolvedCount++;
40-
used[targetSha] = 1;
41-
}
42-
} else {
43-
nextIdx++;
44-
idx[sha] = nextIdx;
45-
latest[subject] = sha;
46-
}
47-
}
48-
END {
49-
if (fixupCount == 0) exit 2;
50-
if (resolvedCount == 0) exit 3;
51-
oldestSha = \"\";
52-
oldestIdx = 0;
53-
for (sha in used) {
54-
if (oldestSha == \"\" || idx[sha] < oldestIdx) {
55-
oldestSha = sha;
56-
oldestIdx = idx[sha];
57-
}
58-
}
59-
if (oldestSha == \"\") exit 4;
60-
print oldestSha;
61-
}
62-
"
63-
)" || rc=$?
25+
if ! git rev-parse --verify HEAD >/dev/null 2>&1; then
26+
echo "No commits found on this branch."
27+
exit 1
28+
fi
29+
30+
workDir="''${TMPDIR:-/tmp}/lazygit-autosquash-$$"
31+
rm -rf "$workDir"
32+
mkdir -p "$workDir"
33+
trap 'rm -rf "$workDir"' EXIT HUP INT TERM
34+
35+
historyFile="$workDir/history"
36+
latestFile="$workDir/latest"
37+
orderFile="$workDir/order"
38+
usedFile="$workDir/used"
39+
tab="$(printf '\t')"
40+
41+
: > "$latestFile"
42+
: > "$orderFile"
43+
: > "$usedFile"
44+
45+
git --no-pager log --reverse --format='%H%x09%s' HEAD > "$historyFile"
46+
47+
fixupCount=0
48+
resolvedCount=0
49+
50+
while IFS= read -r line; do
51+
sha="''${line%%"$tab"*}"
52+
subject="''${line#*"$tab"}"
53+
54+
case "$subject" in
55+
"fixup! "*)
56+
fixupCount=$((fixupCount + 1))
57+
targetSubject="''${subject#fixup! }"
58+
;;
59+
"squash! "*)
60+
fixupCount=$((fixupCount + 1))
61+
targetSubject="''${subject#squash! }"
62+
;;
63+
*)
64+
printf '%s\t%s\n' "$sha" "$subject" >> "$latestFile"
65+
printf '%s\n' "$sha" >> "$orderFile"
66+
continue
67+
;;
68+
esac
6469
65-
if [ "$rc" -eq 2 ]; then
70+
targetSha=""
71+
while IFS= read -r entry; do
72+
entrySha="''${entry%%"$tab"*}"
73+
entrySubject="''${entry#*"$tab"}"
74+
75+
if [ "$entrySubject" = "$targetSubject" ]; then
76+
targetSha="$entrySha"
77+
fi
78+
done < "$latestFile"
79+
80+
if [ -n "$targetSha" ]; then
81+
resolvedCount=$((resolvedCount + 1))
82+
printf '%s\n' "$targetSha" >> "$usedFile"
83+
fi
84+
done < "$historyFile"
85+
86+
if [ "$fixupCount" -eq 0 ]; then
6687
echo "No fixup!/squash! commits found on this branch."
6788
exit 1
68-
elif [ "$rc" -eq 3 ]; then
89+
fi
90+
91+
if [ "$resolvedCount" -eq 0 ]; then
6992
echo "Found fixup!/squash! commits, but could not resolve target commits."
7093
exit 1
71-
elif [ "$rc" -ne 0 ] || [ -z "$oldest" ]; then
72-
echo "Unable to determine oldest target commit."
94+
fi
95+
96+
oldestTargetSha=""
97+
while IFS= read -r candidateSha; do
98+
targetUsed=0
99+
100+
while IFS= read -r usedSha; do
101+
if [ "$usedSha" = "$candidateSha" ]; then
102+
targetUsed=1
103+
break
104+
fi
105+
done < "$usedFile"
106+
107+
if [ "$targetUsed" -eq 1 ]; then
108+
oldestTargetSha="$candidateSha"
109+
break
110+
fi
111+
done < "$orderFile"
112+
113+
if [ -z "$oldestTargetSha" ]; then
114+
echo "Unable to determine the oldest fixup target commit."
73115
exit 1
74116
fi
75117
76-
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --no-verify "$oldest^"
77-
'
118+
if git rev-parse --verify "$oldestTargetSha^" >/dev/null 2>&1; then
119+
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --no-verify "$oldestTargetSha^"
120+
else
121+
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --no-verify --root
122+
fi
78123
'';
79124
description = "Autosquash all fixup/squash commits (auto-detect oldest target, skip hooks)";
80125
loadingText = "Autosquashing fixup commits...";

0 commit comments

Comments
 (0)