commit d1c1ae5fa698c48d70eb16cef11bb3710221ea88 from: Stefan Sperling date: Mon Aug 12 22:33:25 2019 UTC introduce 'got ref -s' and add two tests for 'got ref' commit - 29e86f7a5a094e0e5e9ca231e615a13c0c2e6ed0 commit + d1c1ae5fa698c48d70eb16cef11bb3710221ea88 blob - a7c6931c739bce2b4746264ec0f8a7e4ef97a80d blob + 0a9ce6f2c219a2b2a5308d9efdeb9170171b5d96 --- TODO +++ TODO @@ -15,7 +15,6 @@ got: - 'histedit -c' prompts for log message even if there are no changes to commit - recursive addition: got add -R - recursive removal: got rm -R -- allow for creating symbolic references with 'got ref -s' tog: - cosmetic display issues involving \n and TABs should be fixed blob - 00c7548af39086e290bea57234ee1243e5e1e2bd blob + a826de9bf1ee14823162c06c47bc24c7a3767ec1 --- got/got.1 +++ got/got.1 @@ -459,6 +459,12 @@ work tree, use the repository path associated with thi List all existing references in the repository. .It Fl d Ar name Delete the reference with the specified name from the repository. +.It Fl s +Create a symbolic reference pointing at the specified +.Ar target , +which must be an existing reference. +Care should be taken not to create loops between references when +this option is used. .El .It Cm branch Oo Fl r Ar repository-path Oc Oo Fl l Oc Oo Fl d Ar name Oc Op Ar name Op Ar base-branch Manage branches in a repository. blob - 9a69229f803e9ee42a8f6cb234d669f3282effe6 blob + a322f32e174306295c8b5682c8a19d3280485378 --- got/got.c +++ got/got.c @@ -2561,7 +2561,7 @@ __dead static void usage_ref(void) { fprintf(stderr, - "usage: %s ref [-r repository] -l | -d name | name target\n", + "usage: %s ref [-r repository] -l | -d name | [-s] name target\n", getprogname()); exit(1); } @@ -2646,6 +2646,38 @@ done: if (ref) got_ref_close(ref); free(id); + return err; +} + +static const struct got_error * +add_symref(struct got_repository *repo, const char *refname, const char *target) +{ + const struct got_error *err = NULL; + struct got_reference *ref = NULL; + struct got_reference *target_ref = NULL; + + /* + * Don't let the user create a reference named '-'. + * While technically a valid reference name, this case is usually + * an unintended typo. + */ + if (refname[0] == '-' && refname[1] == '\0') + return got_error(GOT_ERR_BAD_REF_NAME); + + err = got_ref_open(&target_ref, repo, target, 0); + if (err) + return err; + + err = got_ref_alloc_symref(&ref, refname, target_ref); + if (err) + goto done; + + err = got_ref_write(ref, repo); +done: + if (target_ref) + got_ref_close(target_ref); + if (ref) + got_ref_close(ref); return err; } @@ -2656,11 +2688,11 @@ cmd_ref(int argc, char *argv[]) struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; - int ch, do_list = 0; + int ch, do_list = 0, create_symref = 0; const char *delref = NULL; /* TODO: Add -s option for adding symbolic references. */ - while ((ch = getopt(argc, argv, "d:r:l")) != -1) { + while ((ch = getopt(argc, argv, "d:r:ls")) != -1) { switch (ch) { case 'd': delref = optarg; @@ -2673,6 +2705,9 @@ cmd_ref(int argc, char *argv[]) break; case 'l': do_list = 1; + break; + case 's': + create_symref = 1; break; default: usage_ref(); @@ -2687,6 +2722,9 @@ cmd_ref(int argc, char *argv[]) argv += optind; if (do_list || delref) { + if (create_symref) + errx(1, "-s option cannot be used together with the " + "-l or -d options"); if (argc > 0) usage_ref(); } else if (argc != 2) @@ -2744,6 +2782,8 @@ cmd_ref(int argc, char *argv[]) error = list_refs(repo); else if (delref) error = delete_ref(repo, delref); + else if (create_symref) + error = add_symref(repo, argv[0], argv[1]); else error = add_ref(repo, argv[0], argv[1]); done: blob - e86ea7f544fae06c498afb4bfbe43ed12e0e2818 blob + c7f57651b4255a40c5e239acede9d76dae99f6dc --- regress/cmdline/Makefile +++ regress/cmdline/Makefile @@ -1,4 +1,4 @@ -REGRESS_TARGETS=checkout update status log add rm diff blame branch commit \ +REGRESS_TARGETS=checkout update status log add rm diff blame branch ref commit \ revert cherrypick backout rebase import histedit stage unstage NOOBJ=Yes @@ -29,6 +29,9 @@ blame: branch: ./branch.sh +ref: + ./ref.sh + commit: ./commit.sh blob - /dev/null blob + 3774051198b40f4ceaef773bcd650eaba78d8ead (mode 755) --- /dev/null +++ regress/cmdline/ref.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (c) 2019 Stefan Sperling +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +. ./common.sh + +function test_ref_create { + local testroot=`test_init ref_create` + local commit_id=`git_show_head $testroot/repo` + + # Create a head ref based on repository's HEAD reference + got ref -r $testroot/repo refs/heads/newref HEAD + ret="$?" + if [ "$ret" != "0" ]; then + echo "got ref command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + # Ensure that Git recognizes the ref Got has created + (cd $testroot/repo && git checkout -q newref) + ret="$?" + if [ "$ret" != "0" ]; then + echo "git checkout command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + # Ensure Git recognizes the new ref + got checkout -b newref $testroot/repo $testroot/wt >/dev/null + ret="$?" + if [ "$ret" != "0" ]; then + echo "got checkout command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + # Create a head ref based on another specific ref + (cd $testroot/wt && got ref refs/heads/anotherref refs/heads/master) + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/repo && git checkout -q anotherref) + ret="$?" + if [ "$ret" != "0" ]; then + echo "git checkout command failed unexpectedly" + test_done "$testroot" "$ret" + fi + + # Create a symbolic ref + (cd $testroot/wt && got ref -s refs/heads/symbolicref refs/heads/master) + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/repo && git checkout -q symbolicref) + ret="$?" + if [ "$ret" != "0" ]; then + echo "git checkout command failed unexpectedly" + test_done "$testroot" "$ret" + fi + + got ref -r $testroot/repo -l > $testroot/stdout + echo "HEAD: refs/heads/symbolicref" > $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/master: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/newref: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/symbolicref: refs/heads/master" \ + >> $testroot/stdout.expected + cmp -s $testroot/stdout $testroot/stdout.expected + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + +function test_ref_delete { + local testroot=`test_init ref_delete` + local commit_id=`git_show_head $testroot/repo` + + for b in ref1 ref2 ref3; do + got ref -r $testroot/repo refs/heads/$b refs/heads/master + ret="$?" + if [ "$ret" != "0" ]; then + echo "got ref command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + done + + got ref -d refs/heads/ref2 -r $testroot/repo > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + echo "got ref command failed unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + got ref -l -r $testroot/repo > $testroot/stdout + echo "HEAD: refs/heads/master" > $testroot/stdout.expected + echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/ref1: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/ref3: $commit_id" >> $testroot/stdout.expected + cmp -s $testroot/stdout $testroot/stdout.expected + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + got ref -d refs/heads/bogus_ref_name -r $testroot/repo \ + > $testroot/stdout 2> $testroot/stderr + ret="$?" + if [ "$ret" == "0" ]; then + echo "got ref succeeded unexpectedly" + test_done "$testroot" "$ret" + return 1 + fi + + echo "got: reference refs/heads/bogus_ref_name not found" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr $testroot/stderr.expected + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + fi + test_done "$testroot" "$ret" +} + +run_test test_ref_create +run_test test_ref_delete