Puhl was born and raised in Melville, Saskatchewan. In high school, he played baseball, volleyball, track and football. Pitching on a Midget League team, he led the club to a Canadian championship and was named the nation's outstanding pitcher. He was signed by the Houston Astros in 1973. Astros scout Harry Morgan signed Puhl to play in the outfield, a role that the pitcher had never played before.
Puhl made his professional debut with the rookie-league Covington Astros the following season, batting .284. Over the next three seasons, he advanced through the Astros' farm system, playing with the single-A Dubuque Packers in 1975, then splitting the season between the double-A Columbus Astros and the triple-A Memphis Blues in 1976, and finally with the triple-A Charleston Charlies in 1977.
Puhl was called up to the majors in July 1977, and never returned to the minor leagues. He was quickly installed as the club's regular left fielder, replacing Jim Fuller. In his first major league game on July 12, Puhl entered as a defensive replacement for Fuller. The following day he got his first hit in the 13th inning of a game against the Los Angeles Dodgers off relief pitcher Elías Sosa. Later that inning, he scored the winning run on Bob Watson's double. He finished the 1977 season with a .301 batting average in 60 games.
The following year he was the sole Astro selected as a National League All-Star. In the 1980 championship series against the Philadelphia Phillies, Puhl set a then NL-championship series record with a .526 batting average in a losing cause, the best performance ever by a hitter in a play-off series (it has since been superseded). As of 2010, Puhl has the ninth-best lifetime fielding percentage by an outfielder (.993). In 1981, he was named Canadian Baseball player of the year.
A pulled hamstring in 1985 and an ankle injury in 1986 reduced his playing time, however he returned in 1987 as an effective pinch hitter and in 1988 he hit a career high .303.
Puhl was granted free agent status in 1990, and signed with the New York Mets on December 13, 1990. He was released by the Mets during spring training on April 1, 1991, and subsequently signed by the Kansas City Royals on April 25, 1991. His final MLB game was on May 29, 1991, then was released from the Royals on June 9, 1991, ending his MLB career. His career statistics included a .280 batting average, 62 home runs, 435 RBIs, and 217 stolen bases. He accumulated 1,361 hits in 1,531 games. He was particularly effective in postseason play, batting .372 in 13 games over three series.
After Puhl's retirement in 1991, he was inducted into the Saskatchewan Sports Hall of Fame in 1994 and to the Canadian Baseball Hall of Fame in 1995. In November 2006, Puhl was inducted into the Texas Baseball Hall of Fame.
In August 2006, Puhl coached the Canadian National Senior team at the Olympic qualifier in Cuba. Canada advanced to the next round of qualifiers in 2007. In a 15–12 defeat of Panama, Puhl replaced catcher David Corrente with pinch hitter Reed Eastley in the 8th inning, despite the fact that Corrente had four hits in four at bats. Eastley hit a 3-run home run to tie the game. In the bottom of the ninth Reed Eastley came to bat for a second time, this time with the bases loaded and the game on the line. Puhl instead called on pinch hitter Jeremy Ware, whose grand slam won the game for Canada.
In November 2006, Puhl was announced as the first head baseball coach at the University of Houston–Victoria. The UHV Jaguars were previously an independent team of the NAIA, but beginning in the 2015-16 season will compete as a member of the NAIA's Red River Athletic Conference.
His son, Stephen Puhl, was a minor league baseball player. Selected in the 17th round (514th overall) of the 2006 Major League Baseball draft by the New York Mets, Stephen was a catcher in the Mets system in 2006 and then pitched for the organization in 2007 and 2008.