git
廖雪峰
跟踪文本文件的改动
不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符
基础用法
1.git init
把当前目录变成Git可以管理的仓库:
$ mkdir learngit
$ cd learngit
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
2.git add commit
- git add
$ git add readme.txt
- git commit
$ git commit -m "wrote a readme file"
[master (root-commit) eaadf4e] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
-m
后面输入的是本次提交的说明
查看 git status diff log
查看工作区状态
$ git status
查看文件变化
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
Git is free software.
查看日志
git log
命令显示从最近到最远的提交日志
$ git log
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file
一大串类似1094adb...
的是commit id
(版本号),Git的commit id
是一个SHA1计算出来的一个非常大的数字,用十六进制表示
版本切换git reset
- 在Git中,用
HEAD
表示当前版本,也就是最新的提交,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,往上100个版本写成HEAD~100
回退到上一版本
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed
- 提供版本号(比如刚刚回退之前的最新版本的版本号开头是1094a,想到那个版本)
版本号没必要写全,前几位就可以了,Git会自动去找
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL
- 原理
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL
:
┌────┐
│HEAD│
└────┘
│
└──> ○ append GPL
│
○ add distributed
│
○ wrote a readme file
改为指向add distributed
:
┌────┐
│HEAD│
└────┘
│
│ ○ append GPL
│ │
└──> ○ add distributed
│
○ wrote a readme file
然后顺便把工作区的文件更新了。
git reflog
git reflog
查看你的每一次命令:
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file
第一列是版本号
丢弃修改git checkout reset
git checkout -- file
用版本库里的版本替换工作区的版本(让这个文件回到最近一次git commit
或git add
时的状态)
$ git checkout -- readme.txt
命令git checkout -- readme.txt
意思就是,把readme.txt
文件 用版本库里的版本替换工作区的版本,这里有两种情况:
一种是readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
git reset HEAD <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
删除文件
$ rm test.txt
把工作区文件删除之后(test.txt是已经提交了的),
用命令git rm
删掉,并且git commit
:
$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
现在,文件就从版本库中被删除了。
远程仓库
设置user name和email
如果你是第一次使用,或者还没有配置过的话需要操作一下命令,自行替换相应字段。
git config --global user.name "Luke.Deng"
git config --global user.email "xiangshuo1992@gmail.com"
git config –list 查看当前Git环境所有配置,还可以配置一些命令别名之类的。
远程仓库地址操作
添加远程仓库:进入本地仓库执行:origin是给远程源的一个命名,你可以随便取
git remote add origin <远程仓库git的地址>
修改远程仓库地址:
git remote set-url origin <remote-url>
仓库路径查询查询:
git remote -v
删除指定的远程仓库:
git remote rm origin
git push 本地仓库推送到远程仓库(已关联)
将本地当前分支 推送到 远程指定分支上(分支名字方向是 按**数据传输方向 ->**):
git push <远程仓库“名字”,在remote add的时候取的名字> <本地分支名>:<远程分支名> #若两个分支名字只写一个,则默认这俩分支名都是它
比如:
git push origin master # 将当前仓库的master分支推送到origin的master分支
git push origin main baseline # 将当前仓库的main分支推送到origin的baseline分支
-f:强制推送到远程仓库,且覆盖远程代码库
git push -f origin master
git pull 从远程获取代码并合并本地的版本
分支名字方向是 按**数据传输方向 ->**:
git pull <远程仓库“名字”,在remote add的时候取的名字> <远程分支名>:<本地分支名>
比如:
git pull origin master
git clone远程仓库
进入本地目录:
git clone <远程仓库git地址>
这样执行git clone的目录下fork来的那个目录就是一个git目录了,并且自动关联远程仓库
克隆指定分支
git clone -b <指定分支名> <远程仓库git地址>
gitignore
在项目开发过程中个,一般都会添加 .gitignore 文件,规则很简单,但有时会发现,规则不生效。
原因是 .gitignore 只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。
git rm -r --cached .
git add .
git commit -m "update .gitignore"
本地仓库关联git服务器上的.git
step1 git服务器上操作
下文用
附:root如何创建用户:
例如创建“张三”用户:
useradd zhangsan passwd hnuzs
- [可选]ssh免登陆操作
此步骤是为了在本地服务器连接远程git服务器时免于输入用户密码,具体操作如下:
将本地服务器的公钥id_rsa.pub传入远程git服务器的/home/
cat id_rsa.pub >> authorized_keys #pwd:/home/<user_name>/.ssh
- 创建并初始化git仓库
首先创建一个目录作为git仓库并赋予所属用户
cd /home/<user_name>
mkdir zsgitrepo
chown <user_name>:<user_name> zsgitrepo/
接着使用git命令创建一个裸仓库,服务器上的git仓库通常以.git结尾,并更改仓库所属用户:
cd zsgitrepo
git init --bare zsrepo.git
chown -R <user_name>:<user_name> zsrepo.git
step2 本地服务器上操作
- 添加远程版本库
git remote add origin git@<git_server_ip>:/home/<user_name>/xxrepo/xx.git # git@<git_server_ip>:<absolute path to your .git on git server>
关联后举例:git clone克隆仓库
注意clone的.git的地址
$ git clone <user_name>@<git_server_ip>:/home/<user_name>/zsgitrepo/zsrepo.git
Cloning into 'zsrepo'...
公匙
解决 remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
解决方法:
本地服务器生成公匙并上传到远程服务器上,具体操作:
然后remote用ssh的地址,不用http的地址

linux下公匙私匙生成
公匙上传github
windows下公匙私匙生成
git安装好后
右键选择Git GUI Here->Help->Show SSH Key


就能得到私钥和公钥
公钥上传远程git服务器的认证文件中
cat id_rsa.pub >> authorized_keys #pwd:/home/<user_name>/.ssh/
如果没有~/.ssh/authorized_keys就新建一个
cd /home/<user_name>
mkdir .ssh
chmod 700 .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
git原理
暂存区
工作区(Working Directory):比如刚刚git init所在的那个目录
版本库(Repository):工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。

把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用 git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用 git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master
分支,所以,现在,git commit
就是往master
分支上提交更改。现在改成main了
gitflow
流程概念
错误示范:
不知道他怎么搞的,直接 push 到 master 分支去了,直接跨过开发分支和测试分支,直接合到 master 发布分支上去了(一般来说,master都是有保护的!)。
这还不算什么。。。如果只是这样就还好,关键是他看有写代码冲突就直接在 master 分支上对已经成功发版的代码增删改!!!
一般来说,团队合作开发的话,每个人都需要在自己的功能分支 feat/XXX 上开发,最后一起合并到总的开发分支 dev 上,然后将开发分支 dev 合并到测试分支上,最后将测试分支合并到正式发布分支上。
其中总的开发分支一般叫做 dev 分支,正式发布分支一般是叫 main/master/release 分支。
一般的开发流程:

比如说有 A、B、C 三个人协助进行功能开发:
1、首先 A、B、C 三位小伙伴从总开发分支 Dev 上开辟自己的功能分支,分别是 feat/AXXX、feat/BXXX、feat/CXXX,也就是图中 feat/AXXX、feat/BXXX、feat/CXXX 的三条线;
2、然后在自己的开发机上进行开发,这里的开发机可以是本地环境也可以是一些云端的开发机。开发完毕后,再分别合到总开发分支 dev 上,也就是图中蓝色的三条线,在这个过程中可能会产生一些代码冲突,挨个 solve 即可;
3、接着在 dev 分支上确认所有功能开发完毕,进行简单自测,fix 一些 bug 后再向测试分支上进行合并;
4、这个时候就可以艾特测试组的同学来进行测试,测试通过后再合到 master 分支进行发布。

git提交-m规范
type (scope): message
参数介绍:
1、type:指的代码的提交类型,不同的提交类型表示对应不同的代码改动,比如:
- feat:新功能的开发
- fix:bug的修复
- docs:文档格式的改动
- style:代码格式改变
- refactor:对已有的功能进行重构
- perf:性能优化
- test:增加测试
- build:改变了build工具
- revert:撤销上一次的commit提交
- chore:构建过程或辅助工具的变动
2、scope:用于说明commit影响的范围,比如:权限模块、还是首页
3、message: 对提交的代码做一个简短的说明,不能过长。
fix(系统菜单图标):添加缺少的图标
问题
git: Failed to connect to 127.0.0.1 port 1080: Connection refused
在git init顶层目录下
git config --global --unset http.proxy
git config --global --unset https.proxy
OpenSSL SSL_read: Connection was reset, errno 10054
git config --global http.sslVerify "false"
Failed to connect to github.com port 443 after 21114 ms: Timed out
用ssh的那个地址