Skip to content

Commit e4e128c

Browse files
committed
Proceed when target is absent; account for merges
This modifies the script so that: - When the target does not exist on disk at all, we proceed, even if the deletion is an unstaged change. - When there is an uncommitted merge, as happens when a conflict is being resolved (and occasionally otherwise), recognize this case (rather than misinterpreting the short status output), proceeding only if there are no changes at all at the target. Even staged changes cause the copy to be cancelled in that case. - Some cumbersomely expressed code is written more clearly, a couple of specific error messages are added for what should be rare failures of git commands, checking for grep failure is removed (grep should not actually fail if used correctly), and the big comment in first_line_ends_crlf is made more accurate.
1 parent 2e83766 commit e4e128c

File tree

1 file changed

+56
-26
lines changed

1 file changed

+56
-26
lines changed

etc/copy-packetline.sh

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,58 @@ function fail () {
1616
exit 1
1717
}
1818

19-
function status () {
20-
git status --short --ignored=traditional -- "$@"
19+
function chdir_toplevel() {
20+
local root
21+
22+
# NOTE: We get the wrong directory name, if the name ends in newline.
23+
root="$(git rev-parse --show-toplevel)" ||
24+
fail 'git-rev-parse failed to find top-level dir'
25+
26+
cd -- "$root"
27+
}
28+
29+
function merging () {
30+
local git_dir
31+
32+
# NOTE: We get the wrong directory name, if the name ends in newline.
33+
git_dir="$(git rev-parse --git-dir)" ||
34+
fail 'git-rev-parse failed to find git dir'
35+
36+
test -e "$git_dir/MERGE_HEAD"
37+
}
38+
39+
function target_status () {
40+
git status --short --ignored=traditional -- gix-packetline-blocking/src ||
41+
fail 'git-status failed'
2142
}
2243

23-
function avoids_pattern () (
24-
set +e # Temporary, since the function body is in ( ).
25-
grep -q "$@"
26-
test "$?" -eq 1 # Distinguish no-match from error.
27-
)
44+
function check_target () {
45+
if ! test -e "gix-packetline-blocking/src"; then
46+
# The target does not exist on disk, so nothing will be lost. Proceed.
47+
return
48+
fi
49+
50+
if merging; then
51+
# In a merge, it would be confusing to replace anything at the target.
52+
if target_status | grep -q '^'; then
53+
fail 'target exists, and a merge is in progress'
54+
fi
55+
else
56+
# We can lose data if anything of value at the target is not in the index.
57+
if target_status | grep -q '^.[^ ]'; then
58+
fail 'target exists, with unstaged changes or ignored files'
59+
fi
60+
fi
61+
}
2862

2963
function indent () {
3064
sed 's/^/ /'
3165
}
3266

3367
function generate_all () {
34-
local root failures
68+
local failures
3569

36-
# Find the working tree. (NOTE: Wrong if the directory name ends in newline.)
37-
root="$(git rev-parse --show-toplevel)"
38-
cd -- "$root"
70+
chdir_toplevel
3971

4072
if ! test -d gix-packetline/src; then
4173
fail 'no source directory: gix-packetline/src'
@@ -44,12 +76,9 @@ function generate_all () {
4476
fail 'no target parent directory: gix-packetline-blocking'
4577
fi
4678

47-
# FIXME: This misinterprets the status when in an unresolved merge conflict!
48-
if ! status gix-packetline-blocking/src | avoids_pattern '^.[^ ]'; then
49-
fail 'target has unstaged changes or contains ignored files'
50-
fi
79+
check_target
5180

52-
rm -rf gix-packetline-blocking/src # No trailing /, as it may be a symlink.
81+
rm -rf gix-packetline-blocking/src # No trailing /. It may be a symlink.
5382
if test -e gix-packetline-blocking/src; then
5483
fail 'unable to remove target'
5584
fi
@@ -67,16 +96,17 @@ function generate_all () {
6796
}
6897

6998
function first_line_ends_crlf () {
70-
# This is tricky to check portably. On Windows in Cygwin-like environments
71-
# including MSYS2 and Git Bash, most text processing tools, including awk,
72-
# sed, and grep, automatically substitute \n for \r\n. Some can be told not
73-
# to, but in non-portable ways that may affect other implementations. Bash
74-
# does so on command substitution and other input, and optionally more often.
75-
# Easy ways to check are often non-portable to other OSes. Fortunately, tools
76-
# that treat input as binary data are exempt (including cat, but "-v" is not
77-
# portable, and it's unreliable in general as lines can end in "^M"). This
78-
# may be doable without od, by using tr more heavily, but it could be hard to
79-
# avoid false positives with unexpected characters, or with \r not before \n.
99+
# This is tricky to check portably. In Cygwin-like environments including
100+
# MSYS2 and Git Bash, most text processing tools, including awk, sed, and
101+
# grep, automatically ignore \r before \n. Some ignore \r everywhere. Some
102+
# can be told to keep \r, but in non-portable ways that may affect other
103+
# implementations. Bash ignores \r in some places even without "-o icncr",
104+
# and ignores \r even more with it, including in all text from command
105+
# substitution. Simple checks may be non-portable to other OSes. Fortunately,
106+
# tools that treat input as binary data are exempt (even cat, but "-v" is
107+
# non-portable, and unreliable in general because lines can end in "^M").
108+
# This may be doable without od, by using tr more heavily, but it could be
109+
# hard to avoid false positives with unexpected characters or \r without \n.
80110

81111
head -n 1 -- "$1" | # Get the longest prefix with no non-trailing \n byte.
82112
od -An -ta | # Represent all bytes symbolically, without addresses.

0 commit comments

Comments
 (0)