The fourth review looked only at the changes of the third and found two ways,
both opened by those changes, in which finishing an unfinished checkout cost
the user something, and a few smaller things.
- A file somebody added to the index with git, and that the commit does not
have, was removed by the forced checkout. The completion is now refused,
names the file, and says how to go on ('git reset', or move the folder).
- Where the repository has a symbolic link, the folders on the way to it were
no longer checked for links, so a link behind a linked folder could be
replaced outside the clone. The way is checked again, and a link in the
folder is the checkout's own only when it leads where the repository's does
(also on a first checkout, where any link was taken before).
- Whether a marked folder holds its whole tree is asked of the files, not of
the index: what the index says is whoever's git wrote it.
- A path recovery of an unfinished checkout whose branch had to move accepts
the files of the commit it left (whole content), and takes the list of those
commits off when it has written the tree.
- Tests for each, for a list that holds what is not a commit, for the list's
cap and its entries being recorded once, for a file written before the
attributes that change it, and for a link to a folder in a finished tree.
The test of a rewritten history now writes the file it makes a statement
about, and states what happens to it: it stays, untracked.
- README and threat model say what the code does, and name what is not
covered: a marked folder whose index somebody's git wrote and whose last
file was cut off is taken for finished; files of a commit the branch left
stay in the folder.
- The tests that run the WSL clone script use the shell Git for Windows'
launcher starts, not the launcher: it puts git's folders in front of the
path, so the stand-in for git was never found when the tests were started
from PowerShell (as CI starts them), and two of them failed there.
Refs #174
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The third review confirmed, under real process kills, that a checkout that
was cut off leaves no index, and found no way left to replace or delete a
user's file. It found five narrow cases in which gclo refused, failed or said
done where it used to complete the tree.
- When the branch of an unfinished checkout must move before it is written
(a tree Windows cannot write, or a history origin rewrote), the commit it
leaves is recorded, and its files on disk are recognised by it as well.
A history origin rewrote is followed again, as on main.
- A file is the unfinished checkout's own when it holds what the commit
stores or what the checkout filters make of it (the 'ident' attribute).
- Where the repository has a symbolic link, a link in the folder is the
checkout's own.
- A marked folder is taken for finished only when its index and its files
hold the whole tree of its commit: an index somebody's git wrote over an
unfinished tree does not make it whole.
- A link where the repository has a submodule is refused; a link is something
with a target, not anything with a reparse point.
- Tests for each, for a file stored with carriage returns, for a completion
that fails half-way, and for the order of what following origin's default
branch writes. The message of an ordinary update that would replace files
no longer says who changed them.
Refs #174
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The second review showed that telling gclo's files from a user's by exact
content does not hold: with line endings being converted, the completion
refused files its own cut-off checkout had written, and a retry interrupted
after the branch had moved refused them for ever. It also found a user's file
deleted where a submodule's parent folder is needed.
- A marked folder is an unfinished checkout only while it has no index (git
writes the index when a checkout has reached its end). A marked folder with
an index is updated like any clone, without force.
- An unfinished checkout is completed at the commit its branch is on, before
the branch moves; what origin has got since comes with the ordinary pull.
When that commit or origin's cannot be written on Windows, the typed failure
and the marker are kept as before.
- A file is the unfinished checkout's own when it holds the commit's content
or the beginning of it, carriage returns aside.
- Refused as well: a file where a submodule's parent folder is needed, a link
at a destination, a folder there that is not empty.
- Only a repository without branches of its own is an empty clone, and it
follows origin's default branch only when its folder holds nothing but .git.
- An ordinary update that would replace files changed or added here says so.
- The refusals are Windows' rules and apply on Windows.
- WSL: 'mv -T'; the temporary folder's name is refused as an organization.
The run tests find Git for Windows' shell beside git.exe and say when they
had nothing to run.
Refs #174
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The first review reproduced two ways in which this change itself replaced a
user's files, and several holes in what it claimed.
- A repository that has local branches is left alone when its HEAD names a
branch without commits: that is a branch somebody started, not an empty
clone. Origin's default branch is followed only by a repository that has no
branch of its own, and nothing changes before every check has passed.
- The first checkout and the completion of a cut-off checkout go through the
refusals of the path recovery before anything changes: a link on the way, a
file where a folder is needed, a folder with files where a file is needed,
a file that is not what the unfinished checkout wrote, and anything but an
empty folder where the repository has a submodule. The file a cut-off
checkout was writing counts as gclo's and is finished.
- A branch's upstream is configured before the branch exists, and a marker
without a branch starts the first checkout over instead of reporting an
empty folder as done.
- The WSL clone uses a temporary folder of gclo's own, removes it on signals
too, does not move into a destination that appeared meanwhile, accepts an
empty folder at the destination, and removes old leftovers only from its own
folder. The script is now also run for real by the tests.
- One operation per folder: the long-path spelling of a folder is the same
folder, and the message fits every holder.
Refs #174
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
- The first checkout of a clone that was empty refuses, before anything
changes, when something is already where the repository has a file or needs
a folder: a forced checkout would have replaced it.
- The folder is marked unfinished before its branch is created, so a checkout
that is cut off is completed by the next sync instead of being taken for up
to date.
- An empty clone follows origin's default branch when origin does not have the
branch the local HEAD names.
- One git operation per folder at a time in a process. A canceled sync stops
waiting for its operations without stopping them; a second operation in the
same folder is refused until the first has ended.
- A clone without .git/index says so and how to rebuild it, instead of git's
count of conflicts.
- Clone in WSL clones under a temporary name and moves the folder into place
when it is complete; leftovers of killed runs are removed once a day old.
Closes#174
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>