Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!
分布式管理控制和集中式管理控制的区别
基本操作
创建一个空目录mkdir youdir
初始化一个git仓库
git init //得到.git的隐藏文件
提交文件到本地仓库
git add filename1
git add filename2
git commot -m "说明文字"
查看本地仓库和服务器仓库的文件同步状态git status
列出本地仓库和服务器仓库的不同文件内容git diff
按照时间逆序顺序列出提交版本信息,打印commit: git log --prety=oneline
版本回溯,HEAD代表当前版本: git reset --hard HEAD~1 2 3
HEAD^和HEAD~1表示上一个版本
HEAD^^和HEAD~2表示上两个版本,以此类推
或者通过commit id回溯,git reset --hard commitId
机制: 内部有一个指向HEAD的指针,改变指针指向版本
git reflog
记录所有的命令
可以获取到原来提交的版本commitId
工作区和版本区
工作区可以看做是你本地的文件目录
.git文件是版本区,.git/index是暂缓区,HEAD是指针,config是配置
git add
把文件提交到暂缓区,并且保持更改
git commit
把暂缓区的文件提交到master
git checkout -- filename
丢弃工作区中的内容
git reset HEAD filename
把暂缓区的reset掉,重新放回工作区
删除文件
本地删除 rm
版本删除 git rm 提交git commit -m "string"
删错了,且版本里面还有 git checkout -- file
GitHub的远程仓库
本地账号ssh产生公钥id_rsa和私钥id_rsa_pub
ssh-keygen -t rsa -C "youremail@example.com"
绑定github账号,在github账号的setting里面设置key
本地库连接远程仓库
git remote add origin git@github.com:liuhangng/learngit.git
git remote add origin https://github.com/liuhangng/learngit.git
前者是SSH方式,后者是HTTPS方式
SSH更快,且不用每次都输入口令
第一次本地连接GitHub, 需要验证对方发送过来的Key是否来自GitHub
git push -u origin master
把本地当前master内容上传到remote origin(代替了原来的ssh或者https链接)
-u命令可以把本地master和远程master关联起来,下次push操作就不需要-u
从GitHub直接clone整个reposity
这个问题的原因是CAFILE的路劲不正确
$ git config --system http.sslCAInfo "D:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt"
重修修改config配置
版本分支
在当前master的基础上创建一个分支版本,命名,切换到它
git checkout -b dev
-b的指令在这里相当于执行了两次,创建,和切换,可以等效于如下代码
git branch dev
git checkout dev
效果如图
尾后蓝色带括号的字表示当前所在分支
合并分支
git merge dev
效果如图
fast-forward表示快进模式,没有冲突,把dev分支的内容全部做add操作
接下来就是删除分支
git branch -d dev
存在冲突
主线master和支线feature各自做了不同的change
无法自动合并,需要手动解决冲突然后再提交结果
且这个时候进入合并模式
蓝色括号里面的表示状态 master|MERGING
在这个状态
git status
查看不同文件的地方
git diff
查看区别
vim filename
直接编辑所要合并的文件(master上面的)
git commit
最后再次提交,系统会显示 conflict fixed
git log --graph //可以查看合并分支图
最后后面的参数
--pretty=oneline
只显示一行
--abbrev-commit
只显示提交的注释
分支策略管理
实际工程中我们的版本分支情况往往是这样的
master的主线只有版本发布的时候才会更新,平时工程中,只需要修改各个dev版本
XX公司的R7R8就是master版本,每接一个项目,所谓的拉一个分支,就是创建一个dev, 然后一个团队的人就是修改这个dev并最后发布,每当master版本核心模块更新的时候,dev版本就需要有策略的merge
保留分支信息的merge
$ git merge --no-ff -m "merge with no-ff" dev
修复BUG分支
场景:正在分支dev coding但是接到其它分支比如master的bug 101问题单,不能提交dev也不能放弃dev
第一步,保存dev现场
git stash
第二步,创建masterf bug分支
git checkout master
git checkout -b issue-101
第三步,在bug分支修改代码,并提交
git add file
git commit -m "fix issue-101"
第四步,master分支合并bug分支,并删除bug分支
git checkout master
git merge --no-ff -m "fix bug issue1-101" issue-101
git branch -d issue-101
第五步,查看现场并恢复
git checkout dev
git stash list
git stash apply stash{0} //不删除stash保存的
git stash pop //删除这个stash
多人协作,推送服务器
最初远程连接GitHub服务器的时候,有一个名字origin指代,本地仓库master已经修改完成
接下来
git remote -v //可以查看远程仓库
fetch和pull的区别在于pull下载后做merge处理
git checkout -b newA fromB //fromB可以是本地的也可以是远程的比如 origin/dev
git push/pull/fetch toA fromB
场景 多人远程协作
第一步:在GitHub master建立分支
第二步:client做remote连接
在这个过程中,有两种可能
- git checkout -b newA可能这个是本地master的分支,而不是远程,后面需要
gitgit branch --set-upstream-to=origin/dev 把当前本地的这个分支重新指向远程dev分支,然后做pull操作,把远程分支的内容download
- git checkout -b newA origin/dev 直接根据远程分支创建本地分支
标签
解决commit的一堆混乱的数字问题
git tag -a v0.1 -m "version 0.1 released" 3628164
//-a 表示标签名
//-m 表示标签说明
//后面带的数字表示commit,省略表示当前版本
查看标签git tag <name>
删除标签git tag -d name
推送标签 git push toA tagname
推送本地所有未推送的标签git push toA --tags
\
删除远程标签git push origin :refs/tags/<tagname>
自定义Git配置
git config color.ui true //两次tab自动补全可以查看修改属性项
隐藏文件夹.git里面,有一个config配置文件,其内容:
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
[remote “origin”]
url = https://github.com/liuhangng/FirstReposity.git
fetch = +refs/heads/:refs/remotes/origin/
fetch = +refs/heads/devv:refs/remotes/origin/devv
[branch “master”]
remote = origin
merge = refs/heads/master
[branch “dev”]
remote = origin
merge = refs/heads/dev
合并忽略特殊文件
git工作区建立隐藏文件.gitignore,忽略中间文件
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini# Python:
*.py[cod] //使用通配符
*.so
*.egg
*.egg-info
dist
build# My configurations:
db.ini
deploy_key_rsa
如果gitignore规则生效,当时仍然想要提交某个文件采用强制性
git add -f filename
查看gitignore哪一行规则生效
git check-ignore -v filename
配置别名
git config --global alias.xx command //用xx代替原来的command
git config --global alias.last 'log -1' //git last查看最近一次提交
在config文件末尾添加
[alias]
last = log -1
个人实际情景
可以把github看做是一个代码文件服务器
优点
- 代码同步,不管走到哪里,只需要三步pull-write-push
- 享受github的开源
- 工程思维,project完成后,就做push处理,最后代码全部“云”化
缺点
- 每次都需要各种操作,麻烦
- 编程环境更喜欢windows,习惯VS,这种偏linux风格相关性并没有太强
- Git更适合团队,对于个人来讲,优点并没有那么明显
GitHub for Windows
windows平台的客户端
主要是两种使用情形:
第一种,个人本地工程
- 第一步:GitHubForWin建立本地仓库
- 第二步:在这个仓库中,建立项目工程,比如VS
- 第三步:项目代码编写,调试,运行成功
- 第四步:在本地仓库中,根据项目类型,编写gitignore,比如cpp里面忽略调试debug等文件
- 第五步:GitHubForWin中,把本地工程提交到版本支线,个人直接master,需要commit
- 第六步:本地仓库publish到GitHub服务器,建立对应的仓库
- 第七步:sync, 同步
- 最后:以后打开VS和GitHubForWin, VS代码修改并sava的时候,在GitHubForWin中,可以看到那些文件做了修改,提交的时候,解决冲突问题,最后sync merge
第二种,使用他人支线
- 如果没有权限,可以把他人的全部clone,然后建立自己服务端的主线
- 或者直接在本地仓库建立他们版本的支线,并在本地修改,最后做pull request操作
- 如果是团队合作,那么一般会操作权限,根据情况建立团队支线,并将自己的模块pull和push