赞
踩
目录
4、提交—git add / git commit / git push
7、撤销恢复—git checkout / git reset / git revert
(1)、撤销未 add 时的代码用 git checkout
(2)、撤销已经 commit 但未 push 的代码建议用 git reset
(3)、撤销已经 push 的代码建议用 git revert
8、git 合并及删除历史提交——git rebas(必须慎用)
另外还有一个远程仓库:比如GitHub上的库。
他们之间的关系如下:
从远程仓库克隆代码到版本库(本地仓库)。
git 拉取远程分支到本地:
git pull origin [远程分支名称]:[本地分支名称]
这等价于:
- git checkout -b [本地分支名称]
- git branch --set-upstream-to=origin/[远程分支名称] [本地分支名称]
拓展
git status -s 或 git status --short:
状态简览。
git diff: 工作区和暂存区比较。
git diff --cached: 工作目录与上次提交时之间的所有差别,这些内容在不带"-a"参数运行 "git commit"命令时就会被提交。
git diff HEAD: 工作目录与上次提交时之间的所有差别,这条命令所显示的内容都会在执行"git commit -a"命令时被提交。
git diff --word-diff: 使用逐词比较,默认是逐行比较。
git diff <分支名>:查看当前的工作目录与另外一个分支的差别。
git diff <分支1>..<分支2>:比较项目中任意两个分支的差异。如果你想找出 <分支1> 和 <分支2> 的共有父分支和 <分支2> 之间的差异,你用3个‘.'来取代前面的两个'.' 。对比后的结果解读为:“<分支2>比<分支1>增加或删除了xxx。”
git diff HEAD -- ./lib:你当前工作目录下的lib目录与上次提交之间的差别(或者更准确的说是在当前分支)。
提交指定文件:
【拓展】
git commit --amend 修补提交命令,实际上相当于执行了以下两条命令(注:.git/COMMIT_EDITMSG 是保存上次提交的日志):
- git reset ---soft HEAD^
- git commit -e -F .git/COMMIT_EDITMSG
git rm 文件名
git rm -f 文件名
git rm --cached 文件名
请谨慎使用这些方法,因为它们都会丢弃工作目录中的未提交更改:
git checkout 既可以用来切换分支,又可以用来恢复工作目录。下面只对 git checkout “恢复工作目录” 的功能进行研究。
语法:
git checkout . :维持 HEAD 的指向不变,用暂存区的 “所有文件” 直接覆盖 “工作区文件”,相当于 取消自上次 git add 的修改。
git checkout branch --<filename>:维持 HEAD 的指向不变,用 “某个分支的文件” 替换暂存区和工作区中相应的文件。
git checkout HEAD <filename> 或 git checkout HEAD . :将 HEAD 指向的版本库文件,同时替换暂存区和工作区文件。
案例:
放弃本地修改,用暂存区的 “所有文件” 直接覆盖 “工作区文件”(本地文件):
- // 放弃本地修改,用暂存区的 “所有文件” 直接覆盖 “工作区文件”(本地文件)
- git checkout .
- git pull origin <分支>
【注意】
此命令 不会删除掉刚新建的文件(尚未 git add)。因为刚新建的文件还没有加入到 git 的管理系统中,对于 git 来讲是未知的,此时需要自己手动删除该新建的文件就好了。
【拓展】
语法:
git reset --hard <版本号>:放弃本地修改,强制回退到某个版本。
git reset --hard origin/<分支>:放弃本地修改,强制保持与远程分支一致。
git reset --hard HEAD^ 或 git reset --hard HEAD~1:撤销上 1 次的commit,不保留本地修改。
git reset --hard HEAD~2:撤销之前 2 次的commit,不保留本地修改。
git reset --soft <版本号>:保留本地修改,强制回退到某个版本。
git reset --soft origin/<分支>:保留本地修改,强制保持与远程分支一致。
git reset --soft HEAD^ 或 git reset --soft HEAD~1:撤销上 1 次的commit,保留本地修改。
git reset --soft HEAD~2:撤销之前 2 次的commit,保留本地修改。
选项:
--mixed:这是默认操作。重置索引而不是工作树(即,保存更改的文件但未标记为提交)并报告尚未更新的内容。
--soft:根本不触摸索引文件或工作树(但将头重置为 <commit> ,就像所有模式一样)。这git status将使所有更改的文件“变更被提交”,就像它会这样。
--hard:重置索引和工作树。放弃自 <commit> 以来对工作树中跟踪文件的任何更改。
--merge:重置索引并更新工作树中 <commit> 和 HEAD 之间不同的文件,但保留索引和工作树之间不同的文件(即没有添加更改的文件)。如果 <commit> 和索引之间的文件有不同的变化,则重置会中止。换句话说,--merge 可以做一些类似的事情git read-tree -u -m <commit>,但是会传递未合并的索引条目。
--keep:重置索引条目并更新工作树中 <commit> 和 HEAD 之间不同的文件。如果 <commit> 和 HEAD 之间的文件有本地更改,则重置会中止。
案例:
放弃本地修改,强制拉取更新;或者放弃从远程分支拉取的文件,强制拉取另一个分支的文件:
- // 放弃本地修改,强制拉取更新;或者放弃从远程分支拉取的文件,强制拉取另一个分支的文件
- git fetch --all
- git reset --hard origin/<分支>
- git pull origin <分支>
【注意】
若前提是已经 push 到远程仓库了。在使用 reset 进行版本回退后,直接 push 是失败的,因为本地版本号于远程仓库的版本号不一致(本地版本号落后于远程仓库的版本后),这个时候不要去Pull操作,否则代码又还原了,得重新 reset。那怎么办呢?只需在 push 时加上命令:`--force
`(⚠️ 这很可能会删除别人提交的代码,所以最好确保别人没有提交,或者与别人沟通好此操作的必要性以及修复措施,总之这是个危险的操作,慎用),强推,强制覆盖,即可。
git push --force origin develop
【拓展】
详解git reset --hard 和 git reset --soft区别
语法:
- git revert -n <版本号>
- // 或
- git revert -n HEAD~<n-1>
- // n:代表该提交记录的次数
- // n - 1:恢复 HEAD 中某个版本提交的代码时,要指定 HEAD 到 该版本的前一个版本
git revert -n <版本号>:回退到指定的历史版本提交的更改,不自动提交(删掉 该版本号 及其之前 的所有已 push 的更改,等待提交)。这样就把该版本的记录删除了。
git revert -n HEAD~0:回退到 HEAD 中最后一次提交的更改,不自动提交(删掉 上次已 push 的更改,等待提交)。
git revert -n HEAD~2:回退到 HEAD 中倒数第3次提交的更改,不自动提交(删掉 这三次已 push 的所有更改,等待提交)。
选项:
-n(--no-commit ):仅仅恢复工作树和索引,修改后不自动提交,最后一起手动提交。 revert 命令默认会对每一步的 commit 进行一次提交,-n 后可以 最后一起手动提交。
案例:
1⃣️、恢复 HEAD 中最后 1 次提交指定的更改,并使用恢复的更改创建一个新的提交。
- git revert HEAD~0
- git commit -a -m 'revert 到上一个版本'
2⃣️、我们提交了 6 个版本,其中 HEAD 2-3 包含了错误的代码需要被回滚掉。 同时希望不影响到后续的 HEAD 0-1。并使用恢复的更改创建一个新的提交。
- // 查看历史
- git reflog
-
- * 982d4f6 (HEAD -> master) HEAD@{0}: commit: one
- * 54cc9dc HEAD@{1}: commit: two
- * 551c408 HEAD@{2}: commit: three error
- * 7e345c9 HEAD@{3}: commit: four error
- * f7742cd HEAD@{4}: commit: five
- * 6c4db3f HEAD@{5}: commit: six
- // revert 代码
- git revert -n f7742cd..551c408
- // 或
- git revert -n master~4..master~2
- // 提交
- git commit -a -m 'This reverts commit 7e345c9 and 551c408'
【注意】
当你 revert 到一个已经 revert 过的版本之前的 版本号 时(比如:有1、2、3三个历史版本,你先revert到2,然后再revert到1),revert 依然可以找到此版本的更改(也就是1版本的更改),此时,当前版本(也就是1版本)一定会与上一次 revert 后的版本(也就是2版本)产生冲突,需要手动合并代码、解决冲突,然后提交。
revert 后的代码可能会产生冲突,若产生冲突,需要手动合并代码、解决冲突,然后提交。
【拓展】
下图是 git reset 和 git revert 的区别:
如果已经 push 到远程仓库了,不建议用 rebas。因为一旦 rebase 了,别人再 pull 代码时就会出现一大堆的冲突,最恶心的是基本没法修复。
git rebase 是对代码进行比较,将分之修改后的代码打到另外一个分支之后。而 git merge 则是将另外一个分支的代码打到当前分支之后。
git rebase -i HEAD~n // n 就是 HEAD@{n} 里的 n,可记为:操作的记号
【注意】上述代码中的 HEAD~n 与通过 git reflog 查到的 HEAD@{n} 有时候并不一致。
在另一个基础提示之上重新应用提交。
- git rebase [-i | --interactive] [<options>] [--exec <cmd>]
- [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
- git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
- --root [<branch>]
- git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
列出即将被重新设置的提交。让用户在变基之前编辑该列表。此模式也可用于拆分提交(请参阅下面的拆分提交)。
可以通过设置配置选项 rebase.instructionFormat 更改提交列表格式。自定义指令格式将自动将长提交哈希添加到格式中。
在最终历史记录中创建提交的每一行之后附加“exec <cmd>”。<cmd> 将被解释为一个或多个 shell 命令。任何失败的命令都会中断 rebase,退出代码为 1。
您可以通过使用多个命令的一个实例来执行--exec 多个命令:
git rebase -i --exec "cmd1 && cmd2 && ..."
或通过提供多个--exec:
git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
如果 --autosquash 使用,“exec” 行将不会被附加到中间提交,并且只会出现在每个 squash/fixup 系列的末尾。
这在 --interactive 内部使用了机器,但它可以在没有显式 --interactive。
创建新提交的起点。如果未指定 --onto 选项,则起点为 <upstream>。可以是任何有效的提交,而不仅仅是现有的分支名称。
作为一种特殊情况,如果只有一个合并基,您可以使用“A...B”作为 A 和 B 的合并基的快捷方式。您最多可以省略 A 和 B 中的一个,在这种情况下,它默认为 HEAD。
修改 vim 文档时要按照下面的不同选项,来实现自己想要的效果:
若是删除最后一次提交记录建议用 reset 恢复,因为用 rebase 会报错的,且不会删掉。
下面来验证一下:
- // 用 rebase 删除最后一次提交记录
- git rebase -i HEAD~1
执行上面的命令后,会进入 vim 模式:
- // 第五次提交(最后一次提交)
- pick 27d5738 add 5
删除上面的代码后,退出 vim 并保存,此时会提示报错:
error: nothing to do // 错误:什么也没做
所以,建议直接用 reset 操作。
于是我有了新的猜想:如果非要用 rebase,在保证满足下面的条件下是否可行?
- git rebase -i HEAD~n(其中 n > 1)
-
- // 或者直接执行(但是你的提交记录必须大于1条)
-
- git rebase -i
下面咱就来验证一下:
- // 用 rebase 删除最后一次提交记录
- git rebase -i HEAD~2
然后,会进入 vim 模式:
- // 第四次提交(倒数第二次提交)
- pick 27d5738 add 4
-
- // 第五次提交(最后一次提交)
- pick 27d5738 add 5
然后,我将上述代码的最后一行代码(最后一次提交的记录)删掉,退出 vim 并保存。
不出意外的话,此时已经成功的删除了最后一次提交的记录。
综上,既然 rebase 删除最后一次提交风险比较大,何不用 reset 来恢复到上一次提交的代码呢!
最后,push 代码到远程仓库。需要注意的是,如果你修改的代码已经 push 到远程仓库了,那么你需要 git push -f 强行提交到远程仓库。
【注意】一般这样修改提交到远程分支后,别人 pull 代码时,难免会有冲突。
假设:你 commit 了两次,想要将这两次合并为一次提交。
- // 第一次
- git commit -m "git rebase test"
-
- // 第二次
- git commit -m "git rebase test2"
第一步:进入 vim 编码模式
需要先执行:
git rebase -i HEAD~2
会进入 vim 编码模式。在 vim 文档的顶部找到默认的 pick 操作的代码,对其进行修改:
- pick 7d7477e git rebase test
- pick eb3b5fa git rebase test2
第二步:合并提交记录
若需将第二次提交合并到第一次提交上,需将第二个 pick 改为 squash:
- pick 7d7477e git rebase test
- squash eb3b5fa git rebase test2
第三步:是否修改提交信息
然后,询问你是否要修改之前的提交信息(commit message):
- git rebase test
- git rebase test2
是否要修改提交信息是可选的:
若选择修改提交信息,首先你要找到值得被修改的提交信息:因为是要将第二次提交合并到第一次提交上,那么合并后,第一次的提交的记录一定会覆盖掉第二次提交的记录,所以第一次提交的信息是值得被修改的。
我打算将第一次的提交信息由 test 改为 test1,作为最终合并后的提交信息。于是我这样改的:
- git rebase test1
- git rebase test2
然后,退出 vim 模式,操作完成。
第四步:提交代码到远程仓库
最后,要看你 rebase 的提交记录是否包含已经 push 到远程仓库的代码:
【推荐阅读】
git rebase 用法小结(包括游离分支的修复)https://www.jianshu.com/p/4a8f4af4e803
git branch
git branch 分支名
- // 切换分支
- git checkout 分支名
-
- // 创建并切换分支
- git checkout -b 分支名
【拓展】git checkout:既可以用来切换分支,也可以用来回复工作目录。
git branch -D 分支名
git merge 分支名
【拓展】
git merge的 三种操作 merge、squash merge 和 rebase merge
选项(详见官网):
--commit 和 --no-commit
--commit:执行合并并提交结果。
--no-commit:执行合并但不提交结果。
--squash 和 --no-squash
--squash:生成工作树和索引状态,虚拟合并,但实际上不进行提交、移动 HEAD
或 记录 $GIT_DIR/MERGE_HEAD
。然后,你可以通过 git commit -m 'xxx'
命令创建合并提交——这允许您在当前分支之上将原分支上的多个提交创建成单个提交。
--no-squash:执行合并并提交结果。
git diff 本地分支名 origin/远程分支名
git stash 可用于临时保存和恢复工作进度与堆栈(先进后出)中,可跨分支。
git stash 应用场景:
【注意】在未add
之前才能执行stash
!!!
git stash 命令详解:
git stash:能够将所有未提交的修改(工作区和暂存区)保存至堆栈中,用于后续恢复当前工作目录。
git stash save <message>:作用等同于git stash,区别是可以加一些注释。
git stash list:查看当前stash中的内容。
git stash pop stash@{num}:只能恢复一次。将当前stash中的指定内容恢复,并应用到当前分支对应的工作目录上。stash@{num}是可选项,不带此项则默认恢复最近的一次进度,相当于git stash pop stash@{0}。该命令会将堆栈中最近保存的内容删除,所以只能恢复一次。
git stash apply:可恢复多次。将堆栈中的内容应用到当前目录,不同于git stash pop,该命令不会将内容从堆栈中删除,也就说该命令能够将堆栈的内容多次应用到工作目录中,适应于多个分支的情况。
git stash drop <名称>:从堆栈中移除某个指定的 stash。
git stash clear:清除堆栈中的所有 内容。
git stash show:查看堆栈中最新保存的 stash 和当前目录的差异。
git stash branch:从最新的stash创建分支。应用场景:当储藏了部分工作,暂时不去理会,继续在当前分支进行开发,后续想将stash中的内容恢复到当前工作目录时,如果是针对同一个文件的修改(即便不是同行数据),那么可能会发生冲突,恢复失败,这里通过创建新的分支来解决。可以用于解决 stash 中的内容和当前目录的内容发生冲突的情景(发生冲突时,需手动解决冲突)。
总之,git stash命令的作用就是将目前还不想提交的但是已经修改的内容进行保存至堆栈中,后续可以在某个分支上恢复出堆栈中的内容。这也就是说,stash中的内容不仅仅可以恢复到原先开发的分支,也可以恢复到其他任意指定的分支上。git stash作用的范围包括工作区和暂存区中的内容,也就是说没有提交的内容都会保存至堆栈中。
- git branch --set-upstream-to=origin/<远程分支名> <本地分支名>
- // 例如: git branch --set-upstream-to=origin/fix_xiaoming fix_xiaoming
关联后,本地再 pull、push 分支时就不必每次都输入 “origin <远程分支名>” 了。
feat
增加新功能fix
修复问题/BUGstyle
代码风格相关无影响运行结果的perf
优化/性能提升refactor
重构revert
撤销修改test
测试相关docs
文档/注释chore
依赖更新/脚手架配置修改等workflow
工作流改进ci
持续集成types
类型定义文件更改wip
开发中猴子老师的学习资源:https://github.com/cucygh/fe-materialhttps://github.com/cucygh/fe-material
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。