For plain deduplication they give the same rows, and most optimizers turn both into the same plan. SELECT DISTINCT a, b FROM t and SELECT a, b FROM t GROUP BY a, b are equal in result and, in modern engines, in cost.
Where they differ
GROUP BY is the tool when you also compute something per group:
SELECT a, b, COUNT(*) AS n FROM t GROUP BY a, b;
DISTINCT cannot do that. DISTINCT only removes duplicate output rows. It also has a second use inside aggregates, COUNT(DISTINCT customer_id), which is a different thing: it removes duplicates of one expression before counting.
A small trap: SELECT DISTINCT a, b applies to the whole row of selected columns, not to a alone. SELECT DISTINCT(a), b looks like it distincts only a, but the brackets do nothing. It is still DISTINCT (a, b).
Which should you write
Pick whichever says the intent. "Give me the unique pairs" reads naturally as DISTINCT. "Summarise per pair" is GROUP BY. In older MySQL and Oracle versions there were cases where they used different algorithms (sort versus hash), but on current Postgres, Snowflake, BigQuery and Spark you will not see a meaningful difference.
The code smell
The thing to watch for is DISTINCT added to hide a problem. A query returns duplicates, someone adds DISTINCT, and the duplicates vanish. But the real cause was a join fanning out on a non-unique key (see the row-multiplication question). Now the query does extra sort or hash work on every run, and the cause is still there. If any correct result needs DISTINCT, ask why the rows were duplicated first. Fix the join, or deduplicate the table in a CTE before joining.