From: Tracey Emery Subject: Re: fix 'got update' with added + obstructed file To: Stefan Sperling Cc: gameoftrees@openbsd.org Date: Fri, 24 Sep 2021 15:44:17 -0600 On Fri, Sep 24, 2021 at 11:31:14PM +0200, Stefan Sperling wrote: > When 'got update' tries to add a new file to the work tree and this > file is obstructed by a directory on disk, the update fails like this: > > $ got update > ? new > got: new: Is a directory > $ > > And the work tree is not updated. The above update with error can be > run over and over and won't proceed until the directory is removed. > The problem here is simply that the update as a whole should succeed, > not stop on one such file even though there might be more files to update. > > With the patch below this situation is properly detected as an obstruction > and the update succeeds: > > $ got update > ~ new > Updated to refs/heads/master: c1f85b4938dc4c668a88f13df2b98a520fc077cc > File paths obstructed by a non-regular file: 1 > $ > > Regardless, the file 'new' will not be added to the work tree until the > directory is moved and 'got update' is run again. > > And I am extending a corresponding test to cover this issue. > > ok? Looks good. > > diff f365d76274ee1ae2b57225686a0733176fc4bfb2 /home/stsp/src/got > blob - f5bc677438d23ddca778382674edef04e09cb939 > file + lib/worktree.c > --- lib/worktree.c > +++ lib/worktree.c > @@ -1942,8 +1942,20 @@ update_blob(struct got_worktree *worktree, > if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE) > sb.st_mode = got_fileindex_perms_to_st(ie); > } else { > - sb.st_mode = GOT_DEFAULT_FILE_MODE; > - status = GOT_STATUS_UNVERSIONED; > + if (stat(ondisk_path, &sb) == -1) { > + if (errno != ENOENT) { > + err = got_error_from_errno2("stat", > + ondisk_path); > + goto done; > + } > + sb.st_mode = GOT_DEFAULT_FILE_MODE; > + status = GOT_STATUS_UNVERSIONED; > + } else { > + if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) > + status = GOT_STATUS_UNVERSIONED; > + else > + status = GOT_STATUS_OBSTRUCTED; > + } > } > > if (status == GOT_STATUS_OBSTRUCTED) { > blob - cae602420f097ed69b049e9fffb3fc46510d2de5 > file + regress/cmdline/update.sh > --- regress/cmdline/update.sh > +++ regress/cmdline/update.sh > @@ -2588,6 +2588,8 @@ test_update_file_skipped_due_to_obstruction() { > blob_id0=`get_blob_id $testroot/repo "" beta` > > echo "changed beta" > $testroot/repo/beta > + echo "new file" > $testroot/repo/new > + (cd $testroot/repo && git add new) > git_commit $testroot/repo -m "changed beta" > local commit_id1=`git_show_head $testroot/repo` > blob_id1=`get_blob_id $testroot/repo "" beta` > @@ -2617,14 +2619,22 @@ test_update_file_skipped_due_to_obstruction() { > > rm $testroot/wt/beta > mkdir -p $testroot/wt/beta/psi > + mkdir -p $testroot/wt/new > > - # update to the latest commit; this skips beta > + # update to the latest commit; this skips beta and the new file > (cd $testroot/wt && got update > $testroot/stdout) > + ret="$?" > + if [ "$ret" != "0" ]; then > + echo "update failed unexpectedly" >&2 > + test_done "$testroot" "1" > + return 1 > + fi > > echo "~ beta" > $testroot/stdout.expected > + echo "~ new" >> $testroot/stdout.expected > echo "Updated to refs/heads/master: $commit_id1" \ > >> $testroot/stdout.expected > - echo "File paths obstructed by a non-regular file: 1" \ > + echo "File paths obstructed by a non-regular file: 2" \ > >> $testroot/stdout.expected > cmp -s $testroot/stdout.expected $testroot/stdout > ret="$?" > @@ -2656,8 +2666,11 @@ test_update_file_skipped_due_to_obstruction() { > # updating to the latest commit should now update beta > (cd $testroot/wt && got update > $testroot/stdout) > echo "! beta" > $testroot/stdout.expected > + echo "~ new" >> $testroot/stdout.expected > echo "Updated to refs/heads/master: $commit_id1" \ > >> $testroot/stdout.expected > + echo "File paths obstructed by a non-regular file: 1" \ > + >> $testroot/stdout.expected > cmp -s $testroot/stdout.expected $testroot/stdout > ret="$?" > if [ "$ret" != "0" ]; then -- Tracey Emery