最近回顾半年前写的关于git的用法,简直难以下咽。。。当是也是一知半解,面对工作情况下mark下记录的, 随着项目经验的增长(离开了老东家),对git的用法也有更深刻的理解。 当然这些流水账式的记录不能当 技术文来看待,但若干年以后再进行回顾,或许也是一件挺有趣的事情嘛。
其实半年有写到这个用法,只不过因为理解不深就简单略过了。最近有了更深的理解,于是记录下。
当你开发一个新功能,一般是从dev分支checkout一个feature分支进行开发,然后通过Pull Request团队负责人code review, 如果ok了,就合并到dev。简单的feature可以通过一个commit完成,但面对复杂的功能或者完成后需求有更改,开发者需要通过不断提交完善保证开发过程思维的清晰。这时就会产生多条commit,对与code reviewer来说,多条commit其实是很不友好的,需要code reviewer一条条查看commit的修改记录,我们应该避免这种情况,Pull Request产生一条commit,提供所有更改记录。
如果你遇到上面我说的情况,不妨在提Pull Request之前,用git rebase -i HEAD~n
合并你的commit记录
运行命令后,会出现如下交互界面,提供多个可操作功能,通过描述可以了解各自功能的意思,操作时需将commit前面的标签改为对应的功能符号即可。如将需将999298a
, 5e9377b
合并到a603830
,将999298a
, 5e9377b
前面的pick
改为squash
, 接着wq
退出交互界面,git自动进行合并。然后再看看git hitstory, 是不是被合并成一条啦。如果commit已经被推送到远程仓库了,需要 git push orgin <branch> -f
强制更新远程仓库。
pick a603830 fix(MT4LIST): trading_server_id不能为空
pick 999298a feat(Global): 导出CSV文件时,手动类型账户的TA Status、Parent、Trading Group字段内容需要为空
pick 5e9377b fix(IB&Member): 用户列表导出控制
# Rebase 3aaaf38..a6908ec onto a603830 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
git log --format='%aN <%aE>' | sort -u > AUTHORS
项目临近上线,为了保证代码质量,leader增加code review环节,意味着小弟我不能随便向master分支提交代码,转变了git-flow工作模式,也在这个时候更深一步学习了git。
- 在远程仓库创建两个分支,分别命名master, dev
- 开发成员各自从dev分支上面fork一份代码到自己仓库
- 进行feat/bug时候, 本地从fork仓库chekout一个分支, 如feat/aa,此时在自己fork的仓库创建feat/aa远程分支,分支命名最好与code改动的目的相同
- 完成开发,将本地feat/aa内容push到自己远程仓库的feat/aa,同时在git/git lab页面发起merge request, 请求将改动的分支合并到dev分支,团队讨论 觉得code没问题了,leader确定merge request,
- leader将dev合并到master分支
- 版本发布,直接从master分支打tag
上面的流程貌似说得有点乱,主要明白code review的目的是为了让产品更加稳定,要求开发者对自己的code负责,增加了团队对改动code进行review,讨论的环节,减轻测试人员的压力。
git fetch
git stash
git rebase
git stash pop //本地修改可能与远程仓库代码存在冲突
以上是我早上回到公司常做的一个操作,git fetch更新远程代码,如果你本地工作区 有修改过,没有和远程仓库保持绝对的一致,则需要用git stash,这个命令会将你的本地修改暂时缓存起来, 并使你的本地代码指向最近一次的远程更新快照。其实这个命令就是保证git rebase能够顺利进行,在rebase 完成之后,再运行git stash pop将之前的本地修改过的代码检出,在这个时候如果你的本地代码修改比较大, 会出现冲突,需要手动合并冲突,因为git并不知道哪一些代码是你最终需要的。
git stash (in 'master')
git checkout -b 'dev' (create and switch to 'dev')
git checkout master
git merge dev
在此之前,我一直有个疑问,在master主分支开发不就行了吗?为啥要多此一举创建一个分支?
直到在工作中慢慢摸索,才理解当中的意义~ 在实际开发中,有些bug或者新功能需要并发处理,
当这些需求改动比较大具有破坏性,一下子无法完成的时候,会影响当前项目稳定版本的时候,
不妨试下以上操作,创建一个新的分支进行开发,完成开发后再将代码merge回主分支。
我个人觉得这种一种良好的开发习惯,通过创建分支保持代码的干净,至少能让自己在开发中
保持清醒的思维。
git reset HEAD~n
git reset --hard HEAD~n
n代表需要回退的第几个版本
以上命名适用于本地代码有修改并提交,但还没推送到远程仓库。
如果你只是想撤销本地提交,运行第一条命令就行了,这条命令仅仅撤销提交历史记录而已,你修改的代码依然会保存到本地仓库; 如果发现自己写的代码一团糟糕,想要完全清空修改记录,则需要带上**--hard**参数,提醒一下,这条命令需要慎用,它清空你的 工作区。
git revert COMMIT_ID
以上适用于不小心错误提交代码,并且推送到了远程仓库。这个时候你可以选择把错误代码删除,重新提交推送到远程仓库;又或者使用 git revert进行版本回退,你需要找到错误提交的commit id,运行后,如果本地有代码冲突,需要手动解决冲突,冲突解决 完了,你需要手动创建一个提交,这个时候才算真正完成revert。建议使用git revert, 而不是直接修改提交推送到远程仓库, 毕竟良好的使用规范会让git的整个提交历史树更加清晰。
写到现在,发现自己没有耐心详细介绍其他语法的使用情况了,简单说下在实际工作中有遇到的情况
git commit --amend
对已经进行了本地提交,但有新的修改文件,想将这些修改的文件整合到这个提交。在此之前,你需要运用git add将文件添加到暂存区
git rebase -i HEAD~<n>
将多条提交整合到一条。该命令有很多可选项,理解不深就不详细阐述了。。。
git tag 'beta.1'
git push origin bata.1
为仓库打标签,创建一个代码版本标记,相当于历史快照,QC(测试)可以根据整个tag进行测试,而开发可以在测试期间愉快地进行后续的开发,测试报告出来后 根据这个快照方便追踪解决问题
【以上为个人在工作中对git用法的一些理解,仅供参考】