Git工作流
我们在工作中经常用到git来管理自己的代码,也会涉及到多人协作的场景, 被广泛使用的三种工作流如下:
- Git flow
- Github flow
- Gitlab flow
Git flow
典型的长期维护master分支和develop分支,因为是FDD(功能驱动开发),所以会在协作开发中衍生出 功能分支(feature branch)、补丁分支(hotfix branch)、预发版分支(release branch),完成之后会合并到develop或者master分支,之后删除。优点是清晰可控,但这个模式是基于“版本发布”的,目标是一段时间产出一个新版本,不适合“持续发布”的网站开发。
Github flow
只有一个master长期分支,需要协同的人可以fork代码(其实就是新建了一个自己的分支,并且pull到了master上的代码),当你的功能需求代码完成之后,或者需要讨论的时候,就向master发起一个pull request。通知到别人评审、讨论、review你的代码,方便的是,在request提交之后评审的过程中,你还可以提交代码。等到你的request被accept,分支会合并到master,重新部署后,你原来的那个分支就可以删除啦。缺点是有时你的产品发布的代码版本和你master最新的版本并不是一个(比如因为苹果审核需要时间,那么你的代码就需要另一个分支来保留线上版本)。
Gitlab flow
引入了“上游优先”(upsteam first)的原则。只存在一个主分支master,它是所有其他分支的”上游”。只有上游分支采纳的代码变化,才能应用到其他分支。版本发布”的项目,建议的做法是每一个稳定版本,都要从master分支拉出一个分支。使用gitlab建立group project,可以将成员全部添加进小组中,每个人的提交都以分支合并进master分支的方式进行,我们可以将master设置成protected branch,这样就做到了强制代码review的机制,利于提升代码的质量。Issue 用于 Bug追踪和需求管理。建议先新建 Issue,再新建对应的功能分支。
Git命令小结
使用git help和git config
git config --help
使用这个命令可以列出 git config 的帮助列表。git config --list
则可以显示你目前的 git config 配置。
git config 文件有三层。
第一层config是在系统层etc/gitconfig, 可以通过使用 git config –system来进行配置,此层gitcofnig 配置针对系统所有用户的分支都有效。
第二层是~/.gitconfig,针对某个用户有效,针对此层设置使用的是git config –global命令。
第三层是项目文件夹中的配置文件,比如说我有一个 project1的文件夹,project1/.git/config就是在这个 repo 中使用的 gitconfig 配置。直接使用git config 就能进行配置。
具体配置:
设置用户名git config [--global] user.name <name>
设置邮箱git config [--global] user.email <email>
设置编辑器git config [--global] core.editor <editor>
设置github帐号名git config [--global] github.user <user>
设置github的tokengit config [--global] github.token <token>
–global是对当前系统用户的全局设置,在~/.gitconfig中。对系统所有用户进行配置,/etc/gitconfig。对当前项目,.git/config
git init和git remote
这种方式稍微复杂一些,当你本地创建了一个工作目录,你可以进入这个目录,使用git init
命令进行初始化,Git以后就会对该目录下的文件进行版本控制,这时候如果你需要将它放到远程服务器上,可以在远程服务器上创建一个目录,并把 可访问的URL记录下来,此时你就可以利用git remote add
命令来增加一个远程服务器端,例如git remote add origin git://github.com/someone/anotherproject.git
这条命令就会增加URL地址为git://github.com/someone/anotherproject.git
,名称为origin的远程服务器,以后提交代码的时候只需要使用 origin别名即可
现在我们有了本地和远程的版本库,让我们来试着用用Git的基本命令吧:
git rm
从当前的工作空间中和索引中删除文件,例如git rm app/model/user.rb
删除已经add的文件但不删除本地文件的方法:
单个文件:git rm --cached mylogfile.log
单个文件夹:git rm --cached -r mydirectory
git commit
不设定全局用户名的提交方法:git -c user.name= 'username' -c user.email='email' commit -m 'comment'
git push
将本地commit的代码更新到远程版本库中,例如’git push origin’就会将本地的代码更新到名为orgin的远程版本库中
git revert
还原一个版本的修改,必须提供一个具体的Git版本号,例如git revert bbaf6fb5060b4875b18ff9ff637ce118256d6f20
,Git的版本号都是生成的一个哈希值
上面的命令几乎都是每个版本控制工具所公有的,下面就开始尝试一下Git独有的一些命令:
git branch
对分支的增、删、查等操作,例如git branch newbranch
会从当前的工作版本创建一个叫做newbranch的新分支,git branch -D newbranch
就会强制删除叫做newbranch的分支,’git branch’就会列出本地所有的分支
git checkout
Git的checkout有两个作用,其一是在不同的branch之间进行切换,例如git checkout -b newbranch
就会新建并切换到newbranch的分支上去;git checkout -b newbranch origin/branch
,使用origin/branch并checkout到newbranch的本地分支上去,另外一种比较短的写法是:git checkout -t origin/branch
。另一个功能是还原代码的作用,例如git checkout app/model/user.rb
就会将user.rb文件从上一个已提交的版本中更新回来,未提交的内容全部会回滚
git rebase
用下面两幅图解释会比较清楚一些,rebase命令执行后,实际上是将分支点从C移到了G,这样分支也就具有了从C到G的功能
git reset
将当前的工作目录完全回滚到指定的版本号,假设如下图,我们有A-G五次提交的版本,其中C的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20,我们执行了git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20
那么结果就只剩下了A-C三个提交的版本
git stash
将当前未提交的工作存入Git工作栈中,时机成熟的时候再应用回来。如果当前的分支做了修改并且没有commith或stash,那么就无法切换分支,此时就需要使用该命令了
git config
利用这个命令可以新增、更改Git的各种设置,例如git config branch.master.remote origin
就将master的远程版本库设置为别名叫做origin版本库,后面在技巧篇会利用这个命令个性化设置你的Git,为你打造独一无二的 Git
git tag
可以将某个具体的版本打上一个标签,这样你就不需要记忆复杂的版本号哈希值了,例如你可以使用git tag revertversion bbaf6fb5060b4875b18ff9ff637ce118256d6f20
来标记这个被你还原的版本,那么以后你想查看该版本时,就可以使用 revertversion标签名,而不是哈希值了
git blame
如果你想要看看某一个文件的相关历史记录,可以使用git blame 命令。git blame index.html --date short
查看与分支
git branch
列出本地所有分支git branch -r
列出远程所有分支,并且说明当前分支与远程分支的关系。如果没用,用下面这句git ls-remote --heads <remote-name>
回退与更新
假如你想要丢弃你所有的本地改动与提交,可以到服务器上获取最新的版本并将你本地主分支指向到它:git fetch origin
git reset --hard origin/master
合并与更新
要更新你的本地仓库至最新改动,执行:git pull
以在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。
要合并其他分支到你的当前分支(例如 master),执行:git merge <branch>
两种情况下,git 都会尝试去自动合并改动。不幸的是,自动合并并非次次都能成功,并可能导致 冲突(conflicts)。 这时候就需要你修改这些文件来人肉合并这些 冲突(conflicts) 了。改完之后,你需要执行如下命令以将它们标记为合并成功:git add <filename>
在合并改动之前,也可以使用如下命令查看:git diff <source_branch> <target_branch>
关于合并代码
前面那些行显示出git fetch
命令会将哪些文件下载到本地,这些文件一旦下载到本地之后,就可以在本地进行任意操作了。
git fetch
命令执行完毕之后,还不会立即将下载的文件合并到你当前工作目录里,这就给你了一个选择下一步操作的机会,要是想将从远程分支下载的文件更新到你的工作目录里,你需要执行一个“合并(merge)”操作。例如,我当前的本地分支为”master“(执行git checkout master后),这时我想执行合并操作:
git merge origin/master
( 几句题外话:合并的时候有可能你还没有对远程分支提交过任何的更改,或者可能是一个复杂的合并。)
虽然 git pull 大部分时候是好的,特别是如果你用CVS类型的方式使用Git时,它可能正适合你。然而,如果你想用一个更地道的方式(建立很多主题分支,当你需要时随时改写本地历史,等等)使用Git,那么习惯把 git fetch 和 git merge 分开做会有很大帮助。
git merge
和git rebase
的区别
处理冲突的方式:
(一股脑)使用merge命令合并分支,解决完冲突,执行git add .
和git commit -m'fix conflict'
。这个时候会产生一个commit。
(交互式)使用rebase命令合并分支,解决完冲突,执行git add .
和git rebase --continue
,不会产生额外的commit。这样的好处是,‘干净’,分支上不会有无意义的解决分支的commit;坏处,如果合并的分支中存在多个commit,需要重复处理多次冲突。git pull
和git pull --rebase
区别:git pull做了两个操作分别是‘获取’和合并。所以加了rebase就是以rebase的方式进行合并分支,默认为merge。
Git的cherry-pick
在本地 master 分支上做了一个commit ( 38361a68138140827b31b72f8bbfd88b3705d77a ) , 如何把它放到 本地 old_cc 分支上?
办法之一: 使用 cherry-pick. 根据git 文档:Apply the changes introduced by some existing commits
就是对已经存在的commit 进行apply (可以理解为再次提交)
简单用法:git cherry-pick <commit id>
例如:$ git checkout old_cc
$ git cherry-pick 38361a68
- 如果顺利,就会正常提交。结果:
Finished one cherry-pick.# On branch old_cc
# Your branch is ahead of 'origin/old_cc' by 3 commits.
Git代码统计
查看git上个人代码量git log --author="username" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }'
统计每个人的增删行数git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done
提交数统计:git log --oneline | wc -l
参考用的Blog及资料
https://blog.csdn.net/ithomer/article/details/7527877 版本管理工具对比svn,git,cvs
http://hufeng825.github.io/categories/git/
https://learngitbranching.js.org/ 很赞的小游戏,通关即学会
http://www.infoq.com/cn/profile/%E5%88%98%E8%BE%89 git历险记
http://git.oschina.net/progit/index.html pro git 中文版
https://git-scm.com/ 官网