There are several methods that I can think of.
1. Just the base glossaries
package.
\documentclass{article}
\usepackage[colorlinks]{hyperref}
\usepackage[style=tree]{glossaries}
\makeglossaries
\setacronymstyle{long-short}
\newacronym{a}{A}{Apples}
\newacronym[parent=a]{a1}{A1}{Apples 1}
\newacronym[parent=a]{a2}{A2}{Apples 2}
\begin{document}
First use: \gls{a1}, \gls{a2}, \gls{a}.
Next use: \gls{a1}, \gls{a2}, \gls{a}.
\printglossaries
\end{document}
This establishes a hierarchical set of abbreviations:

The \gls{a}
reference links to the parent entry in the list.
\documentclass{article}
\usepackage[colorlinks]{hyperref}
\usepackage[style=tree]{glossaries-extra}
\makeglossaries
\setabbreviationstyle[acronym]{long-short}
\newacronym{a1}{A1}{Apples 1}
\newacronym{a2}{A2}{Apples 2}
\newglossaryentry{a}{name={A},description={Apples},alias={a1}}
\begin{document}
First use: \gls{a1}, \gls{a2}, \gls{a}.
Next use: \gls{a1}, \gls{a2}, \gls{a}.
\printglossaries
\end{document}
This uses the alias
key that makes the hyperlink for \gls{a}
go to the target for a1
. The aliased entry is listed in the glossary with a cross-reference:

The first use of \gls{a}
doesn't show the full form as it's not an abbreviation. It can be an abbreviation if you prefer:
\newacronym[alias=a1]{a}{A}{Apples}
If you don't want the aliased term to appear at all in the list, you can create an ignored glossary and assign it to that:
\documentclass{article}
\usepackage[colorlinks]{hyperref}
\usepackage[style=tree]{glossaries-extra}
\makeglossaries
\setabbreviationstyle[acronym]{long-short}
\newacronym{a1}{A1}{Apples 1}
\newacronym{a2}{A2}{Apples 2}
\newignoredglossary*{ignored}
\newglossaryentry{a}{name={A},description={Apples},alias={a1},type=ignored}
\begin{document}
First use: \gls{a1}, \gls{a2}, \gls{a}.
Next use: \gls{a1}, \gls{a2}, \gls{a}.
\printglossaries
\end{document}
The \gls{a}
reference links to the main glossary even though a
is in an ignored glossary that doesn't show up with \printglossaries
.

This assigns a post-link hook for the aliased entry (which now has the category label aliased
) so that on first use it will show both terms.
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.bib}
@acronym{a1,
short={A1},
long={Apples 1}
}
@acronym{a2,
short={A2},
long={Apples 2}
}
@index{a,
name={A},
alias={a1},
seealso={a1,a2},
category={aliased}
}
\end{filecontents*}
\usepackage[colorlinks]{hyperref}
\usepackage[style=tree,record]{glossaries-extra}
\setabbreviationstyle[acronym]{long-short}
\GlsXtrLoadResources[
src={\jobname}% entries in \jobname.bib
]
\glsdefpostlink{aliased}{%
\glsxtrifwasfirstuse
{%
\glsxtrifhasfield{seealso}{\glslabel}%
{%
\let\DTLlistformatitem\glsxtrlong
\space(\DTLformatlist{\glscurrentfieldvalue})%
}%
{}%
}%
{}%
}
\begin{document}
First use: \gls{a1}, \gls{a2}, \gls{a}.
Next use: \gls{a1}, \gls{a2}, \gls{a}.
\renewcommand{\printunsrtglossaryentryprocesshook}[1]{%
\glsxtrifhasfield*{alias}{#1}{\printunsrtglossaryskipentry}{}%
}
\printunsrtglossaries
\end{document}
Instead of creating an ignored glossary, I've redefined the hook used by \printunsrtglossary
to skip any entry that has the alias
field set.

The command \glsdefpostlink
was new to glossaries-extra
v1.31. If you have an older version you can change:
\glsdefpostlink{aliased}{%
to:
\newcommand{\glsxtrpostlinkaliased}{%
Here's a minor variation that includes a description for the aliased entry:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.bib}
@acronym{a1,
short={A1},
long={Apples 1}
}
@acronym{a2,
short={A2},
long={Apples 2}
}
@entry{a,
name={A},
description={Apples},
alias={a1},
seealso={a1,a2},
category={aliased}
}
\end{filecontents*}
\usepackage[colorlinks]{hyperref}
\usepackage[style=tree,record]{glossaries-extra}
\setabbreviationstyle[acronym]{long-short}
\GlsXtrLoadResources[
src={\jobname}% entries in \jobname.bib
]
\glsdefpostlink{aliased}{%
\glsxtrifwasfirstuse
{%
\space(\glsentrydesc{\glslabel}%
\glsxtrifhasfield{seealso}{\glslabel}%
{%
\let\DTLlistformatitem\glsxtrlong
:\space\DTLformatlist{\glscurrentfieldvalue}%
}%
{}%
)%
}%
{}%
}
\begin{document}
First use: \gls{a1}, \gls{a2}, \gls{a}.
Next use: \gls{a1}, \gls{a2}, \gls{a}.
\renewcommand{\printunsrtglossaryentryprocesshook}[1]{%
\glsxtrifhasfield*{alias}{#1}{\printunsrtglossaryskipentry}{}%
}
\printunsrtglossaries
\end{document}
