Merge branch 'kh/branch-ref-syntax-advice'

When git refuses to create a branch because the proposed branch
name is not a valid refname, an advice message is given to refer
the user to exact naming rules.

* kh/branch-ref-syntax-advice:
  branch: advise about ref syntax rules
  advice: use double quotes for regular quoting
  advice: use backticks for verbatim
  advice: make all entries stylistically consistent
  t3200: improve test style
maint
Junio C Hamano 2024-03-15 16:05:59 -07:00
commit b09a8839a4
6 changed files with 128 additions and 108 deletions

View File

@ -2,27 +2,27 @@ advice.*::
These variables control various optional help messages designed to These variables control various optional help messages designed to
aid new users. When left unconfigured, Git will give the message aid new users. When left unconfigured, Git will give the message
alongside instructions on how to squelch it. You can tell Git alongside instructions on how to squelch it. You can tell Git
that you do not need the help message by setting these to 'false': that you do not need the help message by setting these to `false`:
+ +
-- --
addEmbeddedRepo:: addEmbeddedRepo::
Advice on what to do when you've accidentally added one Shown when the user accidentally adds one
git repo inside of another. git repo inside of another.
addEmptyPathspec:: addEmptyPathspec::
Advice shown if a user runs the add command without providing Shown when the user runs `git add` without providing
the pathspec parameter. the pathspec parameter.
addIgnoredFile:: addIgnoredFile::
Advice shown if a user attempts to add an ignored file to Shown when the user attempts to add an ignored file to
the index. the index.
amWorkDir:: amWorkDir::
Advice that shows the location of the patch file when Shown when linkgit:git-am[1] fails to apply a patch
linkgit:git-am[1] fails to apply it. file, to tell the user the location of the file.
ambiguousFetchRefspec:: ambiguousFetchRefspec::
Advice shown when a fetch refspec for multiple remotes maps to Shown when a fetch refspec for multiple remotes maps to
the same remote-tracking branch namespace and causes branch the same remote-tracking branch namespace and causes branch
tracking set-up to fail. tracking set-up to fail.
checkoutAmbiguousRemoteBranchName:: checkoutAmbiguousRemoteBranchName::
Advice shown when the argument to Shown when the argument to
linkgit:git-checkout[1] and linkgit:git-switch[1] linkgit:git-checkout[1] and linkgit:git-switch[1]
ambiguously resolves to a ambiguously resolves to a
remote tracking branch on more than one remote in remote tracking branch on more than one remote in
@ -33,31 +33,31 @@ advice.*::
to be used by default in some situations where this to be used by default in some situations where this
advice would be printed. advice would be printed.
commitBeforeMerge:: commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to Shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes. merge to avoid overwriting local changes.
detachedHead:: detachedHead::
Advice shown when you used Shown when the user uses
linkgit:git-switch[1] or linkgit:git-checkout[1] linkgit:git-switch[1] or linkgit:git-checkout[1]
to move to the detached HEAD state, to instruct how to to move to the detached HEAD state, to tell the user how
create a local branch after the fact. to create a local branch after the fact.
diverging:: diverging::
Advice shown when a fast-forward is not possible. Shown when a fast-forward is not possible.
fetchShowForcedUpdates:: fetchShowForcedUpdates::
Advice shown when linkgit:git-fetch[1] takes a long time Shown when linkgit:git-fetch[1] takes a long time
to calculate forced updates after ref updates, or to warn to calculate forced updates after ref updates, or to warn
that the check is disabled. that the check is disabled.
forceDeleteBranch:: forceDeleteBranch::
Advice shown when a user tries to delete a not fully merged Shown when the user tries to delete a not fully merged
branch without the force option set. branch without the force option set.
ignoredHook:: ignoredHook::
Advice shown if a hook is ignored because the hook is not Shown when a hook is ignored because the hook is not
set as executable. set as executable.
implicitIdentity:: implicitIdentity::
Advice on how to set your identity configuration when Shown when the user's information is guessed from the
your information is guessed from the system username and system username and domain name, to tell the user how to
domain name. set their identity configuration.
nestedTag:: nestedTag::
Advice shown if a user attempts to recursively tag a tag object. Shown when a user attempts to recursively tag a tag object.
pushAlreadyExists:: pushAlreadyExists::
Shown when linkgit:git-push[1] rejects an update that Shown when linkgit:git-push[1] rejects an update that
does not qualify for fast-forwarding (e.g., a tag.) does not qualify for fast-forwarding (e.g., a tag.)
@ -71,12 +71,12 @@ advice.*::
object that is not a commit-ish, or make the remote object that is not a commit-ish, or make the remote
ref point at an object that is not a commit-ish. ref point at an object that is not a commit-ish.
pushNonFFCurrent:: pushNonFFCurrent::
Advice shown when linkgit:git-push[1] fails due to a Shown when linkgit:git-push[1] fails due to a
non-fast-forward update to the current branch. non-fast-forward update to the current branch.
pushNonFFMatching:: pushNonFFMatching::
Advice shown when you ran linkgit:git-push[1] and pushed Shown when the user ran linkgit:git-push[1] and pushed
'matching refs' explicitly (i.e. you used ':', or "matching refs" explicitly (i.e. used `:`, or
specified a refspec that isn't your current branch) and specified a refspec that isn't the current branch) and
it resulted in a non-fast-forward error. it resulted in a non-fast-forward error.
pushRefNeedsUpdate:: pushRefNeedsUpdate::
Shown when linkgit:git-push[1] rejects a forced update of Shown when linkgit:git-push[1] rejects a forced update of
@ -87,25 +87,28 @@ advice.*::
guess based on the source and destination refs what guess based on the source and destination refs what
remote ref namespace the source belongs in, but where remote ref namespace the source belongs in, but where
we can still suggest that the user push to either we can still suggest that the user push to either
refs/heads/* or refs/tags/* based on the type of the `refs/heads/*` or `refs/tags/*` based on the type of the
source object. source object.
pushUpdateRejected:: pushUpdateRejected::
Set this variable to 'false' if you want to disable Set this variable to `false` if you want to disable
'pushNonFFCurrent', 'pushNonFFMatching', 'pushAlreadyExists', `pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`,
'pushFetchFirst', 'pushNeedsForce', and 'pushRefNeedsUpdate' `pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate`
simultaneously. simultaneously.
refSyntax::
Shown when the user provides an illegal ref name, to
tell the user about the ref syntax documentation.
resetNoRefresh:: resetNoRefresh::
Advice to consider using the `--no-refresh` option to Shown when linkgit:git-reset[1] takes more than 2
linkgit:git-reset[1] when the command takes more than 2 seconds seconds to refresh the index after reset, to tell the user
to refresh the index after reset. that they can use the `--no-refresh` option.
resolveConflict:: resolveConflict::
Advice shown by various commands when conflicts Shown by various commands when conflicts
prevent the operation from being performed. prevent the operation from being performed.
rmHints:: rmHints::
In case of failure in the output of linkgit:git-rm[1], Shown on failure in the output of linkgit:git-rm[1], to
show directions on how to proceed from the current state. give directions on how to proceed from the current state.
sequencerInUse:: sequencerInUse::
Advice shown when a sequencer command is already in progress. Shown when a sequencer command is already in progress.
skippedCherryPicks:: skippedCherryPicks::
Shown when linkgit:git-rebase[1] skips a commit that has already Shown when linkgit:git-rebase[1] skips a commit that has already
been cherry-picked onto the upstream branch. been cherry-picked onto the upstream branch.
@ -123,30 +126,30 @@ advice.*::
by linkgit:git-switch[1] or by linkgit:git-switch[1] or
linkgit:git-checkout[1] when switching branches. linkgit:git-checkout[1] when switching branches.
statusUoption:: statusUoption::
Advise to consider using the `-u` option to linkgit:git-status[1] Shown when linkgit:git-status[1] takes more than 2
when the command takes more than 2 seconds to enumerate untracked seconds to enumerate untracked files, to tell the user that
files. they can use the `-u` option.
submoduleAlternateErrorStrategyDie:: submoduleAlternateErrorStrategyDie::
Advice shown when a submodule.alternateErrorStrategy option Shown when a submodule.alternateErrorStrategy option
configured to "die" causes a fatal error. configured to "die" causes a fatal error.
submoduleMergeConflict:: submoduleMergeConflict::
Advice shown when a non-trivial submodule merge conflict is Advice shown when a non-trivial submodule merge conflict is
encountered. encountered.
submodulesNotUpdated:: submodulesNotUpdated::
Advice shown when a user runs a submodule command that fails Shown when a user runs a submodule command that fails
because `git submodule update --init` was not run. because `git submodule update --init` was not run.
suggestDetachingHead:: suggestDetachingHead::
Advice shown when linkgit:git-switch[1] refuses to detach HEAD Shown when linkgit:git-switch[1] refuses to detach HEAD
without the explicit `--detach` option. without the explicit `--detach` option.
updateSparsePath:: updateSparsePath::
Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1] Shown when either linkgit:git-add[1] or linkgit:git-rm[1]
is asked to update index entries outside the current sparse is asked to update index entries outside the current sparse
checkout. checkout.
waitingForEditor:: waitingForEditor::
Print a message to the terminal whenever Git is waiting for Shown when Git is waiting for editor input. Relevant
editor input from the user. when e.g. the editor is not launched inside the terminal.
worktreeAddOrphan:: worktreeAddOrphan::
Advice shown when a user tries to create a worktree from an Shown when the user tries to create a worktree from an
invalid reference, to instruct how to create a new unborn invalid reference, to tell the user how to create a new unborn
branch instead. branch instead.
-- --

View File

@ -68,6 +68,7 @@ static struct {
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" }, [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" }, [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */ [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
[ADVICE_REF_SYNTAX] = { "refSyntax" },
[ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" }, [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" }, [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
[ADVICE_RM_HINTS] = { "rmHints" }, [ADVICE_RM_HINTS] = { "rmHints" },

View File

@ -36,6 +36,7 @@ enum advice_type {
ADVICE_PUSH_UNQUALIFIED_REF_NAME, ADVICE_PUSH_UNQUALIFIED_REF_NAME,
ADVICE_PUSH_UPDATE_REJECTED, ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_PUSH_UPDATE_REJECTED_ALIAS, ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_REF_SYNTAX,
ADVICE_RESET_NO_REFRESH_WARNING, ADVICE_RESET_NO_REFRESH_WARNING,
ADVICE_RESOLVE_CONFLICT, ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS, ADVICE_RM_HINTS,

View File

@ -370,8 +370,12 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
*/ */
int validate_branchname(const char *name, struct strbuf *ref) int validate_branchname(const char *name, struct strbuf *ref)
{ {
if (strbuf_check_branch_ref(ref, name)) if (strbuf_check_branch_ref(ref, name)) {
die(_("'%s' is not a valid branch name"), name); int code = die_message(_("'%s' is not a valid branch name"), name);
advise_if_enabled(ADVICE_REF_SYNTAX,
_("See `man git check-ref-format`"));
exit(code);
}


return ref_exists(ref->buf); return ref_exists(ref->buf);
} }

View File

@ -582,8 +582,12 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
*/ */
if (ref_exists(oldref.buf)) if (ref_exists(oldref.buf))
recovery = 1; recovery = 1;
else else {
die(_("invalid branch name: '%s'"), oldname); int code = die_message(_("invalid branch name: '%s'"), oldname);
advise_if_enabled(ADVICE_REF_SYNTAX,
_("See `man git check-ref-format`"));
exit(code);
}
} }


for (int i = 0; worktrees[i]; i++) { for (int i = 0; worktrees[i]; i++) {

View File

@ -75,13 +75,13 @@ test_expect_success 'git branch HEAD should fail' '
test_must_fail git branch HEAD test_must_fail git branch HEAD
' '


cat >expect <<EOF
$HEAD refs/heads/d/e/f@{0}: branch: Created from main
EOF
test_expect_success 'git branch --create-reflog d/e/f should create a branch and a log' ' test_expect_success 'git branch --create-reflog d/e/f should create a branch and a log' '
GIT_COMMITTER_DATE="2005-05-26 23:30" \ GIT_COMMITTER_DATE="2005-05-26 23:30" \
git -c core.logallrefupdates=false branch --create-reflog d/e/f && git -c core.logallrefupdates=false branch --create-reflog d/e/f &&
test_ref_exists refs/heads/d/e/f && test_ref_exists refs/heads/d/e/f &&
cat >expect <<-EOF &&
$HEAD refs/heads/d/e/f@{0}: branch: Created from main
EOF
git reflog show --no-abbrev-commit refs/heads/d/e/f >actual && git reflog show --no-abbrev-commit refs/heads/d/e/f >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -440,7 +440,7 @@ test_expect_success 'git branch --list -v with --abbrev' '


test_expect_success 'git branch --column' ' test_expect_success 'git branch --column' '
COLUMNS=81 git branch --column=column >actual && COLUMNS=81 git branch --column=column >actual &&
cat >expect <<\EOF && cat >expect <<-\EOF &&
a/b/c bam foo l * main n o/p r a/b/c bam foo l * main n o/p r
abc bar j/k m/m mb o/o q topic abc bar j/k m/m mb o/o q topic
EOF EOF
@ -453,7 +453,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
test_when_finished "git branch -d $long" && test_when_finished "git branch -d $long" &&
git branch $long && git branch $long &&
COLUMNS=80 git branch --column=column >actual && COLUMNS=80 git branch --column=column >actual &&
cat >expect <<EOF && cat >expect <<-EOF &&
a/b/c a/b/c
abc abc
bam bam
@ -481,7 +481,7 @@ test_expect_success 'git branch with column.*' '
COLUMNS=80 git branch >actual && COLUMNS=80 git branch >actual &&
git config --unset column.branch && git config --unset column.branch &&
git config --unset column.ui && git config --unset column.ui &&
cat >expect <<\EOF && cat >expect <<-\EOF &&
a/b/c bam foo l * main n o/p r a/b/c bam foo l * main n o/p r
abc bar j/k m/m mb o/o q topic abc bar j/k m/m mb o/o q topic
EOF EOF
@ -496,7 +496,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
git config column.ui column && git config column.ui column &&
COLUMNS=80 git branch -v | cut -c -8 | sed "s/ *$//" >actual && COLUMNS=80 git branch -v | cut -c -8 | sed "s/ *$//" >actual &&
git config --unset column.ui && git config --unset column.ui &&
cat >expect <<\EOF && cat >expect <<-\EOF &&
a/b/c a/b/c
abc abc
bam bam
@ -517,18 +517,15 @@ EOF
test_cmp expect actual test_cmp expect actual
' '


mv .git/config .git/config-saved

test_expect_success DEFAULT_REPO_FORMAT 'git branch -m q q2 without config should succeed' ' test_expect_success DEFAULT_REPO_FORMAT 'git branch -m q q2 without config should succeed' '
test_when_finished mv .git/config-saved .git/config &&
mv .git/config .git/config-saved &&
git branch -m q q2 && git branch -m q q2 &&
git branch -m q2 q git branch -m q2 q
' '


mv .git/config-saved .git/config

git config branch.s/s.dummy Hello

test_expect_success 'git branch -m s/s s should work when s/t is deleted' ' test_expect_success 'git branch -m s/s s should work when s/t is deleted' '
git config branch.s/s.dummy Hello &&
git branch --create-reflog s/s && git branch --create-reflog s/s &&
git reflog exists refs/heads/s/s && git reflog exists refs/heads/s/s &&
git branch --create-reflog s/t && git branch --create-reflog s/t &&
@ -1112,14 +1109,14 @@ test_expect_success '--set-upstream-to notices an error to set branch as own ups
test_cmp expect actual test_cmp expect actual
" "


# Keep this test last, as it changes the current branch
cat >expect <<EOF
$HEAD refs/heads/g/h/i@{0}: branch: Created from main
EOF
test_expect_success 'git checkout -b g/h/i -l should create a branch and a log' ' test_expect_success 'git checkout -b g/h/i -l should create a branch and a log' '
test_when_finished git checkout main &&
GIT_COMMITTER_DATE="2005-05-26 23:30" \ GIT_COMMITTER_DATE="2005-05-26 23:30" \
git checkout -b g/h/i -l main && git checkout -b g/h/i -l main &&
test_ref_exists refs/heads/g/h/i && test_ref_exists refs/heads/g/h/i &&
cat >expect <<-EOF &&
$HEAD refs/heads/g/h/i@{0}: branch: Created from main
EOF
git reflog show --no-abbrev-commit refs/heads/g/h/i >actual && git reflog show --no-abbrev-commit refs/heads/g/h/i >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -1696,4 +1693,14 @@ test_expect_success '--track overrides branch.autoSetupMerge' '
test_cmp_config "" --default "" branch.foo5.merge test_cmp_config "" --default "" branch.foo5.merge
' '


test_expect_success 'errors if given a bad branch name' '
cat <<-\EOF >expect &&
fatal: '\''foo..bar'\'' is not a valid branch name
hint: See `man git check-ref-format`
hint: Disable this message with "git config advice.refSyntax false"
EOF
test_must_fail git branch foo..bar >actual 2>&1 &&
test_cmp expect actual
'

test_done test_done