Support shallow sync when the rev is not in-range

If I ask for `--depth 1` and a branch, it's fine.

If I ask for `--depth 1` and a tag, and that tag is not within 1 commit
of the branch that was cloned, it will give an error.  Oddly, if the
initial `clone` was OK, and subsequent syncs drift, it is OK, because of
how we `fetch`.  But if it is too far away at the beginning, kaboom.

This betrays that the current model of `--branch` and `--rev` is really
broken, and should be revamped.  For now, I did something simple - if
the rev can't be found, try a fetch.  A "real" fix is more involved.

Also add tests.
This commit is contained in:
Tim Hockin 2022-08-15 10:19:29 -07:00
parent 12a1d1e298
commit ff0a73f5ad
2 changed files with 92 additions and 3 deletions

View File

@ -1345,7 +1345,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
if err != nil {
return false, "", err
}
hash, err = git.LocalHashForRev(ctx, git.rev)
hash, err = git.ensureLocalHashForRev(ctx, git.rev)
if err != nil {
return false, "", err
}
@ -1368,6 +1368,46 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
return true, hash, git.AddWorktreeAndSwap(ctx, hash)
}
func (git *repoSync) ensureLocalHashForRev(ctx context.Context, rev string) (string, error) {
hash, err := git.LocalHashForRev(ctx, rev)
if err == nil {
return hash, nil
}
// git might return either error, based on flags used internal to
// LocalHashForRev, so we will consider either one to be a "rev not found".
if es := err.Error(); !stringContainsOneOf(es, "unknown revision", "bad revision") {
return "", err
}
// The rev was not found, try to fetch it.
git.log.V(1).Info("rev was not found, trying fetch", "rev", git.rev)
args := []string{"fetch", "-f", "--tags"}
if git.depth != 0 {
args = append(args, "--depth", strconv.Itoa(git.depth))
}
args = append(args, git.repo, "--")
if _, err := git.run.Run(ctx, git.root, nil, git.cmd, args...); err != nil {
return "", err
}
// Try again.
hash, err = git.LocalHashForRev(ctx, git.rev)
if err != nil {
return "", err
}
return hash, nil
}
func stringContainsOneOf(s string, matches ...string) bool {
for _, m := range matches {
if strings.Contains(s, m) {
return true
}
}
return false
}
// GetRevs returns the local and upstream hashes for rev.
func (git *repoSync) GetRevs(ctx context.Context) (string, string, error) {
// Ask git what the exact hash is for rev.

View File

@ -934,10 +934,10 @@ function e2e::sync_slow_git_long_timeout() {
##############################################
# Test depth syncing
##############################################
function e2e::sync_depth_shallow() {
function e2e::sync_branch_depth_shallow() {
# First sync
echo "$FUNCNAME 1" > "$REPO"/file
expected_depth="1"
echo "$FUNCNAME 1" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME 1"
GIT_SYNC \
@ -981,6 +981,55 @@ function e2e::sync_depth_shallow() {
fi
}
##############################################
# Test depth syncing with a tag not within depth
##############################################
function e2e::sync_tag_depth_shallow_out_of_range() {
TAG="e2e-tag"
expected_depth="1"
# First commits, tag is not within --depth
echo "$FUNCNAME 1" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME 1"
git -C "$REPO" tag -af "$TAG" -m "$FUNCNAME 1" >/dev/null
echo "$FUNCNAME 2" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME 2"
GIT_SYNC \
--period=100ms \
--repo="file://$REPO" \
--branch="$MAIN_BRANCH" \
--rev="$TAG" \
--depth="$expected_depth" \
--root="$ROOT" \
--link="link" \
>> "$1" 2>&1 &
sleep 3
assert_link_exists "$ROOT"/link
assert_file_exists "$ROOT"/link/file
assert_file_eq "$ROOT"/link/file "$FUNCNAME 1"
depth=$(GIT_DIR="$ROOT"/link/.git git log | grep commit | wc -l)
if [[ $expected_depth != $depth ]]; then
fail "initial depth mismatch expected=$expected_depth actual=$depth"
fi
# Make 2 new commits, and tag the older one, so it's not within --depth
echo "$FUNCNAME 3" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME 3"
SHA=$(git -C "$REPO" rev-parse HEAD)
echo "$FUNCNAME 4" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME 4"
git -C "$REPO" tag -af "$TAG" -m "$FUNCNAME 3" "$SHA" >/dev/null
sleep 3
assert_link_exists "$ROOT"/link
assert_file_exists "$ROOT"/link/file
assert_file_eq "$ROOT"/link/file "$FUNCNAME 3"
depth=$(GIT_DIR="$ROOT"/link/.git git log | grep commit | wc -l)
if [[ $expected_depth != $depth ]]; then
fail "forward depth mismatch expected=$expected_depth actual=$depth"
fi
}
##############################################
# Test fetch skipping commit
##############################################