介绍
本文主要介绍Git的基本应用,这里是以github和码云gitee为例
本课程为 Git 与 GitHub 的入门课程,本着实用的原则,针对零基础同学,以图文的形式详细介绍了 Git & GitHub 结合使用的基本操作。课程包括:在 GitHub 上创建仓库、克隆 GitHub 上的仓库到本地、添加修改到暂存区以及撤销修改、配置个人信息、版本回退、处理提交时间线分叉问题、使用本地提交变化记录、添加 SSH 关联授权等方方面面的知识点。
⏩ 安装git
Linux 平台
在线安装
# Debian/Ubuntu
apt-get install git
# 或者先更新
apt update; apt install git
# Fedora 系列
yum install git
dnf install git
# Gentoo 系列
emerge --ask --verbose dev-vcs/git
# Arch Linux 系列
pacman -S git
# openSUSE 系列
zypper install git
# Mageia 系列
urpmi git
# Nix/NixOS 系列
nix-env -i git
# FreeBSD 系列
pkg install git
# Solaris 9/10/11 (OpenCSW) 系列
pkgutil -i git
# 等等
GitHub最新版安装
在Github下载最新版本。
-
下载v2.21.0版本
wget https://github.com/git/git/archive/v2.21.0.tar.gz -
安装依赖
yum -y install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker -
解压
tar -zxvf v2.21.0.tar.gz -
进入解压目录
cd git-2.21.0/ -
编译
make prefix=/usr/local/git all -
安装Git在/usr/local/git路径
make prefix=/usr/local/git install -
配置环境变量
# 编辑环境配置文件
vim /etc/profile
# 末尾添加
export PATH=/usr/local/git/bin:$PATH
# 立马生效
source /etc/profile
git version 查看安装的git版本,校验通过,安装成功。
Windows 平台
在 Windows 系统中可以安装 Git for Windows 客户端 :
如遇网络问题无法下载可以访问 华为云镜像站 下载。
⏩ SSH登录代码仓库
Github
我们可以在系统中创建 SSH 公私钥,并将公钥放到 GitHub 指定位置。如此操作即可生成 GitHub 账户对于当前系统中的 Git 授权。
在终端执行下面命令,每次询问按回车即可。
ssh-keygen -t ed25519 -C "你的邮箱地址"
终端执行 ssh-keygen 命令按几次回车生成公私钥,公私钥存放在主目录下的隐藏目录 .ssh 中的两个文件中:
将 ~/.ssh/id_rsa.pub 文件中的公钥内容复制出来
cat /home/shiyanlou/.ssh/id_ed25519.pub
然后在 GitHub 网页上添加公钥:
Title 自定义,把剪切板中的内容粘贴到 Key 中,点击绿色按钮添加 SSH Key 即可:
使用 SSH 的好处主要有两点:
- 免密码推送,执行
git push时不再需要输入用户名和密码了; - 提高数据传输速度。它不是必须的,比如在课程中挑战环境是不可保存的,一次性的,这种环境就没有必要创建 SSH 了,因为相较好处来说,还是太麻烦了。
Gitee
也是一样的,创建完秘钥之后,复制好私钥
添加进去
使用 SSH 的好处主要有两点:
- 免密码推送,执行
git push时不再需要输入用户名和密码了; - 提高数据传输速度。
⏩ 克隆仓库到本地
随便创建一个仓库,比如叫做shiyangit
现在克隆我们在 GitHub 上创建的仓库,使用 git clone + [仓库地址] 命令即可,这是标准的克隆仓库命令。
回到仓库主目录,点击下图所示的绿色按钮,点击紫色框中的 “Use SSH”,然后复制这个链接。
重要的一点:只有使用这种 git 开头的地址克隆仓库,SSH 关联才会起作用。
在实验环境里删除原仓库,使用此链接重新克隆仓库。克隆仓库是需要确认连接,输入 yes 即可:
进入仓库主目录,如下图所示,仓库主目录中有个 .git 隐藏目录,它里面包含了仓库的全部信息,删掉这个目录,仓库就变成普通的目录了。进入到仓库目录中,命令行前缀发生了一些变化,出现了红色的 master ,它就是当前所在的分支名:
- 当我们在 GitHub 上创建一个仓库时,同时生成了仓库的默认主机名 origin,并创建了默认分支 master。
- GitHub 可以看成是免费的 Git 服务器,在 GitHub 上创建仓库,会自动生成一个仓库地址,主机就是指代这个仓库,主机名就等于这个仓库地址。
- 克隆一个 GitHub 仓库(也叫远程仓库)到本地,本地仓库则会自动关联到这个远程仓库,执行
git remote -v命令可以查看本地仓库所关联的远程仓库信息:
Git 要求对本地仓库关联的每个远程主机都必须指定一个主机名(默认为 origin),用于本地仓库识别自己关联的主机,git remote 命令就用于管理本地仓库所关联的主机,一个本地仓库可以关联任意多个主机(即远程仓库)。
克隆远程仓库到本地时,还可以使用 -o 选项修改主机名,在地址后面加上一个字段作为本地仓库的主目录名,举例如下:
另一个在其它 Git 教程中常见的命令 git init ,它会把当前所在目录变成一个本地仓库,因为有 GitHub 的存在,这个命令在我们的生产生活中用到的次数应该是零,除非你想费时费力自己搭建服务器。操作截图如下:
⏩ 从本地修改文件
对工作区进行修改文件
执行 git status 查看整个仓库的状态:
创建一个文件并再次查看仓库状态,这步操作是在工作区中:
如上图所示,新建文件后,命令行前缀又发生了一些微小的变化,红色 master 后面出现了 * 星号,这表示工作区或暂存区有变化,对文件进行增删改操作都会出现这个星号,另外使用 git status 命令亦可查看详情。
添加修改到暂存区以及撤销修改
git add
按照上图的提示,使用 git add [文件名] 命令跟踪此新建文件,即把新增文件添加到暂存区,以备提交:
如果对多个文件或目录进行了增删改,可以使用
git add .命令全部添加到暂存区。
注意这里有个概念,当我们修改了工作区,git add 命令是将这些修改添加到暂存区,暂存区记录的只是修改。
git reset -- | git rm --cached
如果要撤销暂存区的修改怎么办?
根据上图的提示,执行 git reset -- [文件名] 或者 git rm --cached [文件名] 命令即可
上图的命令,如果省略最后的文件名,把命令写成
git reset --即可把暂存区的全部修改撤销。
好,现在暂存区的修改被撤销,又回到了工作区。
git diff
现在介绍另一个命令 git diff,它可以用来查看工作区被跟踪的文件的修改详情,此时新建文件 one.txt 并未被跟踪,而已被跟踪的文件 README.md 无修改,所以看不到。注意,只有在版本区中存在的文件才是被跟踪文件。
我们先修改 README.md 文件,执行此命令:
echo 'git shell ls' >> README.md
然后执行追踪命令:git diff
此时会跳到新的页面,即工作区修改详情页,按 Q 退出此页面:
现在,将工作区的两处修改(新增文件 one.txt,修改文件 README.md)全部添加到暂存区,并使用 git diff --cached 查看暂存区的全部修改:
git add .
git diff --cached
同样,此命令也会跳到新的页面,即暂存区修改详情页:
查看提交历史 git log
接下来,将执行 git commit 命令把暂存区的修改提交到版本区,生成一个新的版本。
在此之前,先介绍另一个命令 git log,它用来查看版本区的提交历史记录,当前只有一个提交,就是在 GitHub 上创建新仓库时的初始化提交。同样此命令也会跳到新页面,如下图所示:
关于查看提交历史记录的命令,有些常用的选项介绍一下:
git log [分支名]查看某分支的提交历史,不写分支名查看当前所在分支git log --oneline一行显示提交历史git log -n其中 n 是数字,查看最近 n 个提交git log --author [贡献者名字]查看指定贡献者的提交记录git log --graph图示法显示提交历史
配置个人信息
接下来需要对 Git 进行一些本地配置:
user.email:写入你自己注册 GitHub 账号的邮箱user.name:你自己的 GitHub 账号名字
这两个命令设置你的身份信息如下图。git config -l 可以查看配置信息(就不展示截图了):
完成后,系统自动生成 Git 的配置文件,就是主目录中的隐藏文件 .gitconfig:
上图所示的配置文件也是可以直接手动修改。
提交暂存区的修改
git commit
现在执行 git commit 命令生成一个新的提交,一个必须的选项 -m 用来提供该提交的备注:
提交后,暂存区的修改被清空,执行 git log 查看提交记录,紫色框中的十六进制序列号就是提交版本号,这是很重要的信息,每个提交都有自己单独的版本号,就像公民身份证号一样:
观察上图的提交信息,提交版本是按时间倒序排列的,也就是最近的提交排在最上面,你可能需要查看时间正序排列的信息,那么可以使用 git log --reverse 命令。
现在介绍一个超级实用、使用频率极高但几乎所有 Git 教程都不重视的命令 git branch -avv,它用来查看全部分支信息:
上图有三行信息,依次说明:
- 第一行,开头的星号表示
当前所在分支,绿色的 master 是分支名,之所以是绿色,也是因为它是当前所在分支。
- 第二项是
版本号。 - 第三项中括号里面蓝色的字,表示
此分支跟踪的远程分支的名字. - 当然啦,这也是克隆远程仓库到本地时的默认设置 -- 创建 master 分支并自动跟踪远程同名分支;
- 冒号后面黑色文字表示本地分支领先其跟踪的远程分支一个
提交。 - 最后一项是提交时填写的
备注信息。
-
第二行,是
Git 指针信息,它指向远程仓库的 master 分支,这行信息暂不重要。 -
第三行,
远程分支信息,详见第一行的解释。
在执行 commit 命令时,再介绍一个我并不推荐的选项 -a ,它的作用是将未添加到暂存区的修改,也就是工作区的修改也一并提交,但会略过未被跟踪的文件,比如新建文件 one.txt,此命令的完整格式:git commit -am xxxxx 。
谨慎的做法是按照前文的顺序,修改工作区 - 提交到暂存区 - 随时使用 git status 查看仓库状态 - 将暂存区的修改提交到版本区生成一次新的提交。
git push
最后一个环节,将本地新增的提交推送到 GitHub 远程仓库中,命令是 git push,后面不需要任何选项和参数,此命令会把本地仓库 master 分支上的新增提交推送到远程仓库的同名分支上,因为当前所在的分支就是 master,而且上文提到,它已经跟踪了远程仓库的同名分支:
此命令需要再次输入你的 Github 用户名和密码,密码为隐藏数据,输入时看不到。推送成功后执行 git branch -avv 查看分支情况:
如上图所示,本地分支 main 与远程分支 origin/main 的版本号一致,通常看两个版本号是否一致,只需比对前四位。看一下网页上的情况:
完全符合预期。
以上就是一次完整的修改 - 提交 - 推送操作。一次推送中可以包含多个 git commit 操作,也就是多个提交可以一起推送。
⏩ 版本回退(撤销)
如果发现 one.txt 文件内容有误,怎么做?可以修改此文件然后再次添加到暂存区、提交、推送,也可以撤销最近一次提交,修改文件后重新提交推送。现在使用后一种方法来演示撤销提交的操作流程。
首先执行 git reset --soft HEAD^ 撤销最近的一次提交,将修改还原到暂存区。
--soft表示软退回--hard硬退回
HEAD^ 表示撤销一次提交,HEAD^^ 表示撤销两次提交,撤销 n 次可以简写为 HEAD~n。
软退回一个提交后执行 git branch -avv 命令查看分支信息:
可以看到本地仓库的 main 分支的版本号已经发生了变化,变成了前一次提交的版本号,中括号里也有提示信息,本地分支 main 落后其跟踪的远程分支 origin/main 一个提交。
执行 git status 查看仓库状态,果然上一个提交中的修改全部扔回了暂存区:
再次修改 one.txt 文件,执行 git add . 命令将新的修改添加到暂存区,然后执行 git commit 命令生成新的提交:
⏩ 强制推送
执行 git status 和 git branch -avv 查看仓库状态和分支状态:
可以看到本地仓库的 master 分支与远程仓库的 origin/master 分支在提交版本上有了冲突,又叫做提交时间线分叉。
因为刚才的提交操作不是基于远程仓库 origin/master 分支的最新提交版本,而是撤回了一个版本。这种情况下也是可以将本地 master 分支推送到远程仓库的,需要加一个选项 -f ,它是 --force 的简写,这就是强制推送:
执行 git branch -avv 看一下分支信息,本地 master 与远程 master 的版本号一致,前四位都是 e290,在浏览器上刷新 GitHub 页面,结果如预期:
⏩ 回退 git reflog
假设此时发现情况不对,之前的那次版本号为 5c04 的提交是正确的,刚才的版本回退操作全都是误操作,怎么办?再次执行一次版本回退吗?当然不需要啦,我们有 git reflog 命令,它会记录本地仓库所有分支的每一次版本变化。实际上只要本地仓库不被删除,随你怎么折腾,都能回退到任何地方。
reflog记录只存在于本地仓库中,本地仓库删除后,记录消失。执行此命令如下图所示:
怎么回退到 5c04 那个版本呢?
可以直接执行命令 git reset --hard [版本号] ,如果记不清版本号,也可以根据上图第 3 行的信息,执行 git reset --hard HEAD@{2} 命令,其中 HEAD@{2} 就是上图第 3 行第 2 列所示,这个命令的意思是回到当前分支最近两次提交版本变化前:
还想反悔,刚才还是改对了,怎么办?再执行一次即可,这次大括号里就是 1 了:
重要的一点,本节全部命令中,只有
push是需要联网执行的,它对远程仓库进行了修改。
⏩ Git设置别名(快捷键)
上一节课程中的操作,有些命令的重复度极高,比如 git status 和 git branch -avv 等,Git 可以对这些命令设置别名,以便简化对它们的使用,设置别名的命令是 git config --global alias.[别名] [原命令],如果原命令中有选项,需要加引号。别名是自定义的,可以随意命名,设置后,原命令和别名具有同等作用。操作如下:
自己设置的别名要记住,也可以使用 git config -l 命令查看配置文件。下面文档中的命令将使用这些别名。
⏩ Git分支管理
1. git fetch 刷新本地分支信息
在介绍分支前,先讲解另一个命令 git fetch,它的作用是将远程仓库的分支信息拉取到本地仓库,注意,仅仅是更新了本地的远程分支信息,也就是执行 git branch -avv 命令时,查看到的 remotes 开头的行的分支信息。
举例说明一下,首先我们在 GitHub 页面上对 one.txt 文件进行修改并增加一次提交。
提交完成后,提交数变成 3 个,点下图紫色框中的链接可以看到提交记录:
在实验环境中执行 git fetch 命令,然后执行 git branch -avv 查看分支信息:
可以看到,本地分支 master 的版本号无变化,而远程分支已经更新。
fetch命令的作用是刷新保存在本地仓库的远程分支信息,此命令需要联网。- 此时若想使本地 master 分支的提交版本为最新,可以执行
git pull命令来拉取远程分支到本地,pull是拉取远程仓库的数据到本地,需要联网。 - 而由于前面执行过
git fetch命令,所以也可以执行git rebase origin/master命令来实现 “使本地 master 分支基于远程仓库的 master 分支”,rebase命令在后面还会经常用到,这里只需按部就班操作即可:
可以看到,远程仓库 master 分支、本地仓库的 origin/master 分支、本地仓库的 master 分支已经一致。
2. 创建新的本地分支
分支在项目开发中作用重大,多人协作时尤其不可或缺。例如一个项目上线了 1.0 版本,研发部门需要开发 1.1、1.2 两个测试版,增加不同的新功能,测试版的代码显然不能在正式版所在的分支上,此时需要新的分支来存放不同版次的代码。
每个人都有各自的分支,在自己的分支上进行修改,然后向 master 分支提 PR(pull request),最后从 master 分支推送到线上。
首先,克隆远程仓库到本地,进入仓库主目录,执行 git br 查看分支信息:
执行 git branch [分支名] 可以创建新的分支:
此命令创建新分支后并未切换到新分支,还是在 master 分支上,执行 git checkout [分支名] 切换分支,checkout 也是常用命令,先给它设置别名,然后切换分支:
创建新分支还要手动切换太麻烦,介绍另一个常用的命令 git checkout -b [分支名] 创建分支并切换到新分支:
如上图所示的分支信息,前两行是新建的本地分支信息,它们的版本号与主分支 master 一致,这是因为在哪个分支上创建新分支,新分支的提交记录就与哪个分支一致。新建分支并无跟踪任何远程分支,所以没有 master 分支中的中括号和括号内的蓝色远程分支名。
假设我们要在当前分支 dev1 上开发一个新的功能,需要增加一个文件 new_func1,然后生成一个新的提交:
3. 将新分支的提交推送给仓库
好,新功能已经写好并提交到了版本区,现在要推送了,推送到哪里呢?正常逻辑当然要推送到远程仓库的同名分支,不过现在远程仓库里只有一个分支:
上图紫色框中是一个下拉按钮,点击后显示仓库中的全部分支,按钮上显示的是当前所在分支。
执行 git push [主机名] [本地分支名]:[远程分支名] 即可将本地分支推送到远程仓库的分支中,通常冒号前后的分支名是相同的,如果是相同的,可以省略 :[远程分支名],如果远程分支不存在,会自动创建:
上图命令可以简写为 git push origin dev1 。注意哦,这是我们创建 SSH 关联后第一次执行 push 命令,可以看到传输速度有明显的提高,更重要的是,不再需要重复输入用户名和密码了,另外打印信息的第一行是警告信息,因为是这个分支的第一次推送嘛,下次执行推送就不会再出现了。现在执行 git br 查看一下分支情况:
可以看到,远程分支 origin/dev1 的信息已经在本地存在,且与本地同名分支一致。再看下 GitHub 页面的情况:
很好,与预期毫无二致。
4. 本地分支跟踪远程分支
在有个问题,当我们再次在 dev1 分支上修改并提交,推送到远程仓库时还是要输入上面的那个长长的命令,好不方便。如果能和 master 分支一样跟踪远程同名分支,就可以直接使用
git push命令推送了。
有办法的,执行这个命令 git branch -u [主机名/远程分支名] [本地分支名] 将本地分支与远程分支关联,或者说使本地分支跟踪远程分支。如果是设置当前所在分支跟踪远程分支,最后一个参数本地分支名可以省略不写:
这个命令的 -u 选项是 --set-upstream 的缩写。可不可以让本地分支跟踪远程非同名分支呢?可以的,尽管几乎遇不到这种自找麻烦的需求。
可不可以撤销本地分支对远程分支的跟踪呢?也是可以的,执行 git branch --unset-upstream [分支名] 即可撤销该分支对远程分支的跟踪,同样地,如果撤销当前所在的分支的跟踪,分支名可以省略不写:
问题又来了,前面的操作是先将本地分支推送到远程仓库,使远程仓库创建新分支,然后再执行命令使本地分支跟踪远程分支,有没有办法在推送时就自动跟踪远程分支呢?有的,在推送的时候,加个 --set-upstream 或其简写 -u 选项即可,现在切换到 dev 分支试一下这个命令:
5. 删除远程分支
接下来,介绍一下删除分支的方法。
首先,删除远程分支,使用 git push [主机名] :[远程分支名] ,如果一次性删除多个,可以这样:git push [主机名] :[远程分支名] :[远程分支名] :[远程分支名] 。此命令的原理是将空分支推送到远程分支,结果自然就是远程分支被删除。另一个删除远程分支的命令:git push [主机名] --delete [远程分支名]。删除远程分支的命令可以在任意本地分支中执行。两个命令分别试一下:
可以看到本地仓库已经没有远程分支 dev 和 dev1 的分支信息。查看 GitHub 仓库页面:
也只剩 master 一个分支。操作成功。
6. 本地分支的更名与删除
回到实验环境,使用 git branch -D [分支名] 删除本地分支,同样地,此命令也可以一次删除多个,将需要删除的分支名罗列在命令后面即可。在此之前,先介绍一个极少用到的命令:给本地分支改名 git branch -m [原分支名] [新分支名] ,若修改当前所在分支的名字,原分支名可以省略不写:
好,现在要一次性删除本地分支 ved 和 dev1。需要注意的一点:当前所在的分支不能被删除。切换到 master 分支,然后执行 git branch -D ved dev1 命令:
执行 git branch -avv 查看当前仓库分支状态:
很好,一切都回到了课程开始时的样子,就像什么都没有发生。