公元前633年冬,楚成王发兵攻打宋国,接连攻下宋国几座城,兵临宋国都城商丘。宋成公急忙派大司马公孙固到晋国求救。晋国大夫先轸认为正是“报施救患,取威定霸”的良机,建议晋文公出兵。
公元前632年春,晋文公攻打楚国的两个盟国——曹国和卫国,想引诱楚军北上与其决战。不料楚军没有上当,继续攻打宋国都城商丘,晋文公的战略意图落空了。
先轸建议让宋国表面上疏远晋国,后由宋国出面,用重礼向齐、秦求援,由齐、秦两国做调解人,让楚军撤兵,同时将攻占的曹、卫两国的一部分土地赠送给宋国,用以增强宋的抵抗信心。楚国不同意齐、秦两国的调停,齐、秦两国便出兵助晋。
楚成王一看形势不妙,便命令楚军统帅子玉回撤。子玉认为自己军力强大,仍坚决要求楚成王允许他与晋军决战,以建功立业,还要求楚成王给予增援。楚成王在关键时刻拿不定主意,又有一些侥幸心理,便同意了子玉的决战请求,希冀他侥幸取胜,但是又不肯给子玉增拨充足的决战兵力,只派少量兵力前往增援。
子玉得到了增援,率领楚、陈、蔡、郑、许五国联军气势汹汹地朝晋国扑来。晋文公避开五国联军的锋芒,让晋军有计划地后退了90里,把楚军引到了预定的战场——城濮(今山东濮县南)一带。在城濮有两大盟国齐和秦的军队,一切准备妥当,只等一声令下。
楚军统帅子玉命令左右两个侧翼发动攻击。晋将栾枝将树枝拖在兵车后飞奔,扬起尘沙扰乱楚军视线,而且边战边退。子玉错误地判断晋军即将溃败,下令全军追击。不料,中途杀出由晋将胥臣率领的大队战车,马身上蒙着老虎皮,吓得陈、蔡两国军队驾战车的马惊慌回窜,阵容混乱,反而冲乱了楚军大将斗勃负责指挥的右军。晋方联军见此良机,猛烈冲击楚军右翼,击杀了蔡将公子印,斗勃也负伤带箭逃跑了,楚军右翼完全被包围。
晋将栾枝和晋上军主将狐毛、佐将狐偃已回军攻击楚军左翼,将楚军左翼拦腰截成两段,楚军左翼全军覆灭。这时候,楚军左右两翼已废,中军冲击晋中军未能取胜。晋方的上军、下军战斗胜利后又参加了主力会战,即将对楚军形成合围,子玉见大势已去,急忙命令中军撤退,迅速脱离战场。楚军战败后,向西南撤退到连谷。子玉因在途中遭受楚成王的训斥羞愤自杀,晋方联军获得了整个战役的胜利。城濮之战的胜利奠定了晋文公成为春秋霸主的基础。