git使用笔记

52 阅读6分钟

git-scm.com/book/zh/v2

代码找回:代码被同事强推覆盖了,自己本地的分支也删掉了

和同事一起开发一个模块,测完没问题已经删掉了本地分支,同事使用git push -f,导致自己最后一个commit丢了,咋整?

git reflog // 查看本地历史提交信息
git checkout <commit-hash> // 切换到需要找回的节点
git checkout -b new-branch-name <commit-hash> // 在这个节点位置创建一个新的分支

几个常用命令

1. 删除某次commit

git log //查看某次commit id 
git rebase -i <commit id> 
按i键进入编辑模式,将commit前的pick改为drop,然后输入“:wq”保存退出 
git log //检查,已经没有了commit id对应的commit信息

2. 删除某次提交到远程的push:待确认(回退到某个commit的版本,然后强制合并到远程,实质不是删除回退,而是覆盖)

git reset --hard xxx //commit id 
git push origin HEAD:develop  --force//git push <远程主机名> <本地分支名>:<远程分支名>

3. 创建标签: git tag

git tag -a tagName -m "message" // 附注标签

4. 从远程拉取:git pull 命用于从远程获取代码并合并本地的版本:默认情况下git pull 其实就是 git fetch 和 git merge FETCH_HEAD 的简写

git pull <远程主机名> <远程分支名>:<本地分支名> 
git pull origin master:brantest git pull origin master 
//如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

git pull --rebase // 有些团队要求使用这个模式,后面再详细展开

5. 退回提交:git reset。

git reset [--soft | --mixed | --hard] [HEAD] 
--mixed 为默认,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变 
   $ git reset HEAD^ # 回退所有内容到上一个版本 
   $ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本 
   $ git reset 052e # 回退到指定版本 
--soft 参数用于回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可 
   git reset --soft HEAD 
--hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:

图形化使用

source tree官方使用说明 不只是sounce tree,ide中内置的图形化插件也是很好用的,都安装上,都尝试尝试,各有优势。

Android studio中,compare功能:当发生代码冲突时,或者要对比两个分支的差异,选出自己想要的代码,很方便。

image.png 很多图形化的操作,都能用命令行,有的指令有点长,用图形化点点点会快很多。在账户管理,节点/分支管理上会清晰很多。

遴选cherry-pick(命令行传送门

遴选经常用,假如现在有一个紧急修复,在dev分支处理后需要提交到主分支,但是dev有一些其他的提交不能合并过去,可以选择使用遴选。

image.png

merge和rebase

为了避免上图问题,设置pull为rebase模式,很多公司,都有这个要求,个人也比较喜欢这种。但是有时用merge确实会比rebase好。

git config --local/--global/--system --add pull.rebase true (默认是添加在local配置中)

官方文档中,关于merge和rebase有以下说明:

image.png

两种观念

rebase,会丢失提交历史的信息,有的团队会很看中这个,有的团队不会看重。

假如遇到了一个因为提交信息的完整性而不让用rebase的团队,个人觉得,有坑的可能性会增大许多。猜想一下,为什么需要回溯到哪一个人哪个时间提交了哪一行代码,需要这么详细的代码记录,是因为什么而实锤什么。难道没有清晰的版本线吗?没有迭代没有经过测试控制稳定性?一行代码,随随便便就能发生产,绕过测试,造成巨大损失,然后再找写代码的人算账?我目前还没有遇到这种公司,不知道这种公司存不存在。

说明中指出的原则:

  1. 对尚未推送或分享给别人的本地修改执行变基操作清理历史
  2. 从不对已推送至别处的提交执行变基操作

看不懂讲了什么。不纠结了,回想一下日常开发中可能出现的这两点:

  • 场景1:甲乙两人开发一个支付模块,在master分支上开了个dev_pay分支;
  • 场景2:丙开发的另一模块提前测试完毕,已经合并到了master分支,此时dev_pay功能提交测试时,测试要求携带全功能,于是甲将dev_pay基于master分支rebase后强行推到了远程;

对于场景1,应该是坚持使用rebase,确保每次提交的代码都是基于上对方最新提交的代码,保持一条清晰的直线。

对于场景2,乙此刻就不建议用pull rebase了,否则大概率会被解决冲突搞到怀疑人生,还不如将本地想要提交的代码stash后删除dev_pay分支,从远程重新拉取dev_pay分支后stash pop再commit。

如果在场景2中,甲不是对master执行的rebase操作,甲将代码merge到了master,此时乙将dev_pay分支对master操作rebase时,也有很大的概率陷入一堆的冲突中,而且是反复的冲突。

工作中推荐用rebase,而不是merge

日常大部分工作中,都适合用rebase,不仅仅是因为能减少一个分叉和少一个commit,还因为merge用多了,会变成下图这样,如果某版本commit太多,merge后会更难看。

对于使用rebase的团队,往往会配合squash一起使用,在合到主分支时,将一个需求中的多个commit合成一个,形成一条十分好看的版本线。有的团队,master是锁定状态,合并代码需要在网页端提交merge request(MR),提交后进行review,团队成员check后才能操作合并,合并时,系统不允许有代码冲突存在,只能使用rebase后提交MR。

大部分公司都是适合用rebase的,甚至在需要用merge的公司大部分时间也是更适合用rebase。如果习惯性的merge,一出手就把分支劈开了,会被讲究的团队提醒,用习惯了rebase的团队,往往还有点洁癖,有的甚至会被diss(不放链接了,搜一下,很有趣,评论区很有趣)。