commit da165977d65c74af18c41b44f93df986324a66fe from: Stefan Sperling via: Thomas Adam date: Tue Jun 18 20:20:12 2024 UTC show a more useful error when a reference name collides with another If a reference cannot be created because a file is present where a directory would need to be created to accomodate the new ref's name, report a name collision rather than an obscure mkstemps ENOTDIR error. issue found by Lucas commit - ad18dfab1c13f15a03638c10db626a4f39827d95 commit + da165977d65c74af18c41b44f93df986324a66fe blob - 2a5a6702d514b6a921362edba623fc8a3d056f46 blob + 0573efa2859ab011ad5cbc1139a11601aac58bf2 --- lib/reference.c +++ lib/reference.c @@ -1205,6 +1205,12 @@ got_ref_write(struct got_reference *ref, struct got_re err = got_opentemp_named(&tmppath, &f, path, ""); if (err) { char *parent; + if (err->code == GOT_ERR_ERRNO && errno == ENOTDIR) { + err = got_error_fmt(GOT_ERR_BAD_REF_NAME, + "collision with an existing reference: %s", + got_ref_get_name(ref)); + goto done; + } if (!(err->code == GOT_ERR_ERRNO && errno == ENOENT)) goto done; err = got_path_dirname(&parent, path); blob - 12ee9f0325d237ae1d8a5a962b5aa23fb7261605 blob + 64e5549700453bd0afc70a70e8b3e31c3cde21db --- regress/cmdline/ref.sh +++ regress/cmdline/ref.sh @@ -170,12 +170,45 @@ test_ref_create() { test_done "$testroot" "$ret" return 1 fi + + # Create a ref with a / in its name + got ref -r $testroot/repo -c $commit_id refs/heads/commit/ref + ret=$? + if [ $ret -ne 0 ]; then + echo "got ref command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + # Create a ref with a name that collides with a file + got ref -r $testroot/repo -c $commit_id refs/heads/commitref/new \ + 2> $testroot/stderr + ret=$? + if [ $ret -eq 0 ]; then + echo "got ref command succeeded unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + echo -n "got: collision with an existing reference: " \ + > $testroot/stderr.expected + echo "refs/heads/commitref/new: bad reference name" \ + >> $testroot/stderr.expected + cmp -s $testroot/stderr $testroot/stderr.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + got ref -r $testroot/repo -l > $testroot/stdout echo "HEAD: refs/heads/newref" > $testroot/stdout.expected echo -n "refs/got/worktree/base-" >> $testroot/stdout.expected cat $testroot/wt/.got/uuid | tr -d '\n' >> $testroot/stdout.expected echo ": $commit_id" >> $testroot/stdout.expected echo "refs/heads/anotherref: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/commit/ref: $commit_id" >> $testroot/stdout.expected echo "refs/heads/commitref: $commit_id" >> $testroot/stdout.expected echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected echo "refs/heads/newref: $commit_id" >> $testroot/stdout.expected