目录
- 一、分支管理
- 1.1理解分支
- 1.2创建分支
- 1.3切换分支
- 1.4合并分支
- 1.5删除分支
- 1.6合并冲突
- 1.7 分支管理策略
- 1.7.1分支策略
- 1.8bug分支
- 1.9删除临时分支
- 二、远程操作
- 2.1理解分布式版本控制系统
- 2.2 远程仓库
- 2.2.1 新建远程仓库
- 2.2.2 克隆远程仓库
- 2.2.3向远端仓库推送
- 2.2.4拉取远端仓库
- 2.3配置Git
- 2.4 命令配置别名
- 🍀小结🍀
🎉博客主页:.小智
🎉欢迎关注:👍点赞🙌收藏✍️留言
🎉系列专栏:Git企业级开发教程
🎉代码仓库:小智的代码仓库
一、分支管理
1.1理解分支
想象你正在写一本书,这本书的每一页都代表着你项目的一个版本。在Git中,每当你创建一个分支,实际上就是在书中创建了一本副本,你可以在副本中进行任何修改,而主版本则保持原样。
假设你的书的主版本(分支)是master
,表示当前的最终版本。现在,你需要写一个新的章节,但你不确定这个章节是否会被最终采纳。为了安全起见,你创建了一个名为feature-chapter
的新分支。
在feature-chapter
分支上,你可以尽情地写你的新章节,而不用担心影响到主版本(master
分支)。你可以随意增删改这个章节的内容,直到你满意为止。
如果你在写作过程中发现有一些错别字需要更正,你可以在feature-chapter
分支上进行修改,而不会影响到master
分支的内容。这就好比在新分支中进行修正,不影响到书的主体内容。
当你完成了新章节的写作,并且对其内容进行了完善,你可以将feature-chapter
分支合并回master
分支。这就好比将你的新写作整合到书的主体中,使得所有读者都可以看到你的最新内容。
最后,一旦新章节被整合到了master
分支中,你可以删除feature-chapter
分支,因为它的使命已经完成了。这就好比在完成编辑后将草稿丢弃或者存档,因为它的内容已经被整合到了正式版本中。
通过这个例子能够帮助理解Git中分支的概念:它允许你在不影响到主要项目版本的情况下进行并行开发和测试,确保你的修改在准备好之后再与主要项目整合。
- 主分支(通常是master)是项目的主要时间线。
- HEAD是指向当前所在分支的指针,它可以让你知道当前在哪个分支上工作。
每次提交,master
都会向后移动一步、这样,不断随着我们的提交,master
分支的线也越来越长,而HEAD
只要一直指向master
分支即可指向当前分支。
1.2创建分支
Git支持我们查看或创建别的分支,我们可以自己创建一个dev分支:
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch #查看当前本地所有分支
* master
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch dev #创建新的分支 dev
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch
dev
* master
创建好分支之后*
表示当前HEAD
指向的是master
分支。
ubuntu@xiaozhi:~/Desktop/gitcode$ ls .git/refs/heads/
dev master
ubuntu@xiaozhi:~/Desktop/gitcode$ cat .git/refs/heads/*
5c846bddb4d0afc3372d2de7a0b03dd490457b76
5c846bddb4d0afc3372d2de7a0b03dd490457b76
ubuntu@xiaozhi:~/Desktop/gitcode$ cat .git/HEAD
ref: refs/heads/master
两个分支指向同一个修改,但是HEAD还是指向的master分支。
画图总结:
1.3切换分支
可以使用git checkout
命令来切换当前分支
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout dev #切换到dev
切换到分支 'dev'
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch #查看当前分支
* dev
master
ubuntu@xiaozhi:~/Desktop/gitcode$ cat .git/HEAD #查看HEAD指针指向
ref: refs/heads/dev
在dev分支下提交一次修改,master分支不受影响:
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
ubuntu@xiaozhi:~/Desktop/gitcode$ echo "I am dev!" >> file1 #修改file1文件
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
ubuntu@xiaozhi:~/Desktop/gitcode$ git add . #添加到暂存区
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1" #添加到本地版本库
[dev 68054cc] md file1
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master #切换到master分支
切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 #查看file1文件并没改变
I am file1!
aaaaaaaaaaaa
查看两个分支的指向:
ubuntu@xiaozhi:~/Desktop/gitcode$ cat .git/refs/heads/dev #查看dev分支的最后一次提交
68054cc7bda01f41ff5bec07c6fe2408196e607f
ubuntu@xiaozhi:~/Desktop/gitcode$ cat .git/refs/heads/master #查看master分支的最后一次提交
5c846bddb4d0afc3372d2de7a0b03dd490457b76
可以看到两个分支指向已经不同。再来通过画图理解:
从上图可以看出,当我们切换回来master分支的时候,当然看不到dev的提交了。
1.4合并分支
为了能在master分支上看到最新的提交,就要将dev分支合并到master分支:
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch #当前处于master分支
dev
* master
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge dev #使用merge将dev合并到master分支
更新 5c846bd..68054cc
Fast-forward
file1 | 1 +
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 #dev下的提交更新到了master分支上
I am file1!
aaaaaaaaaaaa
I am dev!
git merge
命令用于合并指定分分到当前分支。合并后,master
就能看到dev
分支提交的内容了。
Fast-forward 代表“快进模式”,也就是直接把 master 指向 dev 的当前提交,所以合并速度非常快。当然,也不是每次合并都能 Fast-forward,我们后面会讲其他方式的合并。
1.5删除分支
合并完成后,dev
分支对于我们来说就没用了,那么 dev
分支就可以被删除掉。注意,如果当前正处于某分支下,就不能删除当前分支。
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch
* dev
master
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d dev
error: 无法删除检出于 '/home/ubuntu/Desktop/gitcode' 的分支 'dev'。
但是可以在别的分支区删除
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master
切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d dev
已删除分支 dev(曾为 68054cc)。
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master
分支上工作效果是一样的,但过程更安全。
1.6合并冲突
当两个分支上的修改互相冲突时,就会发生合并冲突。这时需要手动解决冲突。
实例:我们将创建一个dev1分支,将dev1中的file1
文件修改之后进行add
和commit
,然后切换到master分支,在修改master分支中file1
的内容然后再add
和commit
。
使用git checkout -b dev1
指令可以创建并切换至dev1
分支。
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout -b dev1 #创建dev1分支并切换至dev1分支
切换到一个新分支 'dev1'
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
ubuntu@xiaozhi:~/Desktop/gitcode$ echo "aaaaaa" >>file1
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
ubuntu@xiaozhi:~/Desktop/gitcode$ git add .
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1:a.."
[dev1 6a71790] add file1:a..
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master #切换至master分支
切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
ubuntu@xiaozhi:~/Desktop/gitcode$ echo "cccccccc" >>file1
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
cccccccc
ubuntu@xiaozhi:~/Desktop/gitcode$ git add .
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1: c..."
[master 7070712] md file1: c...
1 file changed, 1 insertion(+)
此时master和dev1都有了各自新的提交:
此时我们去合并两个分支就会发生冲突:
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge dev1
自动合并 file1
冲突(内容):合并冲突于 file1
自动合并失败,修正冲突然后提交修正的结果。
用vim打开file1文件来看看里面的内容:
此时我们就需要手动去调整冲突的代码,并再次提交更正后的代码!
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
ubuntu@xiaozhi:~/Desktop/gitcode$ git add .
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "merge dev1"
[master f7fe134] merge dev1
ubuntu@xiaozhi:~/Desktop/gitcode$ git status
位于分支 master
无文件要提交,干净的工作区
此时就解决完了冲突。
git log
也可以查看到分支合并的情况:
ubuntu@xiaozhi:~/Desktop/gitcode$ git log --graph --pretty=oneline --abbrev-commit
* f7fe134 (HEAD -> master) merge dev1
|\
| * 6a71790 (dev1) add file1:a..
* | 7070712 md file1: c...
|/
合并完成之后就可以删除dev1分支了
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch
dev1
* master
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d dev1
已删除分支 dev1(曾为 6a71790)。
1.7 分支管理策略
通常合并分支时,如果可以,Git会采用Fast forward
模式。
Fast forward
模式合并之后:
在这种Fast forward
模式下,删除分支之后,我们查看历史分支的时候,会丢失掉分支信息,看不出来最新的提交时merge
进来的还是正常提交的。
当有冲突时,我们解决冲突之后就会再次进行一次add
和commit
这样就不是Fast forward
模式了,这样当我们删除当时为了解决合并冲突创建的dev的分支时,查看历史分支信息,也可以看到master其实是由别的分支合并过来的。
当然Git也支持我们强制禁用Fast forward
模式,那么就是在merge的时候生成一个新的commit,这样就可以通过历史分支信息查看到分支信息。
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout -b dev2 # 切换到一个新分支 'dev2'
ubuntu@xiaozhi:~/Desktop/gitcode$ echo "a,b,c,d" >>file1
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d
ubuntu@xiaozhi:~/Desktop/gitcode$ git add .
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1" # 修改 file1
[dev2 143edf4] md file1
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master # 切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge --no-ff -m "merge dev2 noff" dev2 # 合并 dev2 分支(禁用快进模式),并添加合并注释
Merge made by the 'ort' strategy.
file1 | 1 +
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d
1.7.1分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,仅用来发布新版本,平时不能在上面工作;那么在哪里工作呢?工作都在 dev
分支上,也就是说,dev
分支是不稳定的,直到某个时候,比如 1.0 版本发布时,再将 de
分支合并到 master
上,然后在 master
分支发布 1.0 版本。
你和你的团队每个人都在 dev
分支上工作,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。
1.8bug分支
当我们在dev2分支上开发了一半的时候,突然发现master上有bug,需要解决,此时我们就需要新创建一个分支来修复bug,但是我们dev2分支在工作区开发了一半了,还无法提交,此时我们就需要用到git 给我们提供的一个隐藏功能,先将dev2工作区中修改先隐藏起来,使用命令:git stash
。
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout dev2 # 切换到分支 'dev2'
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1 # 编辑 file1 文件
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d
I am coding...
ubuntu@xiaozhi:~/Desktop/gitcode$ git status # 查看工作区状态
位于分支 dev2
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: file1
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
ubuntu@xiaozhi:~/Desktop/gitcode$ git stash # 将当前修改暂存起来
保存工作目录和索引状态 WIP on dev2: 143edf4 md file1
ubuntu@xiaozhi:~/Desktop/gitcode$ git status # 再次查看工作区状态,确认是干净的
位于分支 dev2
无文件要提交,干净的工作区
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 再次查看 file1 文件内容,确认没有修改丢失
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d
存储好dev2工作区之后再去切换到master分支,建立临时分支来修复bug:
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master # 切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout -b fix_bug # 创建并切换到一个新分支 'fix_bug'
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1 # 编辑 file1 文件,在末尾加了字母 'e'
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d,e
ubuntu@xiaozhi:~/Desktop/gitcode$ git add . # 将修改添加到暂存区
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "fix bug" # 提交修复 bug 的修改
[fix_bug 15efd2f] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master # 再次切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge --no-ff -m "merge fix_bug branch" fix_bug # 合并 fix_bug 分支到 master 分支(禁用快进模式),并添加合并注释
Merge made by the 'ort' strategy.
file1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看合并后的 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d,e
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d fix_bug # 删除已修复的 fix_bug 分支
已删除分支 fix_bug(曾为 15efd2f)。
此时bug修复完成之后再来切换回dev2分支继续开发,此时的dev2工作区是干净的,我们可以使用git stash list
查看暂存的内容。
可以使用git stash pop
命令,恢复的同时也会把stash直接删除,恢复现场也可以采用 git stash apply
恢复,但是恢复后,stash 内容并不删除,你需要用 git stash drop
来删除;
可以多次 stash,恢复的时候,先用 git stash list
查看,然后恢复指定的 stash,用命令 git stash apply stash@{0}
。
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout dev2 # 切换到分支 'dev2'
ubuntu@xiaozhi:~/Desktop/gitcode$ git status # 查看工作区状态,确认干净
位于分支 dev2
无文件要提交,干净的工作区
ubuntu@xiaozhi:~/Desktop/gitcode$ git stash list # 查看当前的 stash 列表
stash@{0}: WIP on dev2: 143edf4 md file1
ubuntu@xiaozhi:~/Desktop/gitcode$ git stash pop # 恢复最近的 stash,并删除该 stash
位于分支 dev2
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: file1
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0}(c6b089a96e51837881e27e98d98b6d6441b164c7)
ubuntu@xiaozhi:~/Desktop/gitcode$ git stash list # 再次查看 stash 列表,确认已删除
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1 # 编辑 file1 文件
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d
I am coding...Done
ubuntu@xiaozhi:~/Desktop/gitcode$ git add . # 将修改添加到暂存区
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1" # 提交修改,并添加提交注释
[dev2 ee02a85] md file1
1 file changed, 1 insertion(+)
此时各个分支的状态图:
此时master分支上的代码是要领先建立dev2分支时的提交,所以dev2中看不到master中修复的bug。
我们的目标是将 dev2
分支合并到 master
分支,通常情况下,我们会切换到 master
分支并进行合并操作。然而,这样做存在一定风险。
合并分支时可能会发生代码冲突,需要手动解决这些冲突(通常在 master
分支上进行)。由于实际项目中可能涉及到大量代码,冲突解决过程可能并不简单,可能会涉及多行甚至数百行代码。在解决冲突的过程中,难免会出现手误或误解,导致错误的代码被错误地合并到 master
分支中。
解决这个问题的一个好的建议是:最好先在自己的分支(比如 dev2
分支)上合并 master
分支,然后再让 master
分支去合并 dev2
分支。这样做的目的是,如果在合并过程中出现冲突,可以在本地分支上解决并进行测试,而不会影响到 master
分支的稳定性和代码质量。
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch # 查看当前分支状态
* dev2
master
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge master # 合并 master 分支到当前分支(dev2 分支)
自动合并 file1
冲突(内容):合并冲突于 file1
自动合并失败,修正冲突然后提交修正的结果。
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1 # 解决冲突后编辑 file1 文件
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d,e
I am coding...Done
ubuntu@xiaozhi:~/Desktop/gitcode$ git add . # 将解决冲突后的文件添加到暂存区
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "merge master" # 提交合并后的修改,并添加提交注释
[dev2 c00519f] merge master
ubuntu@xiaozhi:~/Desktop/gitcode$ git status # 查看当前分支状态
位于分支 dev2
无文件要提交,干净的工作区
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master # 切换到 master 分支
切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ git merge --no-ff -m "merge dev2" dev2 # 合并 dev2 分支到 master 分支,禁用快进模式,并添加合并注释
Merge made by the 'ort' strategy.
file1 | 1 +
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/gitcode$ git status # 查看当前分支状态
位于分支 master
无文件要提交,干净的工作区
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d,e
I am coding...Done
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d dev2 # 删除已合并的 dev2 分支
已删除分支 dev2(曾为 c00519f)。
1.9删除临时分支
在软件开发中,随着不断添加新功能,我们通常希望能够在不影响主分支稳定性的情况下进行开发。每次添加新功能时,最好新建一个专门的分支,通常称为 feature
分支,在该分支上进行开发,开发完成后再合并回主分支,最后删除该 feature
分支。
然而,有时候在某个 feature
分支上开发了一半的功能,突然被产品经理叫停,需要立即停止该功能的开发。尽管该功能未完成,但是这个 feature
分支仍然需要立即删除,因为保留它已经没有意义了。这时候使用传统的 git branch -d
命令删除分支是不可行的。
这里的指令和注释,模拟了上述过程:
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout -b dev3 # 创建并切换到一个新分支 'dev3'
切换到一个新分支 'dev3'
ubuntu@xiaozhi:~/Desktop/gitcode$ vim file1 # 编辑 file1 文件,添加新功能的代码
ubuntu@xiaozhi:~/Desktop/gitcode$ cat file1 # 查看 file1 文件内容,确认修改
I am file1!
aaaaaaaaaaaa
I am dev!
aaaaaa
cccccccc
a,b,c,d,e
I am coding...Done
I am coding... dev3
ubuntu@xiaozhi:~/Desktop/gitcode$ git add . # 将修改后的文件添加到暂存区
ubuntu@xiaozhi:~/Desktop/gitcode$ git commit -m "md file1 for new features" # 提交修改,添加提交注释
[dev3 7bffbbd] md file1 for new features
1 file changed, 1 insertion(+)
#新功能叫停
ubuntu@xiaozhi:~/Desktop/gitcode$ git checkout master # 切换回 'master' 分支
切换到分支 'master'
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -d dev3 # 尝试删除 'dev3' 分支(未合并时)
error: 分支 'dev3' 没有完全合并。
如果您确认要删除它,执行 'git branch -D dev3'。
ubuntu@xiaozhi:~/Desktop/gitcode$ git branch -D dev3 # 强制删除 'dev3' 分支
已删除分支 dev3(曾为 7bffbbd)。
ubuntu@xiaozhi:~/Desktop/gitcode$
这段操作模拟了在 dev3
分支上开发新功能并提交后,尝试删除未合并的分支时出现的情况。因为 dev3
分支中的修改还未合并到 master
分支,所以需要使用 -D
参数强制删除该分支。
二、远程操作
2.1理解分布式版本控制系统
-
每个开发者都拥有完整的仓库副本: 在Git中,每个开发者克隆(clone)的不仅是项目的一个工作副本,而是整个仓库的完整副本,包括所有历史记录、分支和标签。这意味着每个开发者都可以在本地进行大部分的版本控制操作,而无需持续与中央服务器进行通信。
-
本地操作和快速性: Git允许开发者在本地快速执行版本控制操作,如提交(commit)、查看历史(log)、比较差异(diff)等,这些操作不会受到网络延迟的影响。开发者可以频繁地提交代码,记录项目的演变过程。
-
强大的分支管理: Git的分支功能极为强大和灵活,开发者可以轻松地创建、切换、合并和删除分支,而这些操作都是本地执行的。每个分支都是一个独立的实体,允许开发者在不同的功能或实验性质的工作之间进行切换,而不会干扰主分支或其他开发者的工作。
-
安全性和备份: 每个开发者都拥有一个完整的本地备份,这使得Git在灾难恢复和版本回滚方面非常强大。即使中央服务器出现故障或网络中断,开发者仍然可以继续工作,并且可以通过其他开发者的仓库进行恢复。
-
分布式协作和开发模型: Git的设计使得分布式团队能够高效协作。开发者可以通过推送(push)和拉取(pull)操作与其他仓库进行同步,分享自己的代码变更。这种方式不仅支持多人同时开发,还有助于避免单点故障和集中式系统的瓶颈问题。
Git作为分布式版本控制系统,通过其强大的分支管理、本地操作和每个开发者都拥有完整副本的特性,使得团队能够更加灵活和高效地进行协作,同时保证了代码的安全性和稳定性。这种设计理念和架构使Git成为当今软件开发行业中最流行和广泛使用的版本控制系统之一。
2.2 远程仓库
Git是一种分布式版本控制系统,这意味着同一个Git仓库可以分布到不同的机器上。最初,通常只有一台机器有一个原始版本库,其他机器可以通过“克隆”这个原始版本库来获取完全相同的版本库副本,没有主次之分。
即使只有一台电脑,也可以在不同的目录下克隆多个版本库。然而,在实际生活中,很少有人会在同一台电脑上管理多个远程库,因为这样做没有意义,而且如果硬盘出现问题,会导致所有库都受影响。因此,一般情况下,会选择一台电脑作为服务器角色,24小时开机,其他人从这个“服务器”仓库克隆一份到自己的电脑上,并将各自的提交推送到服务器仓库,也从服务器仓库中获取其他人的提交。
可以自己搭建运行Git的服务器,不过在学习Git的初期,为了简化流程,搭建服务器可能显得有些繁琐。这时,GitHub这个网站就显得非常有用了。GitHub提供Git仓库的托管服务,注册一个GitHub账号后,可以免费获得Git远程仓库,方便进行代码管理和团队协作。
2.2.1 新建远程仓库
- 新建仓库
- 填写仓库信息
- 创建成功
- 刚创建的仓库有且只有⼀个默认的
master/main
分支
2.2.2 克隆远程仓库
克隆/下载远端仓库到本地,需要使用git clone 命令,后面跟上我们的远端仓库的链接,远端仓库的链接可以从仓库中找到:选择“克隆/下载”获取远程仓库链接:
SSH协议和HTTPS协议是Git最常用的两种数据传输协议。
SSH协议利用公钥加密和公钥登录机制,具备较高的实用性和安全性。使用SSH协议时,需要在Git服务器上配置和管理公钥。用户通过生成一对公钥和私钥,将公钥添加到Git服务器的账户中,这样就可以使用私钥进行认证和数据传输。SSH协议的优点是安全性高,传输过程中数据加密,适合需要保护代码安全的环境。
HTTPS协议则相对简单,使用起来不需要额外的配置。可以直接通过克隆URL来获取代码,不涉及公钥和私钥的管理。HTTPS协议适合简单的开发和个人项目,不需要复杂的认证过程。
- 使用HTTPS方式:
ubuntu@xiaozhi:~/Desktop/test$ git clone https://github.com/XZ293/git_test.git
正克隆到 'git_test'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
接收对象中: 100% (3/3), 完成.
ubuntu@xiaozhi:~/Desktop/test$ ls
git_test
ubuntu@xiaozhi:~/Desktop/test$ ls git_test/
README.md
- 使用SSH方式:
ubuntu@xiaozhi:~/Desktop/test$ git clone git@github.com:XZ293/git_test.git
正克隆到 'git_test'...
The authenticity of host 'github.com (20.205.243.166)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: 无法读取远程仓库。
请确认您有正确的访问权限并且仓库存在。
使用SSH
方式克隆仓库,由于我们没有添加公钥到远端库中,服务器拒绝了我们的clone
链接。需要我们设置一下:
-
第一步:检查是否已经有SSH Key
- 打开终端。
- 输入以下命令查看是否已经存在.ssh目录和相应的密钥文件:
ls -al ~/.ssh
如果已经存在
id_rsa
和id_rsa.pub
这两个文件,则可以直接跳到下一步。 -
第二步:创建SSH Key(如果不存在)
如果在.ssh目录下没有找到
id_rsa
和id_rsa.pub
文件,需要生成SSH Key:- 在终端中执行以下命令:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
-t rsa
指定生成RSA密钥。-b 4096
指定密钥长度为4096位(更安全的选项,也可以选择2048位)。-C "your_email@example.com"
是一个注释,用来标识该密钥,可以填写你的邮箱地址或其他标识。
-
按照提示,在默认的.ssh目录中保存生成的密钥文件。可以选择保持默认路径和文件名,也可以根据需要修改保存路径和文件名。
-
如果需要设置密码保护密钥(推荐),会提示输入密码和确认密码。
- 第三步:添加SSH公钥到远程Git仓库
添加之后就可以直接去clone了。
ubuntu@xiaozhi:~/Desktop/test$ git clone git@github.com:XZ293/git_test.git
正克隆到 'git_test'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
接收对象中: 100% (3/3), 完成.
ubuntu@xiaozhi:~/Desktop/test$ ls
git_test
ubuntu@xiaozhi:~/Desktop/test$ ls git_test/
README.md
done,成功!如果有多个人协作开发,GitHub/Gitee允许添加多个公钥,只要把每个人的电脑上的Key都添加到GitHub/Gitee,就可以在每台电脑上往GitHub/Gitee上提交推送了。
当我们从远程仓库克隆一个Git仓库后,Git会自动将本地的master
分支(或更新后的默认分支名,如main
)与远程仓库的相应分支(在旧版本Git中为master
)建立跟踪关系,并将远程仓库的名称默认为origin
。在本地,我们可以通过执行git remote
命令来查看远程仓库的信息,包括其名称;若要查看远程仓库的详细信息,包括远程分支列表,可以使用git remote -v
命令。
ubuntu@xiaozhi:~/Desktop/test$ cd git_test/
ubuntu@xiaozhi:~/Desktop/test/git_test$ git remote
origin
ubuntu@xiaozhi:~/Desktop/test/git_test$ git remote -v
origin git@github.com:XZ293/git_test.git (fetch)
origin git@github.com:XZ293/git_test.git (push)
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
2.2.3向远端仓库推送
我们可以在clone到本地的仓库中新建一个文件file.txt并写入数据,提交时候要注意必须设置邮箱和用户名称。否则会报错。
将本地仓库修改推送至远端的指令:
git push <远程主机名> <本地分⽀名>:<远程分⽀名>
# 如果本地分⽀名与远程分⽀名相同,则可以省略冒号:
git push <远程主机名> <本地分⽀名>
git push <远程主机名> <本地分⽀名>:<远程分⽀名>
# 如果本地分⽀名与远程分⽀名相同,则可以省略冒号:
git push <远程主机名> <本地分⽀名>
这里由于我们使用的是SSH协议,是不用每⼀次推送都输入密码的,方便了我们的推送操作。如果你使用的是HTTPS协议,有个麻烦地方就是每次推送都必须输入口令。
此时远端可以看到也已经更新到最新了。
2.2.4拉取远端仓库
我们来编辑远端仓库中的file.txt然后推送提交。再通过本地将远端的改动拉取下来:
从远端向本地拉取的指令:
git pull <远程主机名> <远程分⽀名>:<本地分⽀名>
# 如果远程分⽀是与当前分⽀合并,则冒号后⾯的部分可以省略。
git pull <远程主机名> <远程分⽀名>
ubuntu@xiaozhi:~/Desktop/test/git_test$ git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
展开对象中: 100% (3/3), 1.03 KiB | 1.03 MiB/s, 完成.
来自 github.com:XZ293/git_test
* branch master -> FETCH_HEAD
cdb1578..adc5d68 master -> origin/master
更新 cdb1578..adc5d68
Fast-forward
file.txt | 1 +
1 file changed, 1 insertion(+)
ubuntu@xiaozhi:~/Desktop/test/git_test$ cat file.txt
hello git
远端修改模拟需要拉取代码(日常切忌不能在远端直接对文件进行操作)!!!!!!
2.3配置Git
在日常开发中,我们有些文件不想或者不应该提交到远端,比如保存了数据库密码的配置文件,那怎么让Git知道呢?在Git⼯作区的根目录下创建⼀个特殊的 .gitignore 文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件了。
当时创建仓库的时候就可以直接选择对应的.gitignore文件模板:
如果当时没有选择这个选择,在工作区创建⼀个也是可以的。无论哪种方式,最终都可以得到一个完整的 .gitignore
文件,例如我们想忽略以.so
和.ini
结尾所有文件,.gitignore
的内容
# 省略选择模本的内容
...
# My configurations:
*.ini
*.so
创建好之后就可以把文件推送到本远端仓库了。
ubuntu@xiaozhi:~/Desktop/test/git_test$ vim .gitignore
ubuntu@xiaozhi:~/Desktop/test/git_test$ cat .gitignore
# 省略选择模板的内容
...
# My configurations
*.ini
*.so
ubuntu@xiaozhi:~/Desktop/test/git_test$ git add .
ubuntu@xiaozhi:~/Desktop/test/git_test$ git commit -m "add .gitignore"
[master 85fda93] add .gitignore
1 file changed, 8 insertions(+)
create mode 100644 .gitignore
ubuntu@xiaozhi:~/Desktop/test/git_test$ git push
枚举对象中: 4, 完成.
对象计数中: 100% (4/4), 完成.
使用 2 个线程进行压缩
压缩对象中: 100% (3/3), 完成.
写入对象中: 100% (3/3), 384 字节 | 384.00 KiB/s, 完成.
总共 3(差异 0),复用 0(差异 0),包复用 0
To github.com:XZ293/git_test.git
adc5d68..85fda93 master -> master
我们在本地创建两个被忽略的文件,再来查看仓库状态
ubuntu@xiaozhi:~/Desktop/test/git_test$ touch aaa.so
ubuntu@xiaozhi:~/Desktop/test/git_test$ touch bbb.ini
ubuntu@xiaozhi:~/Desktop/test/git_test$ git status
位于分支 master
您的分支与上游分支 'origin/master' 一致。
无文件要提交,干净的工作区
此时这两个文件是无法被git管理的,也可以通过-f
选项强制添加:
git add -f [filename]
也可以通过git check-ignore -v [filename]
来查看文件被.gitignore
文件的哪一个规则忽略:
ubuntu@xiaozhi:~/Desktop/test/git_test$ git check-ignore -v aaa.so
.gitignore:7:*.so aaa.so
设置了排除规则,也可以单独设立不排除满足规则的某个文件:
# 排除所有.开头的隐藏⽂件:
.*
# 不排除.gitignore
!.gitignore
#把指定文件排除在 .gitignore 规则外的写法就是 ! +文件名
2.4 命令配置别名
Git也给我们提供了给指令起别名的功能。
比如要将git status
起别名为git st
:
ubuntu@xiaozhi:~/Desktop/test/git_test$ git config --global alias.st status
ubuntu@xiaozhi:~/Desktop/test/git_test$ git st
位于分支 master
您的分支与上游分支 'origin/master' 一致。
无文件要提交,干净的工作区
--global
参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。如果不加,那只针对当前的仓库起作用。
ubuntu@xiaozhi:~/Desktop/test/git_test$ git config --global alias.last 'log -1'
ubuntu@xiaozhi:~/Desktop/test/git_test$ git last
commit 85fda93cabce0659098f39e3665dde526ecd0c59 (HEAD -> master, origin/master, origin/HEAD)
Author: 小智 <2935117143@qq.com>
Date: Tue Aug 6 09:35:23 2024 +0800
add .gitignore
🍀小结🍀
今天我们学习了"Git分支管理、远程操作
相信大家看完有一定的收获。种一棵树的最好时间是十年前,其次是现在!
把握好当下,合理利用时间努力奋斗,相信大家一定会实现自己的目标!加油!创作不易,辛苦各位小伙伴们动动小手,三连一波💕💕~~~
,本文中也有不足之处,欢迎各位随时私信点评指正!