前言
What is Git?
Git是目前世界上最先进的分布式版本控制系统(没有之一), 而且是一款免费、开源的分布式版本控制系统, 用于敏捷高效地处理任何或小或大的项目
一直以来, 博主开发项目用的版本管理系用都是SVN[1], 其实早就听闻过Git, 一直没用过, 后来接触Github和Hexo博客框架, 才真正意义上开始接触Git, 感受就是高端大气上档次!
简介
Git是Linux系统的开发者Linus在2005年的时候, BitKeeper[2]的东家BitMover公司回收了Linux社区的免费使用权的情况下, 在仅仅的两周内Linus用C写出了一个分布式版本控制系统, 这就是Git(超级牛X)!从此, Linux系统的源码已经由Git管理了. 逐渐地, Git迅速成为最流行的分布式版本控制系统, 尤其是在Github上线之后, 无数开源项目开始迁移至GitHub, 包括jQuery, PHP, Ruby等等
Git安装
在Debian或者Ubuntu Linux下的Git安装非常简单, 直接一条命令搞定1
sudo apt-get install git
Windows下的模拟环境安装起来比较复杂, 那么可以用牛人封装好的模拟环境加Git, 叫msysgit, 只需要下载一个exe然后双击安装
可从https://git-for-windows.github.io/ 下载, 或者从廖雪峰老师的镜像 下载, 然后按默认选项安装
安装完成后, 在开始菜单里找到“Git”->“Git Bash”, 蹦出一个类似命令行窗口的东西, 就说明Git安装成功
成功安装之后, 还需要配置一下全局个人信息:1
2git config --global user.name "Your Name"
git config --global user.email "email@example.com"
每次提交, 都会记录这两个值, --global
参数, 表示你这台机器上所有的Git仓库都会使用这个配置
可使用 git config -l
查看全局配置信息
运行前配置
一般在新的系统上, 我们都需要先配置下自己的 Git 工作环境. 配置工作只需一次, 以后升级时还会沿用现在的配置.
配置文件如何生效
对于 Git 来说, 配置文件的权重是仓库>全局>系统. Git 会使用这一系列的配置文件来存储你定义的偏好, 它首先会查找 /etc/gitconfig
文件(系统级), 该文件含有对系统上所有用户及他们所拥有的仓库都生效的配置值. 接下来 Git 会查找每个用户的 ~/.gitconfig
文件(全局级). 最后 Git 会查找由用户定义的各个库中Git目录下的配置文件 .git/config
(仓库级), 该文件中的值只对当前所属仓库有效. 以上阐述的三 层配置从一般到特殊层层推进, 如果定义的值有冲突, 以后面层中定义的为准, 例如: .git/config
和 /etc/gitconfig
的较量中, .git/config
取得了胜利.
查看配置
格式: git config [--local|--global|--system] -l
example:
1 | # 查看当前生效的配置 |
修改配置
格式: git config [--local|--global|--system] key value
example:
1 | git config --global user.name ybd |
创建仓库(Repository)
创建一个目录并进入, 进行初始化仓库1
2
3mkdir repo
cd repo
git init
目录下会多一个 .git
的隐藏文件, 现在要创建一个文件并提交到仓库1
2
3
4
5
6
7touch read
vi read
# 按a进入编辑
# 输入Git is a distributed version control system
# 按下Esc, 并输入 ":wq" 保存退出
git add README.md #添加文件到缓存区
git commit -m "first commit" #将缓存区的文件提交到本地仓库
多个文件提交可用 git add -A
然后再 commit1
2
3
4➜ repo git:(master) ✗ git commit -m "first commit"
[master (根提交) 20717f5] first commit
1 file changed, 2 insertions(+)
create mode 100644 read
操作的自由穿越
要随时掌握工作区的状态: git status
查看修改内容: git diff read
查看版本历史信息 got log
或 git log --pretty=oneline
版本穿越
退到上一个版本:1
git reset --hard HEAD^
上上一个版本就是 HEAD^^
, 当然往上100个版本写100个^比较容易数不过来, 所以写成 HEAD~100
要重返未来, 查看命令历史: git reflog
修改管理
添加文件到缓存区: git add read
或 git add -A
然后提交: git commit -m "msg"
查看状态: git status
每次修改, 如果不add到暂存区, 那就不会加入到commit中
撤销修改
当你发现工作区的修改有错误的时候, 可丢弃工作区的修改:1
git checkout -- read
命令 git checkout -- read
意思就是, 把 read
文件在工作区的修改全部撤销, 这里有两种情况:
一种是 read
自修改后还没有被放到暂存区, 现在, 撤销修改就回到和版本库一模一样的状态
一种是 read
已经添加到暂存区后, 又作了修改, 现在, 撤销修改就回到添加到暂存区后的状态
总之, 就是让这个文件回到最近一次 git commit
或 git add
时的状态
注意! git checkout -- file
命令中的 --
很重要, 没有 --
就变成了切换分支了
当你发现该文件修改错误并且已经提交到了缓存区, 这个时候可以把暂存区的修改撤销掉(unstage), 重新放回工作区:1
git reset HEAD read
然后再丢弃工作区中的修改:1
git checkout -- read
git reset
命令既可以回退版本, 也可以把暂存区的修改回退到工作区. 当我们用HEAD时, 表示最新的版本
删除文件
如果把工作区中的文件删除了, 那么工作区和版本库就不一致, git status
命令会立刻告诉你哪些文件被删除了
现在有两个选择
一是确实要从版本库中删除该文件, 那就用命令删掉, 并且提交:
1
2git rm read
git commit -m "delete"另一种情况是删错了, 因为版本库里还有呢, 所以可以很轻松地把误删的文件恢复到最新版本:
1
git checkout -- read
git checkout
其实是用版本库里的版本替换工作区的版本, 无论工作区是修改还是删除, 都可以“一键还原”
远程仓库
那么学会了Git的基本操作之后, 对于分布式管理我们还需要有一个远程仓库供大家一起共同开发, 好在有一个全世界最大最神奇的同性交友网—— Github
那么在使用Github之前呢, 我们需要设置一下与Github的SSH通讯:
1. 创建SSH Key(已有.ssh目录的可以略过)1
ssh-keygen -t rsa -C "youremail@example.com"
你需要把邮件地址换成你自己的邮件地址, 然后一路回车, 使用默认值即可, 由于这个Key也不是用于军事目的, 所以也无需设置密码
如果一切顺利的话, 可以在用户主目录里找到 .ssh
目录, 里面有 id_rsa
和 id_rsa.pub
两个文件, 这两个就是SSH Key的秘钥对, id_rsa
是私钥, 不能泄露出去, id_rsa.pub
是公钥, 可以放心地告诉任何人
2. 登陆GitHub, 打开“Account settings”, “SSH Keys”页面, 然后, 点“Add SSH Key”, 填上任意Title, 在Key文本框里粘贴id_rsa.pub
文件的内容, 最后点“Add Key”
添加远程仓库
首先到Github创建一个仓库
然后与本地关联:1
git remote add origin git@github.com:your-name/repo-name.git
远程库的名字就是origin
, 这是Git默认的叫法, 也可以改成别的, 但是origin
这个名字一看就知道是远程库
下一步, 就可以把本地库的所有内容推送到远程库上:1
git push -u origin master
把本地库的内容推送到远程, 用 git push
命令, 实际上是把当前分支 master
推送到远程
由于远程库是空的, 我们第一次推送 master
分支时, 加上了 -u
参数, Git不但会把本地的 master
分支内容推送的远程新的 master
分支, 还会把本地的 master
分支和远程的 master
分支关联起来, 在以后的推送或者拉取时就可以简化命令
此后的推送都可以使用:1
git push
从远程仓库克隆
1 | git git@github.com:your-name/repo-name.git |
标签管理
查看tag
列出所有tag:1
git tag
这样列出的tag是按字母排序的, 和创建时间没关系. 如果只是想查看某些tag的话, 可以加限定:1
git tag -l v1.*
这样就只会列出1.几的版本.
创建tag
创建轻量级tag
:1
git tag 1.0.1
这样创建的tag
没有附带其他信息, 与之相应的是带信息的tag
,-m
后面带的就是注释信息, 这样在日后查看的时候会很有用, 这种是普通tag
, 还有一种有签名的tag
:1
git tag -a 1.0.1 -m 'first version'
除了可以为当前的进度添加tag
, 我们还可以为以前的commit
添加tag
:
首先查看以前的commit
1
git log --oneline
假如有这样一个commit
: 8a5cbc2 updated readme
这样为他添加tag
1
git tag -a v1.1 8a5cbc2
删除tag
很简单, 知道tag
名称后:1
git tag -d v1.0
删除远程分支:1
git push origin --delete tag <tagname>
共享tag
我们在执行git push
的时候, tag
是不会上传到服务器的, 比如现在的github
, 创建tag
后git push
, 在github
网页上是看不到tag
的, 为了共享这些tag
, 你必须这样:1
git push origin --tags
分支管理
分支相当与平行宇宙, 互不干扰, 哪天合并了就拥有了所有平行宇宙的特性
创建与合并分支
- 每次提交, Git都把它们串成一条时间线, 这条时间线就是一个分支. 截止到目前, 只有一条时间线, 在Git里, 这个分支叫主分支, 即
master
分支 - 一开始的时候,
master
分支是一条线, Git用master
指向最新的提交, 再用HEAD
指向master
, 就能确定当前分支, 以及当前分支的提交点 - 当我们创建新的分支, 例如
dev
时, Git新建了一个指针叫dev
, 指向master
相同的提交, 再把HEAD
指向dev
, 就表示当前分支在dev
上 - Git创建一个分支很快, 因为除了增加一个
dev
指针, 改改HEAD
的指向, 工作区的文件都没有任何变化 - 当
HEAD
指向dev
, 对工作区的修改和提交就是针对dev
分支了, 比如新提交一次后,dev
指针往前移动一步, 而master
指针不变
查看分支: git branch
创建分支: git branch <name>
切换分支: git checkout <name>
创建+切换分支: git checkout -b <name>
合并某分支到当前分支: git merge <name>
删除分支: git branch -d <name>
解决冲突
合并分支并不是每次都不会出问题, 如不同的分支对同一个文件同一行都被修改过, 就会出现以下情况
那么再次合并有可能会冲突1
2
3
4
5
6
7
8
9
10
11
12
13
14
15➜ repo git:(master) git merge feature1
自动合并 read
冲突(内容): 合并冲突于 read
自动合并失败, 修正冲突然后提交修正的结果.
➜ repo git:(master) ✗ git status
位于分支 master
您有尚未合并的路径.
(解决冲突并运行 "git commit")
未合并的路径:
(使用 "git add <文件>..." 标记解决方案)
双方修改: read
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
这种情况必须手动解决然后再次 git add .
, git commit -m "commit"
, 打开文件可看到1
2
3
4
5
6Git is a version control
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
Git用<<<<<<<
, =======
, >>>>>>>
标记出不同分支的内容, 那么经过合意, 不好意思, 大师兄说了, 在座的各位都是垃圾, 于是改成1
Git,too fast too simple
再提交1
2
3
4➜ repo git:(master) ✗ git add read
➜ repo git:(master) ✗ git commit -m "conflict fixed"
[master 8933f88] conflict fixed
➜ repo git:(master)
ok了, 再次 add
和 commit
, 现在 master
分支和feature1
分支变成了这样
多PC协同开发
当你从远程仓库克隆时, 实际上Git自动把本地的 master
分支和远程的 master
分支对应起来了, 并且, 远程仓库的默认名称是 origin
查看远程库的信息:
查看简单信息: git remote
查看详细信息: git remote -v
查看远程仓库分支: git branch -r
查看本地分支与远程分支的对应关系: git branch -vv
推送分支1
2
3git push origin <branch>
git push -u origin <branch> # 第一次推送加-u可以把当前分支与远程分支关联起来
克隆分支并关联1
2
3
4git clone git@github.com:youName/program.git # 默认克隆master分支到当前目录(包含分支文件目录)
git clone -b <branch> git@github.com:youName/program.git ./
# 克隆指定分支到指定文件目录下(不包含分支文件目录)
创建远程 origin
的 dev
分支到本地1
git checkout -b <branch> origin/<branch>
关联本地分支与远程仓库分支1
git branch --set-upstream <branch> origin/<branch>
Commit 带上 emoji 表情
执行
git commit
时使用 emoji 为本次提交打上一个 “标签”, 使得此次 commit 的主要工作得以凸现, 也能够使得其在整个提交历史中易于区分与查找.
只需要加上 emoji 标签即可:
1 | git commit -m ":tada: Initialize Repo" |
常用的标签:
emoji | emoji 代码 | commit 说明 |
---|---|---|
:art: (调色板) | :art: |
改进代码结构/代码格式 |
:zap: (闪电):racehorse: (赛马) | :zap:“:racehorse: |
提升性能 |
:fire: (火焰) | :fire: |
移除代码或文件 |
:bug: (bug) | :bug: |
修复 bug |
:ambulance: (急救车) | :ambulance: |
重要补丁 |
:sparkles: (火花) | :sparkles: |
引入新功能 |
:memo: (备忘录) | :memo: |
撰写文档 |
:rocket: (火箭) | :rocket: |
部署功能 |
:lipstick: (口红) | :lipstick: |
更新 UI 和样式文件 |
:tada: (庆祝) | :tada: |
初次提交 |
:white_check_mark: (白色复选框) | :white_check_mark: |
增加测试 |
:lock: (锁) | :lock: |
修复安全问题 |
:apple: (苹果) | :apple: |
修复 macOS 下的问题 |
:penguin: (企鹅) | :penguin: |
修复 Linux 下的问题 |
:checkered_flag: (旗帜) | :checked_flag: |
修复 Windows 下的问题 |
:bookmark: (书签) | :bookmark: |
发行/版本标签 |
:rotating_light: (警车灯) | :rotating_light: |
移除 linter 警告 |
:construction: (施工) | :construction: |
工作进行中 |
:green_heart: (绿心) | :green_heart: |
修复 CI 构建问题 |
:arrow_down: (下降箭头) | :arrow_down: |
降级依赖 |
:arrow_up: (上升箭头) | :arrow_up: |
升级依赖 |
:construction_worker: (工人) | :construction_worker: |
添加 CI 构建系统 |
:chart_with_upwards_trend: (上升趋势图) | :chart_with_upwards_trend: |
添加分析或跟踪代码 |
:hammer: (锤子) | :hammer: |
重大重构 |
:heavy_minus_sign: (减号) | :heavy_minus_sign: |
减少一个依赖 |
:whale: (鲸鱼) | :whale: |
Docker 相关工作 |
:heavy_plus_sign: (加号) | :heavy_plug_sign: |
增加一个依赖 |
:wrench: (扳手) | :wrench: |
修改配置文件 |
:globe_with_meridians: (地球) | :globe_with_meridians: |
国际化与本地化 |
:pencil2: (铅笔) | :pencil2: |
修复 typo |
更多标签参考:
https://gitmoji.carloscuesta.me/
https://www.webfx.com/tools/emoji-cheat-sheet/
美化你的 README
https://github.com/kefranabg/readme-md-generator
https://github.com/anuraghazra/github-readme-stats
同步更新Github Fork的项目
1、fork
项目并clone
到本地
2、进入项目根目录
3、添加remote
指向上游仓库
1 | git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git |
4、把上游项目fetch
下来
1 | git fetch upstream |
5、merge
到master
1 | git checkout master |
6、push
到自己的远程仓库, 搞定~
附录
Git pull 时每次都要输入用户名和密码的解决办法
如果我们git clone的下载代码的时候是连接的https://而不是git@git (ssh)的形式,当我们操作git pull/push到远程的时候,总是提示我们输入账号和密码才能操作成功,频繁的输入账号和密码会很麻烦。
git bash
进入你的项目目录,输入:
1 | git config --global credential.helper store |
然后你会在你本地生成一个文本,上边记录你的账号和密码。当然这些你可以不用关心。然后你使用上述的命令配置好之后,再操作一次git pull,然后它会提示你输入账号密码,这一次之后就不需要再次输入密码了。
Git 多平台统一换行符
设置 git 全局参数
git 中有三个参数于换行符有关:
eol
: 设置工作目录中文件的换行符, 有三个值 lf, crlf 和 native(默认, 同操作系统)autocrlf
:true
表示检出是转换CRLF, 提交时转换为 LFinput
表示检出是不转换, 提交时转换为 LFfalse
表示不做转换
safecrlf
:true
表示不允许提交时包含不同换行符warn
则只在有不同换行符时警告false
则允许提价时有不同换行符存在
配置方法:
1 | <!--统一换行符为 lf--> |
增加配置文件 .gitattributes
虽然通过设置了 git 全局参数解决了问题, 但是作为团队协作的话, 并不能保证所有人都正确配好了. git 提供了 .gitattributes
文件解决了这个问题, 在项目根目录新建 .gitattributes
文件, 添加一下内容:
1 | # Set the default behavior, in case people don't have core.autocrlf set. |
通过这种方式避免有人没有设置 core.autocrlf
参数, 并且将该文件加入版本控制中.
另外根据需要 .gitattributes
文件可以在项目不同目录中创建, 而一些非文本文件可以设置为二进制文件, 不用考虑换行符问题.
最后
Git真的异常强大, 但命令繁多, 需多加练习
参考: 廖雪峰老师的教程
附命令图一张: