git 版本控制系统
为什么要有版本控制系统
在开发过程中,经常需要对一个文件进行修改甚至删除,但是我们又希望能够保存这个文件的历史记录,如果通过备份,那么管理起来会非常的复杂
什么是版本控制系统
版本控制系统(Version Control System):是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
版本控制系统不仅可以应用于软件源代码的文本文件,而且可以对任何类型的文件进行版本控制。
版本控制系统的分类
参考文章:关于版本控制的介绍
本地版本控制系统
本地版本控制系统就是在一台机器上,记录版本的不同变化,保证内容不会丢失
- 如果多人开发,每个人都在不同的系统和电脑上开发,没办法协同工作。
集中式版本控制系統
svn
是集中式的版本控制系统,集中式版本控制系统都有一个单一的集中管理的服务器(中央服务器),保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
- 需要一个中央服务器来管理代码的的版本和备份
- 所有的用户电脑都是从中央服务器获取代码或者是将本地的代码提交到中央服务器
- 依赖与网络环境,如果连不上中央服务器,就无法提交和获取代码。
分布式版本控制系统
git
是分布式的版本控制系统。分布式版本控制系统的客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份
- 需要一台服务器作为代码仓库
- 每个用户电脑都是一个服务器(代码仓库),并且和代码仓库是镜像的,用户修改和获取代码都是提交到自己的服务器当中。
- 不需要网络就可以进行工作。
- 当连接网络时,用户可以选择将自己的服务器与代码仓库进行同步。
Git
git 官方中文文档
Git 核心概念
**
WorkSpace
**:
工作区,即从仓库中 checkout 出来的,需要通过 Git 进行版本控制的目录和文件,可以简单的理解为在电脑里真实看到的文件**
Stage(Index)
**:
暂存区,或者叫做待提交更新区;在提交进入 Repository 之前,可以把所有的更新放在暂存区, 用git add
的文件都在这里**
Repository(Remote/Local)
**:
仓库,一个存放在远端/本地的版本库,用git commit
提交的文件就到 Local Repository,用git push
提交的文件就到 Remote Repository**
.git
**:存放 Git 管理信息的目录,初始化仓库的时候会自动创建
Git 初始设置
设置用户名和邮箱
# 用户名使用英文 |
全局设置会在 ~/.gitconfig
中以如下形式输出设置文件,可以直接编辑这个文件来修改设置
[user] |
每个仓库的 Git 配置文件都放在 .git/config
文件中,可以直接修改此文件$ cat .git/config
查看配置文件
# 解决中文变成数字加百分号,也可以在设置中将编码修改为 utf-8 |
设置 SSH Key
GitHub 上连接已有仓库时的认证,是通过使用了 SSH 的公开密钥认证方式进行的。现在我们来创建公开密钥认证所需的 SSH Key,并将其添加至 GitHub
运行下面的命令
ssh-keygen -t rsa -C "your_email@example.com" |
输入密码后会出现以下结果
Your identification has been saved in /Users/your_user_directory/.ssh/id_rsa. |
id_rsa
文件是私有密钥,id_rsa.pub
是公开密钥
添加公开密钥
在 GitHub 中添加公开密钥,今后就可以用私有密钥进行认证了
点击右上角的账户设定按钮(Account Settings),选择 SSH Keys 菜单。点击 AddSSH Key 之后,在 Title 中输入适当的密钥名称。Key 部分请粘贴 id_rsa.pub 文件里的内容
id_rsa.pub
的内容可以用如下方法查看
cat ~/.ssh/id_rsa.pub |
完成以上设置后,就可以用手中的私人密钥与 GitHub 进行认证和通信了
ssh -T git@github.com |
出现如下结果即为成功
Hi cuilongjin! You've successfully authenticated, but GitHub does not provide shell access. |
提高命令输出的可读性
将 color.ui
设置为 auto
可以让命令的输出拥有更高的可读性
git config --global color.ui true |
~/.gitconfig
中会增加下面一行
[color] |
这样一来,各种命令的输出就会变得更容易分辨。
文件名大小写问题
git 默认对文件名大小写不敏感
# 设置 git 大小写敏感 |
设置头像
通过 Gravatar 服务
配置别名
# 配置 st 别名表示 status |
搭建 Git 服务器
搭建 Git 服务器
配置多用户
根据不同邮箱生成对应的私钥公钥
ssh-keygen -t rsa -C email |
将公钥上传到对应的用户账号中
在 .ssh
目录创建 config
文件,配置私钥对应的服务器,每个账号单独配置一个 Host,每个 Host 要取一个别名,每个 Host 主要配置 HostName 和 IdentityFile 两个属性即可
# 配置用户1 |
Host 的名字可以任意,不过这个会影响 git 相关命令,例如:
Host mygithub 这样定义的话,命令如下
git clone git@mygithub:cuilongjin/cuilongjin.git
即 git@ 后面紧跟的名字改为 mygithub
执行 ssh -T git@github
、ssh -T git@gitlab
测试是否成功
配置局部 git 用户名和邮箱,如果没有局部配置,默认用全局配置
git config user.name "Your name" |
或者直接找到 .git/config
文件,添加
[user] |
Git 基本操作
git init
mkdir project |
如果初始化成功,执行了 git init
命令的目录下就会生成 .git
目录。这个 .git
目录里存储着管理当前目录内容所需的仓库数据
mkdir project
命令创建 project 空文件夹
pwd
命令用于显示当前目录
git add
# 将指定文件夹添加到暂存区(目录中的所有文件,包括新增/修改/删除的文件)--not-all 忽略删除的 |
git commit
# 将文件从暂存区提交到仓库 |
-m 参数后的 'First commit'
称作提交信息,是对这个提交的概述,如果想要记述得更加详细,请不加 -m
,直接执行 git commit
命令,执行后编辑器就会启动。
在编辑器中记述提交信息的格式如下:
第一行:用一行文字简述提交的更改内容
第二行:空行
第三行以后:记述更改的原因和详细内容
git status
# 建立 README.md 文件作为管理对象 |
git status
命令可以让我们时刻掌握仓库当前的状态,但不能看到具体修改了什么内容,需要用 git diff
这个命令来查看具体修改内容。
git diff
# 查看当前工作树和最新add之间(暂存区)的差别(difference) |
HEAD 是指向当前分支中最新一次提交的指针
git log
# 显示当前版本之前的提交信息 |
git reset
git reset -h '查看帮助' |
HEAD
表示当前版本,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上 100 个版本写 100 个^比较容易数不过来,所以写成HEAD~100
- 使用
commit_id
回退 ,git reflog
用来记录你的每一次命令和commit_id
git reset --soft HEAD^ |
git checkout –file
git checkout -- README.md |
把 README.md 文件在 工作区的修改全部撤销
,用版本库里的版本替换工作区的版本
这里有两种情况:
一种是 README.md 自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
一种是 README.md 已经添加到暂存区后,又作了修改,现在撤销修改就回到添加到暂存区后的状态
总之,就是让这个文件回到最近一次 git commit 或 git add 时的状态,可用于撤销文件修改或恢复误删文件
git remote
git remote add origin git@github.com:cuilongjin/git_test.git |
添加后,远程库的名字就是 origin,这是 Git 默认的叫法,也可以改成别的,但是 origin 这个名字一看就知道是远程库
# 查看远程库的信息 |
上面显示了可以抓取和推送的 origin 的地址。如果没有推送权限,就看不到 push 的地址
# 删除已有的 GitHub 远程库 |
git pull
# 获取远程仓库的更新,并且与本地的分支进行合并 |
git push
git push <远程仓库名> <本地分支名>:<远程分支名> |
remote: error: GH007: Your push would publish a private email address.
解决方法——http://github.com/settings/emails 把 Keep my email address private 这一项去掉勾选即可。
如果推送失败,则因为远程分支比你的本地更新,需要先用 git pull
拉取远程的新提交
git clone
git clone git@github.com:cuilongjin/仓库名.git [指定文件夹] |
Git 支持多种协议,包括 https,但通过 ssh 支持的原生 git 协议速度最快
从远程库 clone 时,默认情况下,只能看到本地的 master 分支
要在 dev 分支上开发,就必须创建远程 origin 的 dev 分支到本地,于是用这个命令创建本地 dev 分支
git checkout -b dev origin/dev |
克隆指定分支
# git clone -b|--branch 分支名或tag名 仓库地址 |
git fetch
# 将某个远程仓库的更新,全部取回本地。默认取回所有分支(branch)的更新 |
git fetch 和 git pull 区别
git pull 获取远程仓库的更新,并且与本地的分支进行合并
git fetch 所取回的更新,在本地主机上要用 “远程仓库/分支名” 的形式读取,即不会与本地分支合并
git 忽视文件
在仓库中,有些文件是不想被 git 管理的,比如数据的配置密码、写代码的一些思路等。git 可以通过配置从而达到忽视掉一些文件,这样这些文件就可以不用提交了
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如 Java 编译产生的 .class 文件
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件
在仓库的根目录创建一个 .gitignore
的文件,文件名是固定的
将不需要被 git 管理的文件路径添加到 .gitignore
中,把 .gitignore
也提交到 Git,Git 就会自动忽略这些文件
# 忽视 index.txt 文件 |
GitHub 已经为我们准备了各种配置文件 https://github.com/github/gitignore
强制添加被 .gitignore 忽略的文件
# 强制添加被.gitignore忽略的文件 |
git branch
在 git 中,分支实质上仅仅是一个指针,每次代码提交后,这个分支指针就会向后移动,保证一直指向最后一次提交的的版本。git 中使用 HEAD 指向当前分支
git branch |
*
(星号)表示当前所在的分支
- git checkout -b 创建、切换分支
# 以 branch 为基础创建名为 feature-A 的分支 |
连续执行下面两条命令也能收到同样效果
# 创建 feature-A 分支 |
- git branch -d 删除分支
# 删除本地 feature-A 分支 |
- git branch -m 重命名分支
# 重命名本地分支 |
git merge
合并分支
# 将 feature-A 合并到 master 上 |
git stash
# 把当前工作现场“储藏”起来 |
恢复工作现场
# 恢复工作现场,stash 内容并不删除 |
恢复指定的 stash,用命令:git stash apply stash@{0}
廖雪峰 Git 教程创建与合并分支
廖雪峰 Git 教程分支管理策略
廖雪峰 Git 教程 Bug 分支
git tag
- 创建标签
# 首先切换到需要打标签的分支上 |
- 查看标签
# 查看所有标签 |
- 推送标签到远程
# 推送 v1.0 标签到远程 |
- 删除标签
# 删除本地标签 v1.0 |
git 仓库分离
将一个 git 仓库里的一部分文件转出作为一个独立的仓库并保留提交记录 commit log
# 这就是那个大仓库 big-project |
快速克隆大项目
克隆单个分支
git clone --branch <branch_name> <remote-address> |
只克隆最新的提交记录
git clone <remote-address> --depth 1 |
– depth 代表克隆的深度,–depth 1 代表只克隆最新一次提交记录以及这次提交之后的最新内容,不克隆历史提交,所造成的影响就是不能查看历史提交记录
克隆单个分支的最新一次提交
git clone --branch <branch_name> <remote-address> --depth 1 |
git 修改提交历史
修改最后一条 commit
git commit --amend |
修改多条 commit
git rebase -i HEAD~3 修改最近三次提交 |
Commands
p, pick = use commit: 直接使用 commit 不做任何修改,其中 p 是 pick 的缩写,以下雷同
r, reword = use commit, but edit the commit message: 使用 commit,修改 commit 注释
e, edit = use commit, but stop for amending :使用 commit,但是遇到此命令时会停止合并,可以修改提交信息
s, squash = use commit, but meld into previous commit: 使用 commit,但是会合并到前一个 commit 中,默认保留所有的 commit 注释,并变为可以修改状态
f, fixup = like “squash”, but discard this commit’s log message:和 squash 类似,但是会抛弃 commit 的 log 信息
x, exec = run command (the rest of the line) using shell:使用 shell 运行命令
d, drop = remove commit:丢弃 commit,(并删除该提交所做的修改)
https://www.jianshu.com/p/67f20d19605a
git-bisect
git 有一个以二分法帮助定位问题的命令——bisect。
# 开始二分查找问题 |
参考:https://git-scm.com/book/zh/v2/Git-工具-使用-Git-调试
git filter-branch
彻底删除不需要的文件
# 删除 ./node_modules 目录 |
修改提交用户名
git filter-branch -f --env-filter "GIT_AUTHOR_NAME=your new author name" -- --all |
修改提交邮箱
git filter-branch -f --env-filter "GIT_AUTHOR_EMAIL=your new author email" -- --all |
other
git add .的时候遇到
warning: LF will be replaced by CRLF in ……`
git config core.autocrlf |
Git 永久删除文件(包括历史记录)
https://help.github.com/articles/removing-sensitive-data-from-a-repository/
# 在仓库的根目录执行 |
重新绑定,而不是合并创建的旧(受污染)存储库历史记录中的任何分支
- git 修改已提交的某一次的邮箱和用户信息
git filter-branch -f --env-filter \ |
fork 的项目( A )与原项目 (B) 保持同步
# 将 A 克隆到本地做中转 |
远程分支删除以后,本地显示仍然存在的解决办法
# 显示所有分支: |