晉、楚兩國的戰爭不可避免了。子玉派大夫鬥勃到晉營挑戰說:“我們請求同您的戰士作戲,您可以靠在車前扶手的橫木上觀看,得臣(子玉的名)也將奉陪參觀。”晉文公也不示弱,他叫欒枝答複說:“貴國請戰的事,我國的國君已經知道了。楚君的恩惠不敢忘記,所以我們才退到這兒。既然得不到貴國的諒解,隻好煩你轉告你們的主將,準備好戰車,謹慎地執行你們國君交付的任務。明天清早,我們在戰場上見麵吧。”
晉軍有戰車七百輛,士兵五萬二千五百人,裝備都已經齊全。戰鬥開始以前,晉文公登上古代有莘氏的廢墟,檢閱全軍。他說:“上下一致,紀律嚴明,可以同楚軍一戰了。”接著,他吩咐戰士們砍伐樹木,作為補充武器。第二天,也就是四月初四日,晉軍在城濮擺開陣勢,等候對敵。
楚國的軍隊,分為左、中、右三軍。左軍由子西率領。右軍是陳、蔡的軍隊組成的,由子上率領。中軍是主力,子玉親自指揮。子玉過低地估計了晉國的力量,過高估計了自己的力量。在決戰以前,他還誇口說:“今天晉國一定要完蛋了!”
會戰開始,晉文公命令下軍副將胥臣率領一支部隊,首先向楚的右軍進攻。胥臣把駕車的戰馬都蒙上虎皮,向前衝去。陳、蔡聯軍的戰馬驚懼起來,伏倒在地。士兵也驚惶失措,紛紛棄陣逃跑。楚國的右軍崩潰了。接著,晉上軍主將狐毛假充中軍,豎起兩麵大軍旗(當時主帥統率的中軍才有兩麵大旗),裝作要退兵的樣子。同時,下軍主將欒枝也叫人用戰車拉著樹枝,揚起塵土,假裝敗逃。楚軍看到這種情景,誤認為晉國的主帥敗退了,就驅馬追擊。晉將見楚軍中計,先軫、邯溱就指揮中軍(就是晉文公統率的親兵),攔腰衝殺過去。狐毛、狐偃也指揮上軍,夾攻子西。楚國的左軍也崩潰了。隻有子玉及時收兵,才沒有全軍覆滅。
就這樣,城濮之戰以楚國的失敗和晉國的勝利而結束了。
在這次戰役裏,晉軍俘獲了楚國的戰車一百乘,步兵一千人。戰鬥結束以後,晉軍在城濮休整了三天,吃的是楚軍積聚的糧食。四月初八日,晉軍高唱凱歌,班師回國。
楚成王本來就不大同意子玉同晉國作戰,這回聽說楚軍戰敗,更是生氣。他派使者對子玉說:“申、息兩地的子弟跟從你出征,現在都戰死了。你活著回來還有什麼麵目見他們的父老?”意思是要子玉自殺。使者沒有到達以前,子玉也曾經想自殺,結果被子西和子玉的兒子大心勸止。所以子西和大心聽了使者的那番話以後,便急忙替子玉辯解說:“子玉本來也想自殺,是我們阻止了他,要他回國接受國法的製裁。”使者把子西和大心的話轉告楚成王。楚成王感到說得有理,於是又差遣使者向子玉傳達免死的命令。但是,在使者還沒有趕到以前,子玉已經在連穀(楚地名)自殺了。
子玉雖然驕傲自大,缺少計謀,但仍舊不失為楚國的一員猛將。因此,晉文公聽到子玉自殺的消息,高興地說:“以後就投有人同我作對了。”
晉國在城濮大戰中的勝利,大大提高了它的聲威。從前同楚國關係密切的一些諸侯國,許多都來向晉國討好。城濮戰役前三月,鄭國國君還到楚國拉關係,現在聽說楚國打敗了,非常恐懼,趕緊去同晉國訂立盟約。其他一些諸侯國,也陸續來歸附晉國。這樣,就改變了戰前晉、楚兩國力量的對比,實際上確定了晉國的霸主地位。