AcWing「Linux基础课」第 5 讲 Git

Git 简介

Git 是一个版本控制工具,可以记录我们每次提交到 Git 中的版本,便于版本控制,以及还有一个重要的功能就是协作开发。

Git 的版本控制是基于树结构的,开始状态只有根节点(空姐点),之后每提交一个版本就会再根节点下添加一个节点,同时 HEAD 指针会指向这个节点。默认是在 master 分支上操作,可以创建其他分支多人协作开发,比如 dev 分支,在 dev 分支上开发完成之后再合并到 master 分支上。

image-20220401214818003.png

Git 命令

1. Git 配置

配置全局用户名和邮箱用于唯一标识一个用户

1
2
git config --global user.name tonngw
git config --global user.email xxx@qq.com

配置的信息会存在家目录下 ~/.gitconfig 文件中

2. 快速开始

首先创建一个项目文件夹,比如 project,想让 git 管理这个文件夹里的所有内容。

第一步git init

进入 project 文件夹,初始化 git 仓库 git init

ls -a 会发现当前目录下多了一个 .git 隐藏文件夹,用 git 管理项目的所有信息都会存在这个文件夹中。哪一天不想让 git 管理项目了,直接删掉就行了。

第二步git add filename/directory

project 下添加内容,比如创建了一个文件 readme.txt,然后通过 git add readme.txt 将它添加到暂存区,让 git 管理。

git add . 可以将当前文件夹下的所有文件的修改都添加到暂存区中。

第三步git commit -m "commit message"

将暂存区中的内容提交 / 持久化到本地库。

这就是一个最基本的用 git 管理本地项目的流程。当然代码放到本地说不定哪一天就丢掉,或者想在别的电脑上开发,这时候就需要远程仓库了。

第四步git remote add origin 远程地址

我们需要先在远程仓库创建一个仓库,如果没有配置 SSH,默认是 https 的地址,推送代码需要输入账号密码授权。为了方便还是用 SSH 可以免密推送,只需将本地公钥配置到远程仓库中就可以了。SSH 配置可以看上一篇笔记

第五步git push -u origin master

将当前分支(默认是 master 分支)推送到远程仓库,此时刷新远程仓库页面马上就能看到我们的代码。

第一次推送需要 -uu - upstream,指定远程分支上传流 / 将当前本地分支与远程分支进行绑定,让 git 知道默认要推送到哪,之后可以直接 git push 不需要加后面的参数。

详情

其他:git status,查看当前状态,非常常用,我们每进行一系列操作后都会查看一下当前的状态是否是我们预期的。

3. 查看信息

查看版本信息

git log:查看当前分支的所有版本,从根节点到 HEAD 的所有版本,HEAD 之后的版本看不到。

  • git log --pretty=oneline:将版本信息显示在一行,方便查看,原始的 git log 打印的信息比较多,不方便查看。

git reflog:查看 HEAD 指针的移动历史,即 HEAD 指针所有指向过的版本,这个命令可以看到所有的版本。

git log --stat:显示 commit 历史,以及每次 commit 发生变更的文件

查看文件差异

1
2
git diff # 查看暂存区和工作区的差异
git diff HEAD # 显示工作区与当前分支最新commit之间的差异

查看文件状态

git status

查看暂存区信息

git ls-files:查看暂存区中的内容

4. 添加文件

添加文件到暂存区

1
2
3
git add [file] # 将指定文件添加到暂存区
git add [dir] # 将指定目录添加到暂存区
git add . # 将当前目录下的所有内容添加到暂存区

5. 代码提交

将暂存区中的内容提交到本地库

1
2
3
4
5
6
# 最常用
git commit -m "message" # 将暂存区中的内容提交到本地库

git commit -m [file] [file2] # 将暂存区中指定的文件提交到本地库
git commit -a # 提交工作区自上次 commit 之后的变化,不能指定 message
git commit -v # 提交时显示所有的 diff 信息

强迫症必备!!!

有时候我们提交了一次,可能就单纯因为提交信息写的不好,想改,怎么办?版本回退一下那你的代码还得再写一遍,不太值得吧。这事用下面的命令就可以轻松解决

1
2
3
# 使用一个新的 commit 替代上一次的提交
# 如果代码没有变化,那仅仅用来修改上一次 commit 的提交信息
git commit -amend -m "message" # amend 修改

写了两个功能,一不小心提交了,现在想把这两个功能分两次提交,可以用下面这个命令

1
2
# 重做上一次 commit,仅包含指定的文件
git commit --amend [file] [file2]

6. 版本回滚

git reset --hard HEAD^git reset --hard HEAD~:将本地库回滚到上一个版本,^~ 都表示上一个,要回退几个版本后面加几。

  • git reset --hard HEAD^^:向前回滚两个版本
  • git reset --hard HEAD~100:向前回滚 100 个版本

当版本比较多的时候我们也不知道回滚几次才是我们想要的版本,此时就需要通过版本号来进行回滚,非常常用

  • 首先通过 git log 查看想要回退到的版本号,取当前版本 hash 值前 7 位 或者前 6 位都可以。
  • 然后 git reset --hard 版本号:即可回滚到当前版本
  • 如果想回退到 HEAD 之后的版本,git log 是看不到版本信息的,可以用 git reflog 查看。

7. 恢复删除(暂存区)

恢复 restore

前面说了版本回退,是针对本地库的,这里的恢复是针对暂存区的。

git restore readme.txt :将尚未加入到暂存区中的修改全部撤销,即将工作区中 readme.txt 文件的状态恢复成暂存区中 readme.txt 文件的状态

git restore --staged readme.txt: 将 readme.txt 在暂存区的当前版本回退到上一个版本。这里指的版本是在暂存区中的版本。之后再执行 git restore filename 恢复的就是暂存区中上一个版本的内容,加上 --staged 和不加的效果完全不一样

这里我是这样理解的,我们知道本地库维护着一个版本链,暂存区也维护着一个版本链,当我们将暂存区中的版本持久化到本地库中的时候,本地库的版本链才会更新。

恢复 checkout

1
2
3
4
5
6
# 恢复暂存区的指定文件到工作区
git checkout [file]
# 恢复某个 commit 的指定文件到暂存区和工作区
git checkout [commit] [file]
# 恢复暂存区的所有文件到工作区
git checkout .

移除

当我们不想让 git 管理某个文件时,只需要将它从暂存区中删除即可。

1
2
# 让 git 不要管理 readme.txt,和 restore 不一样,一个是从暂存区中删除一个是从暂存区中恢复
git rm --cached readme.txt

8. 分支操作

创建分支

切换分支的时候最好先把当前分支上的修改 commit,防止与其他分支修改产生冲突

1
2
git branch branch-name # 新建分支
git checkout -b branch_name # 新建分支,并切换到当前分支

切换分支

1
2
git checkout branch_name # 切换分支
git checkout - # 快速切换到上一个所在的分支

查看分支

1
2
3
git branch # 查看本地所有分支和当前所在分支,* 表示当前所在分支
git branch -r # -r remote 查看所有远程分支
git branch -a # -a all 查看所有分支,包括本地分支和远程分支

删除分支

1
2
git branch -d branch_name # 删除分支,要到其他分支下才能删除当前分支
git push -d origin branch_name # 删除远程分支

分支合并

比如现在在 master 分支上,要合并 dev 分支,merge 之后就会将 dev 分支合并到 master 中,默认是 fast-forward 快速合并,即直接修改 HEAD 指针指向了 dev 的最新提交。
如果 merge 的时候出现冲突(当两个分支 / 两个用户都对同一个文件进行了修改),需要手动处理冲突,然后再 git add、git commit

1
2
3
4
git merge branch_name # 本地分支与本地分支合并,将 branch_name 合并到当前分支上

# 选择一个 commit,合并进当前分支
git cherry-pick [commit]

9. 远程同步

仓库相关

1
2
git init # 在当前目录下创建一个 Git 本地仓库
git clone [url] # 将远程仓库下载到本地

将本地仓库与远程仓库关联

1
2
3
4
5
6
7
8
git remote add origin [url] # 将本地仓库与远程仓库关联,origin 就是远程仓库的别名

# 修改远程仓库地址
# 方法一:直接修改
git remote origin set-url [url]
# 方法二:先删后改
git remote rm origin
git remote add origin [url]

查看远程仓库信息

1
git remote -v

推送 push

1、将本地分支推送到远程仓库中

方式一:第一次需要加 -u,将当前所在分支和远程分支相关联,下次推送直接 git push 就可以默认推送到你刚才设置的分支上了。

1
2
git push -u origin branch_name
git push

方式二:每次都指定 origin 和 branch_name,可以推送任何分支到远程仓库

1
git push origin branch_name

2、设置本地的 branch_nam 分支对应远程仓库的 branch_name 分支

1
2
3
git push --set-upstream origin branch_name # 和 -u 参数是一样的
# 下次 push,直接
git push

3、删除远程仓库的 branch_name 分支

1
git push -d origin branch_name

强行推送当前分支到远程仓库,即使有冲突,不建议经常使用,特殊时候救急!

1
git push origin --force

拉取 pull

将远程分支拉取到本地仓库中

方式一:先将远程的 branch_name1 分支与本地的 branch_name2 分支对应。

1
git branch --set-upstream-to=origin/branch_name1 branch_name2

然后使用

1
git pull

从设置的远程分支上拉取代码,并将远程仓库的当前分支与本地仓库的当前分支合并。

方式二:指定 origin 和 branch_name,可以拉取远程任何分支上的内容到本地仓库中,并将远程仓库的 branch_name 分支与本地仓库的当前分支合并。

1
git pull origin branch_name

方式三:使用下面命令也可以将远程的 branch_name 分支拉取到本地

1
git checkout -t origin/branch_name

10. Stash 操作

Stash 是一个栈,用于存储当前工作区和暂存区还未提交的修改

应用场景:比如现在我们正在某个分支下编写代码,此时线上服务器出现了故障,领导让你赶紧去修复一下,你需要新开一个分支去解决线上的 bug,那么现在有两个选择:

  1. 将当前分支下的修改 git add、git commit,然后再去维护 bug
  2. 刚写了一点,还没实现一个完整的功能,你还不想马上就提交到本地库,此时就可以使用 Stash 将我们目前工作区和暂存区中未提交的修改添加进去。等处理完线上问题再把刚才的工作从 Stash 中弹出来继续工作~
1
2
3
4
5
git stash # 将工作区和暂存区中未提交的修改存入栈中
git stash apply # 将栈顶存储的修改恢复到当前分支,但不删除栈顶元素
git stash drop # 删除栈顶存储的修改
git stash pop # 将栈顶存储的修改恢复到当前分支,同时删除栈顶元素
git stash list # 查看栈中所有元素

参考资料

作业代码

这次作业太舒服了,one pass 很过瘾,y 总讲的太好了~

homework_0

1
2
mkdir homework
git init

homework_1

1
2
3
4
5
6
7
vim readme.txt
i
111 # 添加内容
:wq

git add .
git commit -m "111"

homework_2

1
2
3
4
5
6
7
8
vim readme.txt
G
o
222
:wq

git add .
git commit -m "222"

homework_3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir problem1 problem2
cd problem1
# 复制代码
vim main.cpp
:set paste
Shift + Insert
# 检查代码是否正确
:wq

cd problem2
# 复制代码
vim main.cpp
:set paste
Shift + Insert
# 检查代码是否正确
:wq

cd .. # 回到 homework 目录
git add .
git commit -m "add main.cpp"

homework_4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rm -r problem2
mkdir problem3
cd problem3
touch main.cpp
# 复制代码
:set paste
Shift + Insert
:wq

cd .. # 回到 homework 目录
vim readme.txt
G
dd
o
333
:wq

git add .
git commit -m "333"

homework_5

1
2
3
4
# 云端创建 homework 仓库,不要选创建生成 README.md 文件
# 复制远程仓库地址
git remote add origin git@git.acwing.com:tonngw/homework.git # 让本地与远程建立关联
git push -u origin master # 推送到远程 master 分支

homework_6

1
2
3
4
5
6
7
8
9
10
11
git checkout -b dev
vim readme.txt
G
o
444
:wq

git add .
git commit -m "444"

git push --setupstream origin dev # 将本地分支推送远程分支

homework_7

1
2
3
4
5
6
7
8
9
git checkout master
vim readme.txt
G
o
555
:wq

git add .
git commit -m "555"

homework_8

1
2
3
4
5
6
7
8
git merge dev
# 手动处理冲突,会提示 readme.txt 文件有冲突
vim readme.txt
# 删除注释
:wq

git add .
git commit -m "fix conflicts"

homework_9

1
2
3
4
git push # 将本地 master 分支推送到远程仓库
# 登录 myserver 服务器,创建文件夹
# 克隆仓库
git clone git@git.acwing.com:tonngw/homework.git

image-20220401203030239.png

Author: tonngw
Link: https://tonngw.com/2022/04/03/AcWing/第 5 讲 Git/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.