From 8b107dc5e1cd0745628e2bfb473477342c719f25 Mon Sep 17 00:00:00 2001 From: William Bain Date: Wed, 3 May 2017 11:20:57 -0600 Subject: [PATCH] revparse: support open-ended ranges Support '..' and '...' ranges where one side is not specified. The unspecified side defaults to HEAD. Closes #4223 --- src/revparse.c | 25 ++++++++++++++++++++++--- tests/refs/revparse.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index d5511b47b..fd6bd1ea6 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -892,6 +892,17 @@ int git_revparse( const char *rstr; revspec->flags = GIT_REVPARSE_RANGE; + /* + * Following git.git, don't allow '..' because it makes command line + * arguments which can be either paths or revisions ambiguous when the + * path is almost certainly intended. The empty range '...' is still + * allowed. + */ + if (!git__strcmp(spec, "..")) { + giterr_set(GITERR_INVALID, "Invalid pattern '..'"); + return GIT_EINVALIDSPEC; + } + lstr = git__substrdup(spec, dotdot - spec); rstr = dotdot + 2; if (dotdot[2] == '.') { @@ -899,9 +910,17 @@ int git_revparse( rstr++; } - error = git_revparse_single(&revspec->from, repo, lstr); - if (!error) - error = git_revparse_single(&revspec->to, repo, rstr); + error = git_revparse_single( + &revspec->from, + repo, + *lstr == '\0' ? "HEAD" : lstr); + + if (!error) { + error = git_revparse_single( + &revspec->to, + repo, + *rstr == '\0' ? "HEAD" : rstr); + } git__free((void*)lstr); } else { diff --git a/tests/refs/revparse.c b/tests/refs/revparse.c index c22c30440..459188cf7 100644 --- a/tests/refs/revparse.c +++ b/tests/refs/revparse.c @@ -122,6 +122,14 @@ static void test_id( test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); } +static void test_invalid_revspec(const char* invalid_spec) +{ + git_revspec revspec; + + cl_assert_equal_i( + GIT_EINVALIDSPEC, git_revparse(&revspec, g_repo, invalid_spec)); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -749,6 +757,33 @@ void test_refs_revparse__parses_range_operator(void) "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("HEAD~3..", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE); + + test_id("HEAD~3...", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("..HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE); + + test_id("...HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("...", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_invalid_revspec(".."); } void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void)