楚军官兵见晋军后退,想就此罢手,不再追击。但是,子玉不同意。他认为晋军的后退是由于害怕楚军。因此,他命令楚军背靠着一个名叫的险要丘陵地带,扎下营寨,准备同晋军决战。
多少年来,楚国很少打过败仗,现在又占领了险要的丘陵地区,晋文公不禁担心起来。他听到一群晋军士兵唱起这样一首歌:“田里好庄稼,密密又层层。旧的且丢开,新的要经营。”晋文公又误认士兵唱的歌是讽刺他忘了楚国过去对他的恩惠,因此更加怀疑起来。狐偃看见这种情形,就给他打气说:“战吧!战胜了,我们可以得到各国诸侯的拥戴。即使失败了,我们晋国内有太行山,外有黄河,形势险要,可以固守,也不会有什么害处的。”其他一些将领,也同意狐偃的主张。晋文公见大家同心协力,斗志昂扬,战胜楚国的信心也就加强了。
晋、楚两国的战争不可避免了。子玉派大夫斗勃到晋营挑战说:“我们请求同您的战士作戏,您可以靠在车前扶手的横木上观看,得臣(子玉的名)也将奉陪参观。”晋文公也不示弱,他叫栾枝答复说:“贵国请战的事,我国的国君已经知道了。楚君的恩惠不敢忘记,所以我们才退到这儿。既然得不到贵国的谅解,只好烦你转告你们的主将,准备好战车,谨慎地执行你们国君交付的任务。明天清早,我们在战场上见面吧。”晋军有战车七百辆,士兵五万二千五百人,装备都已经齐全。战斗开始以前,晋文公登上古代有莘氏的废墟,检阅全军。他说:“上下一致,纪律严明,可以同楚军一战了。”接着,他吩咐战士们砍伐树木,作为补充武器。第二天,也就是四月初四日,晋军在城濮摆开阵势,等候对敌。
楚国的军队,分为左、中、右三军。左军由子西率领。右军是陈、蔡的军队组成的,由子上率领。中军是主力,子玉亲自指挥。子玉过低地估计了晋国的力量,过高估计了自己的力量。在决战以前,他还夸口说:“今天晋国一定要完蛋了!”
会战开始,晋文公命令下军副将胥臣率领一支部队,首先向楚的右军进攻。胥臣把驾车的战马都蒙上虎皮,向前冲去。陈、蔡联军的战马惊惧起来,伏倒在地。士兵也惊慌失措,纷纷弃阵逃跑。楚国的右军崩溃了。接着,晋上军主将狐毛假充中军,竖起两面大军旗,装作要退兵的样子。同时,下军主将栾枝也叫人用战车拉着树枝,扬起尘土,假装败逃。楚军看到这种情景,误认为晋国的主帅败退了,就驱马追击。晋将见楚军中计,先轸、谷阝溱就指挥中军,拦腰冲杀过去。狐毛、狐偃也指挥上军,夹攻子西。楚国的左军也崩溃了。只有子玉及时收兵,才没有全军覆灭。
就这样,城濮之战以楚国的失败和晋国的胜利而结束了。
在这次战役里,晋军俘获了楚国的战车一百乘,步兵一千人。战斗结束以后,晋军在城濮休整了三天,吃的是楚军积聚的粮食。四月初八日,晋军高唱凯歌,班师回国。
楚成王本来就不大同意子玉同晋国作战,这回听说楚军战败,更是生气。他派使者对子玉说:“申、息两地的子弟跟从你出征,现在都战死了。你活着回来还有什么面目见他们的父老?”意思是要子玉自杀。使者没有到达以前,子玉也曾经想自杀,结果被子西和子玉的儿子大心劝止。所以子西和大心听了使者的那番话以后,便急忙替子玉辩解说:“子玉本来也想自杀,是我们阻止了他,要他回国接受国法的制裁。”使者把子西和大心的话转告楚成王。楚成王感到说得有理,于是又差遣使者向子玉传达免死的命令。但是,在使者还没有赶到以前,子玉已经在连谷(楚地名)自杀了。
子玉虽然骄傲自大,缺少计谋,但仍旧不失为楚国的一员猛将。因此,晋文公听到子玉自杀的消息,高兴地说:“以后就没有人同我作对了。”