为什么需要Git
大家一定有过这样的经历,在写论文的时候,由于各种各样的原因,改了又改,改了又改,每次的版本又需要留个底备用,于是便有了如下情况:
由于我们对论文的多次版本迭代,产生了大量的文件,最终,我们只会选取一份最终的文件提交。同时为了记录版本的迭代历史,以及随时回滚到之前的版本,实现回溯,我们需要一个版本控制工具。当然,这份论文也许是由多个小伙伴一起完成的,那么就需要多人同时进行编辑,最终的结果又要汇总到一个地方,并且能够解决出现的冲突,也就是说,我们需要一个分布式的版本控制工具,对于代码而言,更是如此,而Git,正是解决这种问题的一个工具。
什么是Git
git是一个分布式版本控制软件,最初由林纳斯·托瓦兹创作,于2005年以GPL许可协议发布。最初目的是为了更好地管理Linux内核开发而设计。(Wikipedia)
首先放出一张图,有助于后面理解Git里面的各种概念:
可以看到,它大致分为4个板块:
- 工作目录:存放我们正在写的代码(当我们新版本开发完成之后,就可以进行新版本的提交)
- 暂存区:暂时保存待提交的内容(新版本提交后会存放到本地仓库)
- 本地仓库:位于我们电脑上的一个版本控制仓库(存放的就是当前项目各个版本代码的增删信息)
- 远程仓库:位于服务器上的版本控制仓库(服务器上的版本信息可以由本地仓库推送上去,也可以从服务器抓取到本地仓库)
快速开始
官方文档
更详细的教程可以到官方文档查询学习,本文仅用于快速入门
《Pro Git》:https://git-scm.com/book/zh/v2
安装git
下载地址:https://git-scm.com/download
选择你使用的系统并安装之,安装过程略
接下来本文将以Windows 11为例,所有命令将在 git bash
中进行
设置你的用户名和邮箱
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
初始化仓库
在任意文件夹下执行:
git init
这一步将会在当前目录下生成一个 .git
目录,该目录是隐藏目录,包含了这个仓库的所有信息
添加到暂存区
在当前目录下新建一个 hello.txt
文件夹,并随便编辑后保存
执行如下:
git add hello.txt
当然,如果有多个文件,可以执行如下命令,将会把当前目录下所有文件都放入暂存区
git add .
执行后,hello.txt
文件就被添加到了暂存区
提交
git commit -m 'First commit'
执行后,得到如下提示,hello.txt
文件就被添加到了本地仓库
[master (root-commit) a7e0219] First commit
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
其中:First commit
表示当前 commit
的信息,用于简单描述提交的内容
查看提交记录
git log #查看提交记录
git log --graph #以 ASCII 图形显示提交记录
git log --graph --oneline #以 ASCII 图形显示提交记录,并且每条记录一行显示
$ git log
commit a7e02198703e06bcbe786e59e85cc57aa750fa3a (HEAD -> master)
Author: kakkk <kakkk@live.com>
Date: Sat Jan 15 22:27:41 2022 +0800
First commit
$ git log --graph
* commit a7e02198703e06bcbe786e59e85cc57aa750fa3a (HEAD -> master)
Author: kakkk <kakkk@live.com>
Date: Sat Jan 15 22:27:41 2022 +0800
First commit
$ git log --graph --oneline
* a7e0219 (HEAD -> master) First commit
回滚
仓库提交记录如下:
* 2bc7ac9 (HEAD -> master) Second commit
* a7e0219 First commit
如果我们需要回滚到 a7e0219
分支,执行如下命令:
git reset --hard a7e0219
其中:--hard
表示回滚的模式,a7e0219
表示commit的ID
关于回滚的模式,具体可到官方文档了解:https://git-scm.com/docs/git-reset/en
分支管理
看到这里,你已经完成了最基本的操作,接下来,我们来了解下GIt的分支管理
首先我们来查看下当前分支:
git branch
一般情况下,git默认创建的是 master
分支
本文将涉及以下几个操作:
- 创建分支
- 合并分支
- 变基分支
- 优选
创建分支
git branch test #创建名为test的分支
git branch -d test #删除名为test的分支
切换分支,也叫签出(checkout)
git checkout test
添加文件并提交:
git add BranchTest.txt
git commit -m 'commited by test'
查看当前记录:
$ git log --all --graph --oneline
* d269daa (HEAD -> test) commited by test
* 2bc7ac9 (master) Second commit
* a7e0219 First commit
合并分支
首先我们回到 master
分支
git checkout master
合并分支
git merge test
如果没有冲突,将会自动完成分支的合并:
Updating 2bc7ac9..d269daa
Fast-forward
BranchTest.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 BranchTest.txt
如果存在冲突,则需要先进行冲突的解决
解决冲突
首先我们需要制造冲突,很简单,同时在两个分支修改同一个文件并提交即可
制造冲突后,分支情况如下:
$ git log --all --graph --oneline
* 99e8b90 (test) update hello by test
| * 63244d2 (HEAD -> master) update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
此时,回到 master
分支,合并 test
分支,会得到如下的提示“
$ git merge test
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
打开 hello.txt
,内容如下:
<<<<<<< HEAD
hello master
=======
hello test
>>>>>>> test
在Git中,使用 <<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,这里我们采纳两个分支的内容,也就是把 hello.txt
修改成如下:
hello master
hello test
当然,也可以不采纳 test
分支的提交,也就是把 hello test
删掉,具体怎么处理冲突需要看实际需求,这里只做演示
修改好之后,进行一次 commit
:
git add hello.txt
git commit -m 'merge on conflict'
重新查看分支情况:
$ git log --all --graph --oneline
* c0b47bf (HEAD -> master) merge on conflict
|\
| * 99e8b90 (test) update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
发现合并已完成
变基分支
所谓变基分支,就是修改分支的开始位置
比如,当前我正在 test
分支写代码,而 master
分支更新了一个文件,恰好我需要这份文件的更改,我就可以将我的 test
分支开始的位置定位到 master
分支最新的位置。
说起来比较抽象,举个例子:
首先在 master
新建一个 aaa.txt
并提交,切换到 test
分支,新建一个 bbb.txt
并提交
查看当前分支情况:
$ git log --all --graph --oneline
* 9b9cfae (HEAD -> test) add bbb.txt
| * c37cf6b (master) add aaa.txt
| * c0b47bf merge on conflict
| |\
| |/
|/|
* | 99e8b90 update hello by test
| * 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
可以看到,test分支的开始位置在 99e8b90
,此时,我们需要 master
分支中的 bbb.txt
,但是又不想合并,我们可以使用变基分支进行操作:
git rebase master
重新查看分支情况:
$ git log --all --graph --oneline
* f3d4f66 (HEAD -> test) add bbb.txt
* c37cf6b (master) add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
此时,目录下已经出现了 aaa.txt
优选
优选,即 charrypick
操作,可以单独合并某一次提交,比如,在 master
分支中,其他人创建了 ccc.txt
和 ddd.txt
文件,此时,我只需要 ddd.txt
文件,并不需要 ccc.txt
文件,并且我既不想进行分支合并,也不想进行分支变基,这个时候,就可以使用优选操作。
首先当然是在 master
分支中创建并提交 ccc.txt
和 ddd.txt
文件,此时,分支情况如下:
$ git log --all --graph --oneline
* 6fb1632 (HEAD -> master) add ddd
* a4e8ed0 add ccc
| * f3d4f66 (test) add bbb.txt
|/
* c37cf6b add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
切换到 test
分支,进行优选操作:
git cherry-pick 6fb1632
其中,6fb1632
表示需要优选的commit ID
查看分支情况:
$ git log --all --graph --oneline
* f17beb6 (HEAD -> test) add ddd
* f3d4f66 add bbb.txt
| * 6fb1632 (master) add ddd
| * a4e8ed0 add ccc
|/
* c37cf6b add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
远程仓库
远程仓库,可以理解为位于远程服务器的仓库,可以实现多人合作进行项目开发。
远程仓库有公有的,也有私有的,共有仓库有Github、Gitee、Coding等,私有的一般使用Gitlab进行搭建,在公司中,一般使用私有仓库,只对公司内部开放
本文以Github为例,因此需要先注册一个Github账号。
创建远程仓库
在Github中,找到New Repository选项,填写你的仓库地址和名称,设置成共有或私有,点击创建即可
添加远程仓库并推送
接下来,复制你的仓库地址:
回到你的仓库中,添加仓库地址:
git remote add origin git@github.com:kakkk/test.git
其中,origin
为远程仓库名称,git@github.com:kakkk/test.git
为远程仓库地址
添加身份验证
这里可以使用SSH,也可以使用token进行身份验证,本文使用SSH的方式
首先,在本地生成一个rsa公钥
ssh-keygen -t rsa
一路回车,最后将会提示你在User目录生成了你的公钥和私钥
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/kakkk/.ssh/id_rsa):
Created directory '/c/Users/kakkk/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/kakkk/.ssh/id_rsa
Your public key has been saved in /c/Users/kakkk/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:L72E1ARiVnog33fcNBd6KPn1KZvBxQkLq6azeOXGlU0 kakkk@kakkk-VM
The key's randomart image is:
+---[RSA 3072]----+
| . =.o . .o.o|
| = = . .+o*o.|
| o o o+o+.* |
| . +..+E+ o|
| So. += ..|
| .o= o .= |
| o* = o |
| ..o* . |
| .... . |
+----[SHA256]-----+
接下来,用记事本或任一文本编辑器打开你的公钥,即 id_rsa.pub
打开Github,点击头像,Setting
选择右侧的 SSH and GPG keys
,点击 New SSH key
将刚刚得到的公钥复制到里面,添加即可
添加完成后,使用如下命令测试以下:
ssh -T git@github.com
输入 yes
,回车,出现如下内容说明连接成功:
Hi kakkk! You've successfully authenticated, but GitHub does not provide shell access.
推送
搞定了身份验证,就可以推送到远程仓库了
git push origin master
$ git push origin master
Enumerating objects: 26, done.
Counting objects: 100% (26/26), done.
Delta compression using up to 4 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (26/26), 1.97 KiB | 336.00 KiB/s, done.
Total 26 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), done.
To github.com:kakkk/test.git
* [new branch] master -> master
查看远程仓库:
克隆项目
就是把远程仓库的项目克隆下来:
git clone 远程仓库地址
抓取/拉取项目
当其他同学在这个仓库修改了代码之后,你需要将它抓取或拉取下来,抓取和拉取的区别:
- 抓取(fetch):只获取远程仓库分支,不进行自动合并,需要手动合并才能提交
- 拉去(pull):获取并自动合并远程分支
方法如下:
git fetch origin
git pull origin
抓取
比如,在github上面在线编辑以下 hello.txt
文件,抓取远程分支:
$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 641 bytes | 49.00 KiB/s, done.
From https://github.com/kakkk/test
2e0c4ee..0251187 master -> origin/master
查看分支结构:
$ git log --all --graph --oneline
* 0251187 (origin/master) Update hello.txt
* 2e0c4ee (HEAD -> master) Merge branch 'test' merge test
|\
| * f17beb6 (test) add ddd
| * f3d4f66 add bbb.txt
* | 6fb1632 add ddd
* | a4e8ed0 add ccc
|/
* c37cf6b add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
合并分支:
$ git merge origin/master
Updating 2e0c4ee..0251187
Fast-forward
hello.txt | 1 +
1 file changed, 1 insertion(+)
拉取
同样的,我们在远程再次修改文件,本地拉取并查看分支情况:
$ git pull origin master
From https://github.com/kakkk/test
* branch master -> FETCH_HEAD
Updating 0251187..8685ea1
Fast-forward
aaa.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --all --graph --oneline
* 8685ea1 (HEAD -> master, origin/master) Update aaa.txt
* 0251187 Update hello.txt
* 2e0c4ee Merge branch 'test' merge test
|\
| * f17beb6 (test) add ddd
| * f3d4f66 add bbb.txt
* | 6fb1632 add ddd
* | a4e8ed0 add ccc
|/
* c37cf6b add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
处理冲突
处理远程仓库冲突的流程和本地仓库合并时处理冲突的流程差不多
这里我们同样在本地和远程修改 bbb.txt
制造冲突方便演示
拉取仓库:
$ git pull origin master
From https://github.com/kakkk/test
* branch master -> FETCH_HEAD
Auto-merging bbb.txt
CONFLICT (content): Merge conflict in bbb.txt
Automatic merge failed; fix conflicts and then commit the result.
不出意外,它会提示冲突,这时候我们打开 bbb.txt
对冲突进行处理,然后提交,查看分支情况:
$git add bbb.txt
$ git commit -m 'merge origin and fix conflict'
[master abec189] merge origin and fix conflict
$ git log --all --graph --oneline
* abec189 (HEAD -> master) merge origin and fix conflict
|\
| * 8c30158 (origin/master) Update bbb.txt
* | 1d38a3b update bbb by local
|/
* 8685ea1 Update aaa.txt
* 0251187 Update hello.txt
* 2e0c4ee Merge branch 'test' merge test
|\
| * f17beb6 (test) add ddd
| * f3d4f66 add bbb.txt
* | 6fb1632 add ddd
* | a4e8ed0 add ccc
|/
* c37cf6b add aaa.txt
* c0b47bf merge on conflict
|\
| * 99e8b90 update hello by test
* | 63244d2 update hello by master
|/
* d269daa commited by test
* 2bc7ac9 Second commit
* a7e0219 First commit
总结时间
至此,我们的Git从入门到入门已经结束,恭喜看到这里的你成功入门。本文偏入门,因此Git的一些其他操作以及本文没有讲到的东西,还需要查阅文档才能使用,但是学到这里,应该已经能够掌握Git的基本使用了。
当然,很多IDE的自带的Git图形化界面相当好用,我也在用,学习Git命令时为了更好地使用图形化界面,毕竟你得了解Git是怎样的一个流程嘛。
好了就这么多,这篇文章居然写了我一个晚上,唉,我还是菜。