超实用,超详细,一看就懂的 git 教程!

3,132 阅读17分钟

前言

本文行文将力求实用,详细,易懂,结合工作场景,将工作中遇到的最常用的git相关知识点做一总结。既是对git相关知识体系的一次梳理,又能分享给有需要的小伙伴进行学习提升。因本人能力水平有限,如有错误和建议,欢迎在评论区指出。若本篇文章有帮助到了您,不要吝啬您的小手还请点个赞再走哦!

1 起步

1.1 git是什么

Git是一个版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。

1.2 安装

官网(速度贼慢)

git-scm.com/downloads/

淘宝镜像(速度快)

npm.taobao.org/mirrors/git…

安装完检查一下版本 git --version

2 相关配置

2.1 使用前配置

配置使用者的用户名和邮箱,配置信息默认存储在:C:\Users\【当前电脑用户名】\.gitconfig 中

为了方便多人协作,所以需要设置用户
配置用户名
	git config --global user.name 提交人姓名
配置邮箱
	git config --global user.email 提交人邮箱

查看git配置信息

git config --list

注意: 如果要对配置信息进行修改,重复上述命令即可配置只需要执行一次

2.2 ssh免登录(以github为例)

实现原理:

将自己电脑中的私钥和github中的公钥进行配对,配对成功就不用输入账号密码了,所以只需要生成一次,配置完成后此电脑中的任何项目上传到自己的仓库都不需要登陆了

生成私钥和公钥

在要生成ssh 秘钥的项目中打开git ,输入ssh-keygen, 一直按回车就会在
C:\Users\【当前电脑用户名】\.ssh 中生成私钥和公钥对. 

将电脑中的公钥放到 github 中就能免密码上传了

将C:\Users\【当前电脑用户名】\.ssh 中 id_rsa.pub 文件中的字符 复制到 github 的 
(右上角 settings / ssh and GPG keys / New SSH key/)的 key 输入框中

RSA 是一种非对称加密方式

使用

在 github 仓库中 Clone or download 中点击 Use SSH 就能获取到 SSH 对应的地址了,然后就能免密码克隆或推送了

2.3 忽略或追踪文件或文件夹

在项目根目录下面 添加 .gitignore 文件。文件中每一行表示需要忽略的文件的正则表达式

忽略文件夹或文件:

  • /mtk/

    过滤整个文件夹

  • *.zip

    过滤所有.zip文件

  • js/*.zip

    过滤js目录下所有.zip文件

  • /mtk/do.c

    过滤某个具体文件

被过滤掉的文件就不会出现在git仓库中(gitlab或github)了,当然本地库中还有,只是push的时候不会上传。

追踪文件夹或文件:

与忽略唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中。

  • !*.zip

    追踪所有.zip文件

  • !/mtk/one.txt

    追踪mtk目录下的 one.txt 文件

如果你不慎在创建.gitignore文件之前就push了项目,那么即使你在.gitignore文件中写入新的过滤规则,这些规则也不会起作用,Git仍然会对所有文件进行版本管理。简单来说,出现这种问题的原因就是Git已经开始管理这些文件了,所以你无法再通过过滤规则过滤它们。因此一定要养成在项目开始就创建.gitignore文件的习惯,否则一旦push,处理起来会非常麻烦。

.gitignore 文件中的规则需要提交到 Git 仓库后才能生效。一旦你修改或添加了 .gitignore 文件,你需要将这个文件提交到仓库,这样 Git 才会在以后的提交和状态检查中考虑这些规则。

2.4 忽略已经 push 到远程的文件

示例: /public/script/version.js 路径下的文件被 push 到了远程,直接在.gitignore 文件中添加规则 /public/script/version.js,push 到远程后发现并未生效。

原因:version.js 文件已经被纳入版本控制,那么 .gitignore 中的规则将不会起作用。你需要先从版本控制中移除该文件,然后提交更改。


git rm --cached public/script/version.js 

git commit -m "Remove version.js from version control"

这样,文件将从版本控制中移除,而 .gitignore 中的规则将在以后生效。

3 提交及查看

3.1 初始化git仓储

在项目所在目录点击右键,选择 Git Bash Here, 输入 git init,会自动创建一个隐藏的空目录 .git,项目的备份代码会存储在这里

3.2 查看状态

git status

如当输入 git add ./文件名 后,可以通过它来查看文件是否放到了暂存区。 如果放到了入口,会显示:modified: readme.md

检测项目文件和存入仓储的文件是否一致,如果一致,返回 nothing to commit, working tree clean。否则会显示红色字体的 modified: readme.md

3.3 将代码分两步存储到本地git仓储

  1. 把代码放到仓储暂存区

    • git add 文件名

    将指定的文件放到暂存区

    • git add .

    只要是修改过的文件都会放到仓储暂存区

  2. 把代码放到仓储房间

    • git commit -m 描述信息

      git commit -m "这里写文件的描述信息" (m是message的简写)。如果没有写 -m,可以通过按ESC后输入 :q 来退出

3.4 查看日志(提交历史)

  • git log

    可以查看到用户名,邮箱,每一次修改的时间和说明等内容。注意这是查看当前分支,再次按q退出

  • git log 分支名

    查看指定分支的用户名,邮箱,每一次修改的时间和说明等内容。再次按q退出

  • git log --pretty=oneline

    只显示提交的commitID 和 说明内容

  • git log --graph --all

    --all 可以查看所有分支,已经被回退掉的分支也能查看到

  • git log --graph --pretty=oneline --abbrev-commit

    查看分支合并情况

  • git blame

    以列表方式查看指定文件的提交历史

3.5 查看文件修改内容

  • git diff

4 撤消

4.1 用暂存区中的文件覆盖工作目录中的文件

  • git checkout 文件名

业务场景:代码写到一半的时候先把代码添加到了暂存区,继续写下面的代码,写完后发现代码有问题,要恢复到一半的时候,用这个命令就能把暂存区的代码覆盖本地的代码,从而实现回退

4.2 将文件从暂存区中删除

  • git rm --cached 文件名

业务场景:不小心把一些不需要上传到仓库的代码提交到了暂存区,可以用这个命令删除暂存区的文件,本地的文件不会受到影响

4.3 将文件从暂存区中删除

4.3 回退到之前的版本

根据commitID 回退到指定版本

  • git reset --hard commitID

将git仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作目录

commitID: git log 命令可以获取到,commitID 格式:e6cc775bd2a738b0c22e6642794ddfcad2e7619a

通过 HEAD 回退到之前版本

  • git reset --hard HEAD^

HEAD表示当前版本,也就是最新的提交1094adb...,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

恢复回退之前的版本(穿梭至未来)

  • git reflog

记录你的每一次命令,这样可以查看到最近的操作,从而获取到 commitID,然后根据 ID 回退即可

5 把本地库的内容推送到远程

5.1 通过github中仓库中项目的http地址来推送

  • git push http地址 分支名

示例:git push origin github.com/wangjunjie0… master

注意:如果是用https的方式进行提交,第一次提交时需要输入github账号密码,后面就不需要了,这是win10 系统帮我记住了密码,不是git的功能。在控制面板-凭据管理器--windows凭据里面可以查看到

5.2 给远程提交增加别名

  • git remote add 别名 远程地址

示例:git remote add origin github.com/wangjunjie0…

然后就能通过 git push origin 分支名 来提交了,如提交到远程的 dev 分支可以这样写:git push origin dev。

5.3 查看远程仓库地址

  • git remote -v

5.4 远程仓库地址更改后本地仓库重新关联

  • git remote add 别名 远程地址

注意:此时若之前用 别名 origin 关联过了,现在仍然想用 origin 关联更改地址后的仓库,需要 <git remote rm 别名> 先删除关联过的别名再进行操作

5.5 记住远程仓库地址和分支名

  • git push -u origin master

-u 这样写是绑定origin和master的,下次推送只需要输入git push 就可以了

5.6 强制操作

强制提交

  • git push origin 分支名 --force

  • 或 git push origin 分支名 -f

  • 或 git push -f

会将远程文件覆盖,谨慎操作!

6 拉取操作

6.1 克隆远程仓库到本地(无本地仓库,相当于拷贝一份远程仓库)

  • git clone 远程地址

    把远程仓库的内容克隆到执行git命令的文件夹,项目名称也就是远程仓库的名称 git clone github.com/wangjunjie0…

  • git clone <url> filename --depth=1

    filename:克隆文件的重命名 --depth=1:只下载最后一次的commit(提交),其他历史记录不要

  • 直接克隆远程指定分支

    上面的命令默认克隆master主分支, 克隆远程指定分支可以用以下命令:

    git clone -b <指定分支名> <远程仓库地址>

    示例:git clone -b dev-permission github.com/wdlhao/vue2…

6.2 拉取远程仓库最新版本(本地仓库存在,远程仓库和本地仓库比较)

  • git pull 远程仓库地址 分支名

    用地址和分支名的方式拉取。

  • git pull origin master

    用别名的方式拉取远程代码,前提是给远程仓库添加过别名

  • git pull

    拉取当前分支最新代码

6.3 强制拉取

  • git pull --rebase origin master

    会将本地文件覆盖,谨慎操作!

7 将本地库内容推送到远程的完整步骤(远程仓库还未初始化的情况)

  1. 在本地项目中调出 git Bash here

  2. 命令行输入 git init 初始化git仓库

  3. 命令行输入 git add . (将代码放到仓储暂存区)

  4. git commit -m '描述信息' (将代码放到仓储房间)

  5. git remote add 别名 远程地址

    给远程提交增加别名,一般会写成这样:git remote add origin 远程地址 远程地址在github中复制。可以新建一个仓库 (注意:只是新建不要初始化这个仓库),然后在界面中复制地址就行了

  6. 然后就能通过 git push origin master 将代码提交到远程了

    或者根据 5.5节 方式记住远程仓库地址和分支名,下次推送只需要输入 git push 就可以了

报错处理:

fatal: remote origin already exists.

这是因为之前已经关联过了,删除后再重新关联即可

git remote rm 别名
git remote add 别名 远程地址

8 分支

为了便于理解,大家暂时可以认为分支就是当前工作目录中代码的一份副本。使用分支,可以让我们从开发主线上分离出来,以免影响开发主线。

8.1 查看远程库信息

  • git remote

    查看远程库的信息(简单信息), 返回远程仓库的名称,默认为 origin

  • git remote -v

    查看远程库的信息(详细信息), 返回下方所示: origin http://192.168.3.95:10000/root/demo.git (fetch) origin http://192.168.3.95:10000/root/demo.git (push) 上方显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址

8.2 一般项目中所需分支

  • 主分支(master)

    第一次向git仓库中提交更新记录时自动产生的一个分支

  • 开发分支(develop)

    作为开发的分支,基于master分支创建

  • 功能分支(feature)

    作为开发具体功能的分支,基于开发分支创建

8.3 分支命令

  • git branch

    显示所有本地分支

  • git branch -r

    显示所有远程分支

  • git branch 分支名称(新写法:git switch -c 分支名称 )

    创建分支,当前在哪个分支就基于哪个分支创建分支

  • git branch -m 指定分支名 新的分支名

    重命名本地指定分支

  • git branch -m 新的分支名

    重命名本地当前分支

  • 重命名远程分支

    先拉取想要重命名的最新远程分支,然后在本地重命名,然后删除远程分支,最后重新将重命名后的本地分支推送到远程即可

  • git branch -d 分支名称

    删除本地分支,分支合并后才允许删除,将-d 换成 -D 为强制删除。

删除分支时需要切换到其他的分支,如果分支还没有合并 -d 不能删除,如有必要可以用 -D 强制删除

  • git push origin -d 分支名称

    删除远程分支

  • git checkout 分支名称(新写法:git switch 分支名称

    切换到指定分支。示例:创建并切换到dev分支:git checkout -b dev(git switch -c dev)

    在不同分支创建的文件提交后,切换到其他的分支是查看不到的,注意要提交,放到暂存区的不行。 如果不提交或不暂时保存更改就切换,会在其他分支上显示此分支新建的内容

  • git merge 来源分支

    合并指定分支到当前分支,默认用 Fast forward(--ff) 模式合并。

如果当前分支上的工作已经完成,就可以把当前分支上的工作合并到其他分支上去了。 如需要把 develop 分支合并到 master,需要在 master 上操作

  • 查看分支合并情况(简略版)

    • git log --graph --pretty=oneline --abbrev-commit

图示:

111.png

  • 查看分支合并情况(详细版)

    • git log --graph

图示:

222.png

8.4 创建 及 切换分支图解

创建分支:Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,表示当前分支在dev上

333.png

在分支工作:此时工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变

444.png

--ff 模式合并:直接把master指向dev的当前提交

555.png

删除dev分支:如果是 --ff 模式合并,删除分支后,会丢掉分支信息

666.png

8.5 本地分支与远程分支的关系维护篇

  • git branch -vv

    查看本地分支和远程分支的映射关系

777.png

上图dev是本地分支,映射的是 origin/dev 远程分支

  • 本地分支不存在dev,远程分支存在dev时的处理:

    1、在本地创建dev分支:git switch -c dev

    2、将本地分支关联到远程分支:git branch --set-upstream-to=origin/dev dev

    解析:git branch --set-upstream-to=origin/远程分支名 本地分支名 使用 git 在本地新建一个分支后,需要做远程分支关联。如果没有关联,git会在下面的操作中提示你添加关联。

    3、拉取远程分支到本地:git pull

  • 本地分支存在 dev 远程分支不存在dev时的处理:

    git push -u origin dev (git push -u origin 新建的远程分支名)

9 stash 暂时保存更改

适用于遇到临时的任务,可以在不提交分支任务的情况下切换分支。

  • git stash

    存储临时改动到git的剪贴板

  • git stash save "save message"

    执行存储时,添加备注,方便查找,只有git stash 也要可以的,但查找时不方便识别

  • git stash list

    查看 临时改动到git的剪贴板

  • git stash pop

    恢复改动,将git剪贴板上所有的改动恢复到分支上

  • git stash clear

    删除所有缓存的stash

剪贴板是独立于分支之外的,所以在其他的分支也能执行这个命令,所以需要注意你当前所在的命令在哪个分支

10 标签管理

10.1 概述

标签其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。

那么有commit,为什么还要引入tag呢?tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起,如tag指定为 v1.0.0 比 commitID 一串无意义额数字要好找

10.2 创建标签

  • 在当前分支创建标签

    git tag <tagname>

    示例:git tag v1.0,默认标签是打在最新提交的 commit 上的。

  • 在指定分支创建标签

    git tag <标签名> commitID

    示例:git tag v0.9 f52c633

  • 创建带有说明的标签

    git tag -a 标签名 -m "说明文字" commitID

    示例:git tag -a v0.1 -m "version 0.1 released" 1094adb

用-a指定标签名,-m 指定说明文字,省略 commitID 时默认指定当前版本

  • 查看所有标签

    git tag

图示:

888.png

注意:标签不是按时间顺序列出,而是按字母排序的。可以用 git show <tagname> 查看标签信息

10.3 操作标签

  • 删除

    git tag -d <tagname>

    示例:git tag -d v0.1,创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除

  • 推送某个标签到远程

    git push origin <tagname>

    示例:git push origin v1.0

  • 一次性推送全部尚未推送到远程的本地标签

    git push origin --tags

  • 删除远程标签

    1. 先从本地删除

    git tag -d <tagname>

    示例:git tag -d v0.9

    1. 再从远程删除

    git push origin :refs/tags/ <tagname>

    示例:git push origin :refs/tags/v0.9

10.4 真实场景再现

需求:本地只有 dev 分支无 master 分支,此时向远程 master 分支 push 内容并打上标签。

  1. 创建并切换到master分支

    git switch -c master

  2. 拉取远程 master

    git pull origin master --allow-unrelated-histories

  3. 将本地 master 分支映射到 远程 master

    git branch --set-upstream-to=origin/master master

  4. 将本地 commit 推送到远程 master

    git push -u origin master

  5. 创建带有说明的标签

    git tag -a <标签名> -m "说明文字"

    示例:git tag -a v1.0 -m "xxx说明文字"

  6. 推送标签到远程master

    git push origin v1.0

11 团队及跨团队协作(github为例)

11.1 团队协作

邀请合作者

  • 只有仓库的所有者邀请合作者之后,合作者才能将代码提交到仓库。

  • 在仓库中点击setting-collaborators,输入密码后,在输入框中输入被邀请者的github账号, 点击邀请后,上面会出现邀请链接,把这个链接发送给被邀请的程序员,被邀请进入这个链接接收邀请后就能向这个仓库提交代码了

11.2 跨团队协作

在其他开发者的github仓库中点击fork,此时会把这个仓库复制到自己的仓库中,先从自己仓库克隆到本地,然后可以在里面进行完善修改提交,修改完善完成可以发送给原开发者,如果采纳才能将你的代码合并到原作者的仓库。

以程序猿C为例的步骤:

  1. 程序猿C fork仓库

  2. 程序猿C 将仓库克隆在本地进行修改

  3. 程序猿C 将仓库推送到远程

  4. 程序猿C 发起 pull request

  5. 原仓库作者审核

  6. 原仓库作者合并代码

从自己仓库把修改后的代码向原作者发出请求的步骤

  1. 在自己本地仓库点击 Pull requests
  2. 点击New pull request
  3. 点击create pull request (在这一步可以写一些描述信息来和原作者进行沟通,然后修改信息就会发送给原作者了,原作者可以在自己仓库的Pull requests 中查看到这条信息,并予以回复)

参考文献:www.liaoxuefeng.com/wiki/896043…