全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-04-03_2.5W字!8个场景问题!带你了解最实用的 git 操作!!!

您的位置:首页 >> 新闻 >> 行业资讯

2.5W字!8个场景问题!带你了解最实用的 git 操作!!! 关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding ?网上稍微搜一搜,每一篇 git 文章都在教你怎么 git add,git push,少数文章会给你说 git cherry-pick,git stash,但是很少有文章会给你说 git rebase。 从刚工作时起,你的 leader 前辈们都在告诉你,git rebase 很危险,平时就用 git merge 就行了,所以你工作了三五年,还没怎么用过 git rebase,有时候遇到 git 问题,不是删分支就是在删分支的路上,我猜你还会把需求代码先一点一点复制粘贴下来,然后删除旧分支再建新分支,再改回去,对吧? stop!!! 诶棒油,你的头顶长了什么东西,我眼睛里没有~ 那么今天,我们 git rebase 要讲,git cherry-pick、git stash 也要讲,而且要讲一些可能大家不知道的,实用的 git 知识和操作。 带着问题找答案,先来看看下面八个问题,你是否能解决。如果你都能解决,那么恭喜你,你的 git 已然化境: (前四个问题只能算是开胃小菜) 「新需求忘记开新分支,提交到其它分支了,怎么办?」「新开发了一个功能,合并 master 了,产品过了一段时间说不要了,怎么办?(不可以殴打产品)」「功能开发了一半,需要拉一下 master,但是你又不想 commit 代码怎么办?」「刚才提交了一个 commit,发现 message 写得有问题,怎么办?」「需求开发提交了几个 commit,提交 master 时领导 review 后,说你第一笔 commit 代码有问题,让你改一下,怎么办?」「刚才提交了很多个 commit,发现最初的 commit meesage 写得有问题,怎么办?」「一个大需求开发了一个月,每天拉 master 代码合并到本地分支,发现这个需求自己提了十多个 commit,需求需要发布 merge 到 master 了,领导让你把十多个 commit 合并成一个,方便 code review,怎么办?」「昨天提交了一个 commit 到 master 了,今天发现 commit message 写错了,但是 master 上别人的提交已经有几十上百个了,领导说你 message 写错了,改一下,怎么办?」不能完全解答的朋友就请继续往下看。 为了方便演示,我现在新建一个 git-demo 的项目,新增 a.js、b.js、c.js、d.js 四个演示文件,每个文件一句代码,每个文件一次 commit 共四个 commit: 问题1:新需求忘记开新分支,提交到其它分支了,怎么办?我当初犯过最严重的错误就是,同时开发两个需求,忙来忙去,两个需求的 commit 搞岔了,两个分支都各有另一个需求的 commit,当时带我的同事都懵了。 然后在他一顿猛如虎的操作下,才理清了我的 commit。 其实答案很简单,就是 cherry-pick,这倒不是什么新鲜知识,很多有点工作经验的都知道,那为什么我们还讲,一是照顾新同学,二是这个命令对我们后续的题目解答很重要。 git cherry-pcik 的作用,就是将任意分支的 commit 挑拣到当前分支,但是这个挑拣不会删除原分支的 commit。 使用方式,就是紧跟着我们某个 commit 的 hash 值,可以跟多个,每个 hash 使用空格分割: git cherry-pick 123abc 456def 789ghi 不妨在演示项目中新建一个分支 test: 我们在 test 分支新增一个 commit: 然后我们复制 e.js 的 hash,切回 master 使用 cherry-pick 将其应用到 master 上: 而 test 分支的 e.js commit 不会受到影响: 这就是 cherry-pick 最简单的应用。 不过,你聪明的小脑袋瓜可能会问,cherry-pick 任意分支?那挑拣的 commit 如果是在本分支呢? 诶,问得好,我们不妨试试。 先将刚才的 e.js 从 master 撤回。然后将 e.js、d.js 做 cherry-pick,这里的 e.js 是 test 分支的,d.js 是 master 分支自己的,我们在 master 分支做 cherry-pick 操作: 注意看红框里的内容,第一个框里说的意思,就是上一个 cherry-pick 是空的,可能是解决冲突产生的,你可以直接执行git commit --allow-empty将没有任何内容更改的 commit 提交到当前分支。 假设我们直接执行git commit --allow-empty,会弹出 vim 编辑器让我们编辑该 commit 的信息: 我们不做任何操作,直接按esc键,然后输入:wq并按回车键退出: 可以看到,d.js 有两次 commit: 回到前面,除了git commit --allow-empty,git 还提示我们有其它几个命令可以选择: git cherry-pick --skipgit cherry-pick --continuegit cherry-pick --abortgit cherry-pick --skip的意思就是跳过,d.js 本身对比 master 自身来说没有任何修改,是空的,直接跳过,仅 cherry-pick e.js。 git cherry-pick --continue的意思是说,当你使用 git cherry-pick 遇到冲突,解决冲突并把修改添加到暂存区(使用 git add)之后,就可以使用这个命令,让 git 继续执行 cherry-pick 操作。如果你没解决冲突,一直执行这个命令,是不会有任何有意义的效果的。 git cherry-pick --abort则是放弃此次 cherry-pick,只要放弃了,所有内容都不会 pick,包括 e.js 也不会被 pick 过去,等于直接放弃本次 pick 操作。 综上,如果你在 cherry-pick 时不小心 pick 了本分支的 commit,且是空白内容没有实质性内容冲突,最好执行git cherry-pick --skip。但是实际上,那么多个 commit,它只会提示你The previous cherry-pick is now empty, possibly due to conflict resolution.,你并不知道具体是哪个,直接跳过也不见得是正确的,也可以先 pick 过来,再决定取舍。 另外,cherry-pick 的 commit 理想状态下是没有冲突的,但是很多时候会有冲突,必须解决冲突了才能继续 cherry-pick。 具体点说,冲突解决完,需要继续git add 文件1 文件2 ...,然后修改 commit message。 这两步做完,还需要继续执行: git cherry-pick --continue 这样呢,一次 cherry-pick 的过程才算结束。 再多说一句,git cherry-pick 本就应该用于挑拣其它分支的 commit,所以用的时候不要挑拣本分支 commit。 问题2:新开发了一个功能,合并 master 了,产品过了一段时间说不要了,怎么办?这个问题也不算太难,直接 git revert。 使用方式,也是跟 hash 值: git revert 123abc 456def 当然,上面的用法是针对不连续的 commit 来说的,如果你是连续的多个 commit 一起撤回,可以这么用: git revert start_commit(不包含)..end_commit(包含),例如: git revert abcdef123..7890abcd 问题3:功能开发了一半,需要拉一下 master,但是你又不想 commit 代码怎么办?git stash。 又是一个高频使用的命令,重要性不言而喻。场景很多,比如,我在当前 bug_fix 分支,在修复一个 bug,突然来了一个优先级更高的 bug,那已经写的代码不能直接 commit 吧?你当然可以说建一个新分支呗,一个 bug 一个分支,这也是一个解决方案,不过各家公司有各家公司的要求,具体问题具体分析。不切换分支的情况下,就可以 git stash。 修复完这个紧急 bug 后,我们需要继续修复前一个 bug,就可以执行git stash apply将之前暂存的代码恢复,继续开发。 不过,这里需要注意,git stash apply是应用最近一次 stash 的代码,如果你存了很多个,就必须指定。 我们可以通过git stash list命令查看所有的 stash: stash@{0}: On main: stash1 stash@{1}: On feature: stash2 stash@{2}: On feature: stash3 stash@{3}: On main: stash4 越上面的越新,如果我们要应用某个旧的,指定一下即可: git stash apply stash@{3} git stash 和 git commit 一样也可以设置 message: git stash -m'stash: 这是一个 stash' 篇幅所限,我们用表格汇总下 stash 命令: 命令作用示例git stash或git stash push将当前工作目录和暂存区的修改保存到栈中git stash push -m "保存修改"git stash list查看当前保存的所有 stashgit stash listgit stash apply应用最近一次保存的 stash,应用后 stash 仍保留在栈中git stash applygit stash apply stash编号应用指定的 stashgit stash apply stash@{1}git stash pop应用最近一次保存的 stash,并将其从栈中删除git stash popgit stash pop stash编号应用指定的 stash 并将其从栈中删除git stash pop stash@{1}git stash drop删除最近一次保存的 stashgit stash dropgit stash drop stash编号删除指定的 stashgit stash drop stash@{1}git stash clear删除栈中所有的 stashgit stash cleargit stash show查看最近一次 stash 的差异git stash showgit stash show stash编号查看指定 stash 的差异git stash show stash@{1}git stash show -p stash编号查看指定 stash 的详细差异内容git stash show -p stash@{1}问题4:刚才提交了一个 commit,发现 message 写得有问题,怎么办?git commit --amend。 当我们执行完命令后,会打开 vim 编辑器: vim 编辑器的使用其实很简单,我们输入 i,底部会提示我们进入编辑模式: 我们使用箭头移动光标位置,输入新的 message: 修改完成,按esc键,再输入:wq回车,操作完成。 问题5:需求开发提交了几个 commit,提交 master 领导 review 后,说你第一笔 commit 代码有问题,让你改一下,怎么办?这里的意思很简单,当我们辛苦开发了一阵子需求,提了好几个 commit 后,发现某一笔(非最新一笔)的代码有问题,需要修改,一般人的做法,就是库库一阵改了,再提个新的 commit 呗。 这其实也可行,但是还是那句话,不同的公司有不同的规范,commit 的管理尺度各不相同,所以不用太较真场景和问题的解决方法。 假设我们现在不新增 commit,就在原 commit 的基础上修改,这就需要用到 rebase。我们不讲深奥的理论,就只讲实操和现象,你先用起来再说。 现在,我们将 b.js 的const a = 1的内容修改一下,且不新增 commit。 我们需要执行命令git rebase -i hash。 这里有个关键点,rebase -i 操作,后面跟的这个 hash 是一个开区间,也就是不包含在内的意思,假如,我要修改 b.js,hash 就是 a.js 的 hash,假如我要修改 c.js,hash 就至少得是 b.js 的 hash。 Talk is less,show me the code. 直接看结果,假设是 a.js 的 hash: git rebase -i 081b0c26a4d7deb04ed1625b2a84f31f24d5fbe8 那么我们就可以编辑 b、c、d 三个提交。 假设是 b.js 的 hash: git rebase -i b8cd836ef539457228a86fca8ddeb3ec2b52017e 那么我们就可以编辑 c、d 两个提交。 其实就是在这个开区间的 hash 范围内,所有的 commit 都可以被操作。 现在,我们就修改一下 b.js 的内容,不新增 commit: 这里绿色区域的文字,默认进入是 pick,当我们要操作某个 commit 时,将其替换为对应的操作,例如: edit 的意思就是编辑该 commit。务必记得,在 vim 编辑器里,需要先键入i才能进入编辑模式。然后我们继续esc+:wq退出: 到了这一步,我们相当于穿越时空,来到了 b.js 提交的那个时空,我们在当前可以任意修改文件,任意操作代码,然后执行 commit,或者使用git commit --amend修改当前 b.js 的 message。 我们将 b.js 代码内容修改一下: 修改完代码,务必将修改后的代码暂存: 暂存完,这一步我们需要修改 commit message,如果我们不修改 commit message,我们直接git rebase --continue,系统还是会弹出 vim 编辑器让我们修改,不修改的话我们直接esc+:wq退出: 仔细观察红框中的内容,首先是 commit 没有什么变化,其次,master 分支名旁边的表示 rebase 进程的提示没有了。 那么,我们针对历史 commit 代码的修改就结束了。 好了,这时候聪明的你又会问,除了 edit,还有其它的操作吗? 有的,有的兄弟,这样的命令一共有 11 种: pick 就是默认的,reword 是只修改 commit message 不修改代码,squash 是将多个 commit 合并为一个。 squash 这里比较重要,我们继续来举个例子,假设我一共 4 个 commit,那么到底什么场景下我会需要把它合并成一个呢? 首先,开发时间长,每天都可能要处理不同需求和 bug,有时就只能先 commit,然后去做其它事情。这样就会产生多个 commit,当我们开发完了,我们需要提代码给 leader review,你一个需求不能整个五六个、七八个 commit 给他看吧,这时候就需要合并 commit。 其次,假设我现在修改 bug,先写了一版,推上去发现有问题,我需要继续修改,此时我当然可以使用上面的 git rebase 的 edit 方法,不过你也可以再新增一个 commit,然后合并 commit,这也是一种方案。 OK,废话不多说。 假设我现在需要把 b.js、c.js 的 commit 合并为一个: 此时是 a.js 的 hash,才能选择 b.js 与 c.js。 git rebase -i 081b0c26a4d7deb04ed1625b2a84f31f24d5fbe8 (s 是 squash 的缩写) 但是你发现,为什么第一个 s 是红色的? 其实是因为,在 squash 操作中,第一个 commit 不允许被 squash,第一个默认就是 pick。 假设合并 b & c,需要这样: 假设合并 c & d,需要这样: 假设合并 b & c & d,需要这样: 那么继续esc+:wq退出,如果有冲突会按照冲突流程处理,前面我们已经处理过。 可能看到这里,你又有疑问,如果git rebase -i hash的 hash 是开区间,那我就是要编辑或者合并 a.js 的 commit 怎么办? 可以使用参数 --root 解决: git rebase -i --root 必须这样执行,不需要加 hash。 这样又引出了新的问题,就是,我操作完了,发现搞错了,我怎么反悔?得回到 squash 前的状态啊!! 这里就涉及到 git 的 back 操作,想必你工作中也用到过,前面的内容中我们也提到了 revert。 那这里的回退,我们卖个关子,放在后面讲。 现在以表格整理一下这些命令,其余命令大家可以实操试试,毕竟实践出真知。 简称英文全称解释ppick按原样应用指定的提交,让提交按原有的顺序和内容应用到变基后的分支上。rreword应用该提交,但会暂停以允许修改提交信息,可用于完善之前提交时写得不够清晰或有错误的提交信息。eedit应用该提交,但会暂停以便修改提交内容,你能对此次提交所做的更改进行调整,之后使用git commit --amend更新提交。ssquash将该提交与前一个提交合并,并且可以编辑合并后的提交信息,有助于把多个相关的小提交合并成一个更有意义的大提交。ffixup类似于squash,将该提交合并到前一个提交,但会丢弃当前提交的提交信息,只保留前一个提交的信息。xexec在处理到该提交时执行一个 shell 命令,允许在变基过程中插入自定义操作,如运行测试脚本等。ddrop移除该提交,即不将此提交应用到变基后的分支中,可用于去除不必要的提交。bbreak在该提交处暂停变基,让你可以手动检查状态或执行额外操作,之后使用git rebase --continue继续变基。llabel在当前位置创建一个新的标签,类似于git label命令,方便后续引用该位置。treset返回到指定的标签位置,撤销自该标签之后的所有变基操作。mmerge引入指定的标签或提交,将其与当前分支合并,就像执行了一次git merge操作。问题6:刚才提交了很多个 commit,发现最初的 commit meesage 写得有问题,怎么办?通过前面的学习案例,后续的问题我们直接给出参考答案,减少演示带来的阅读负担。 第一个你应该想到的思路,就是 git rebase -i,并执行 reword 或者 edit 命令。 第二个思路,就是直接 revert 该 commit,然后重新 commit 时修改 message。 问题7:一个大需求开发了一个月,每天拉 master 代码合并到本地分支,发现这个需求自己提了十多个 commit,需求需要发布 merge 到 master 了,领导让你把十多个 commit 合并成一个,方便 code review,怎么办?git rebase -i,执行 squash 操作。 当然了,这是一个理想状态,你的需求的 commit 是连续的,只有你自己的 commit。 可现实开发中,一个大需求绵延一个月,我们每天还要更新 master 的代码,我们自己的 commit 可能散落在各个时间点上,不能直接 squash,不然你就会面对几百个上千个 commit,无异于大海捞针。 最正确的做法,是我先将开发完成的分支 push 到 remote 仓库,然后我新建一个 merge request,不要直接确认,我们只是需要其 diff 出分支上的更改。因为此时 gitlab 等托管平台已经会自动 diff 出本分支的 commit,这样你不用再去翻找一月前的那些 commit 了。 然后,你新建一个分支,将原来分支上所有的 commit (这就是为什么要在原分支新建 merge request,方便你复制 commit hash)使用 cherry-pick 转移到新分支上来。 接着使用 squash 操作将其合并为一个 commit,再推送新分支到 remote,发起真正的 merge request。 怎么样!!这个思路是不是很 sao ~。 问题8:昨天提交了一个 commit 到 master 了,今天发现 commit message 写错了,但是 master 上别人的提交已经有几十上百个了,领导说你 message 写错了,改一下,怎么办?你可能会说,git rebase -i,执行 reword 或者 edit。 是的,这不算错。 但是这和第 6 题不同,这是已经在 master 上的修改了,不是本地的 commit。 如果我们执行 rebase 操作,因为涉及到变基,代码 push 到托管平台后,会 diff 出你的变更,它会把该 commit 后的所有 commit 都识别为你的变更,你会发现你这个分支提上去 merge 到 master 时会有 N 个 commit,那些 commit 都是你同事的,且已经是在 master 上了。 理论上你直接合并也没有问题,因为你本身没有修改过任何东西,哪怕合上去起了冲突,冲突解决完就行了。但是你的领导看着你的这个操作,明明只是修改了一个 commit message,但是却多出来 N 个已经在 master 的 commit,他看到肯定会懵逼,几乎不会同意你的 merge request。 所以,最好的解决方案是就是: 将错就错~? 哈哈,大概率现实是这样的,你的 leader 会和你说,错就错了,一个 commit message 而已。 这其实没毛病,但是如果管理严格一点的公司呢? 或者说,这个问题难道真的没法解决吗? 其实方案我们在第 6 题也提过。 解决办法就是先对其 revert,然后重新 commit,这是最稳妥的解决办法。 对,思路就是这么简单,不要拘泥于 git rebase 强大的历史 commit 能力,最简单朴素的方式或许是最安全的。 一点点后续:我想反悔,怎么办?假如我们 git rebase 出错了怎么办? 假如你还没执行完,你的分支显示是这样的:master|REBASE,那么你可以直接执行git rebase --abort。这会直接放弃本次 rebase。 其它的情况,例如 cherry-pick 也是同理。 但是,假如你的分支变成了((0903e23230...))或者其它你看不懂的样子,并且 commit 也不见了一些,别慌!! git 其实为我们保存了所有的历史记录。 我们使用 git reflog 可以查看: 想退出此模式的话直接q或者wq。 假设现在我想回到下面红框时候的 commit 状态: 此时,我只需要先复制它的 hash —— c7d7bbb,然后 reset: git reset --hard c7d7bbb 就能回到最初的时候了!~ 不过使用--hard参数会丢失暂存区的更改和影响工作目录,如果你不是很明确地想要回退到某个历史记录上,建议使用git reset --soft。下面也列一下 reset 的参数: 参数作用描述--soft仅移动分支指针到指定提交,暂存区和工作目录的内容保持不变,不改变文件的修改状态,暂存的内容依然保留。--mixed默认参数,移动分支指针到指定提交,同时重置暂存区,使其与指定提交时的状态一致,但工作目录中的文件内容不会被修改。--hard移动分支指针到指定提交,并将暂存区和工作目录的内容都重置为指定提交时的状态,会覆盖未提交的修改,使用需谨慎。--merge用于处理合并冲突后,将分支指针重置回合并前的状态,同时保留工作目录和暂存区中已解决的冲突内容。--keep尝试将分支指针移动到指定提交,同时保留工作目录中的修改。若工作目录中的修改与指定提交存在冲突,重置操作会失败。--abort终止一个正在进行的--merge或--keep重置操作。给个三连吧!!!!!!!!!!!! 往期推荐爆肝两个月,我用flutter开发了一款免费音乐app80+????102+?? 搭建一个快速开发油猴脚本的前端工程24+????42+?? 金九银十招聘季,IT 打工人,该怎么识别烂公司好公司?70+????80+?? 为什么就这个文件的 ESLint 检查失效了? 学会 TypeScript 体操,轻松看懂开源项目代码 别人休息我努力,悄悄写个 cli 工具,必须提升效率,skr~60+????110+?? 一文掌握 eslint,再也不怕项目报错20+????30+?? 开发一个 npm 库应该做哪些工程配置?40+????50+?? 分享我在前端学习与开发中用到的神仙网站和工具40+????110+?? uniapp 踩坑记录(二)130+????150+?? 闲来无事,摸鱼时让 chatgpt 帮忙,写了一个 console 样式增强库并发布 npm100+????110+?? uniapp 初体验踩坑记录30+????60+?? 两小时学会 JS 正则表达式,终身不忘50+???? 【一年前端必知必会】如何写出简洁清晰的代码50+???? 【一年前端必知必会】了解 Blob,ArrayBuffer,Base6440+????90+?? 点击关注公众号,“技术干货” 及时达! 阅读原文

上一篇:2021-06-15_2021金瞳奖“最具口碑原创剧集”、“最具口碑原创内容栏目”投票开始啦! 下一篇:2021-07-09_15位广告大佬火力全开 , 这些话你不得不听……

TAG标签:

20
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价