Git
以下内容为对https://www.bilibili.com/video/BV1MU4y1Y7h5/?vd_source=d57b2df928037367dfb7f5027819b5ec视频以及https://www.runoob.com/git/git-tutorial.html教程的整理
0. 配置
超级详细:https://blog.csdn.net/mukes/article/details/115693833?spm=1001.2014.3001.5506
1. 概述
1.1 开发中的实际场景
- 备份
- 代码还原
- 协同开发
- 追溯问题代码的编写人员和时间
1.2 版本控制器的方式
- 集中式
- 版本库是集中存放在中央服务器的,team里每个人work时从中央服务器下载代 码,是必须联网才能工作,局域网或互联网。个人修改后然后提交到中央版本库。
- 举例:SVN和CVS
- 分布式
- 每个人的电脑上都是一个完整的版本库,这样工作的时候,无需要联网了,因为版本库就在你自己的电脑上。多人协作只需要各自的修改推送给对方,就能互相看到对方的修改了。
- 举例:Git
1.3 Git 工作流程
Git是分布式的,Git不需要有中心服务器,我们每台电脑拥有的东西都是一样的。我们使用Git并且有个 中心服务器,仅仅是为了方便交换大家的修改,但是这个服务器的地位和我们每个人的PC是一样的。我们可以 把它当做一个开发者的pc就可以就是为了大家代码容易交流不关机用的。没有它大家一样可以工作,只不 过“交换”修改不方便而已。
命令如下:
- clone(克隆):从远程仓库中克隆代码到本地仓库
- checkout(检出):从本地仓库中检出一个仓库分支然后进行修订
- add(添加):在提交前先将代码提交到暂存区
- commit(提交):提交到本地仓库。本地仓库中保存修改的各个历史版本
- fetch(抓取):从远程库抓取到本地仓库,不进行任何的合并操作,一般操作比较少
- pull(拉取):从远程库拉到本地仓库,自动进行合并(merge),然后放到工作区,相当于fetch+merge
- push(推送):修改完成后,需要和团队成员共享代码时,将代码推送到远程仓库
2. Git 常用命令
2.1 Git 工作区、暂存区和版本库
基本概念
- 工作区:本地电脑能看到的目录
- 暂存区:stage/index,一般存放在
.git
目录下的 index 文件中,有时也叫做索引 - 版本库:工作区有一个隐藏目录
.git
,这个不算工作区,而是 Git 的版本库
关系
![image-20230424085856265](https://i-blog.csdnimg.cn/blog_migrate/cdeea1de3e961f2575264434f7cad682.png)
- 图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage/index),标记为 “master” 的是 master 分支所代表的目录树
- 图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。
- 当对工作区修改(或新增)的文件执行
git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。 - 当执行提交操作
git commit
时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。 - 当执行
git reset HEAD
命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。 - 当执行
git rm --cached <file>
命令时,会直接从暂存区删除文件,工作区则不做出改变。 - 当执行
git checkout .
或者git checkout -- <file>
命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。 - 当执行
git checkout HEAD .
或者git checkout HEAD <file>
命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
2.2 创建仓库
git init
在执行完成 git init
命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。
-
使用当前目录作为 Git 仓库
git init
-
指定目录作为 Git 仓库
git init newrepo
-
当前目录下有几个文件想要纳入版本控制
需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交$ git add *.c $ git add README $ git commit -m '初始化项目版本'
以上命令将目录下以 .c 结尾及 README 文件提交到仓库中。
注: 在 Linux 系统中,commit 信息使用单引号 ',Windows 系统,commit 信息使用双引号 "。
所以在 git bash 中 git commit -m ‘提交说明’ 这样是可以的,在 Windows 命令行中就要使用双引号 git commit -m “提交说明”。
git clone
我们使用 git clone
从现有 Git 仓库中拷贝项目
-
克隆仓库
git clone <repo>
-
克隆到指定的目录
git clone <repo> <directory>
-
参数说明:
- repo: Git 仓库。
- directory: 本地目录。
配置
git 的设置使用 git config
命令。
显示当前的 git 配置信息:
$ git config --list
credential.helper=osxkeychain
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
编辑 git 配置文件:
$ git config -e # 针对当前仓库
或者:
$ git config -e --global # 针对系统上所有仓库
设置提交代码时的用户信息:
$ git config --global user.name 'hhq'
$ git config --global user.email test@163.com
如果去掉 –global 参数只对当前仓库有效。
2.3 基础操作指令
Git工作目录下对于文件的修改(增加、删除、更新)会存在几个状态,这些修改的状态会随着我们执行Git 的命令而发生变化。
git status
命令用于查看项目的当前状态
通常我们使用 -s 参数来获得简短的输出结果:git status -s
git add
将该文件添加到暂存区
-
添加一个或多个文件:
git add [file1] [file2] ...
-
添加指定目录,包括子目录:
git add [dir]
-
添加当前目录下的所有文件:
git add .
-
添加本地工作区的所有修改:
git add --all
以下实例我们添加两个文件:
$ touch README # 创建文件
$ touch hello.php # 创建文件
$ ls
README hello.php
$ git status -s # 查看项目的当前状态
?? README
?? hello.php
$ git add README hello.php # 添加文件
$ git status -s
A README
A hello.py
现在我们修改 README 文件:
$ vim README
在 README 添加以下内容:# Git 测试,然后保存退出。
再执行一下 git status:
$ git status -s
AM README
A hello.py
AM
状态的意思是这个文件在我们将它添加到缓存之后又有改动。改动后我们再执行 git add . 命令将其添加到缓存中:
$ git add .
$ git status -s
A README
A hello.py
文件修改后,我们一般都需要进行 git add 操作,从而保存历史版本。
git commit
我们使用 git add
命令将内容写入暂存区。git commit
命令将暂存区内容添加到本地仓库中。
-
提交暂存区到本地仓库中:
git commit -m [message]
[message] 可以是一些备注信息。 -
提交暂存区的指定文件到仓库区:
git commit [file1] [file2] ... -m [message]
-
-a 参数设置修改文件后不需要执行 git add 命令,直接来提交
git commit -a
在提交代码开始前我们需要先设置提交的用户信息,包括用户名和邮箱:
$ git config --global user.name 'hhq'
$ git config --global user.email test@163.com
如果去掉 --global 参数只对当前仓库有效。
接下来我们就可以对 hello.py 的所有改动从暂存区内容添加到本地仓库中。
以下实例,我们使用 -m 选项以在命令行中提供提交注释。
$ git add hello.php
$ git status -s
A README
A hello.py
$ git commit -m '第一次版本提交'
[master (root-commit) 04d4b8e] 第一次版本提交
2 files changed, 1 insertion(+)
create mode 100644 README
create mode 100644 hello.py
现在我们已经记录了快照。如果我们再执行 git status:
$ git status
# On branch master
nothing to commit (working directory clean)
以上输出说明我们在最近一次提交之后,没有做任何改动,是一个 “working directory clean”,翻译过来就是干净的工作目录。
如果你觉得 git add 提交缓存的流程太过繁琐,Git 也允许你用 -a 选项跳过这一步。命令格式如下:
git commit -a
我们先修改 hello.py文件为以下内容:
print('hello git')
再执行以下命令:
$ git commit -am '修改 hello.py 文件'
[master db9828a] 修改 hello.py 文件
1 file changed, 1 insertion(+), 1 deletion(-)
git log
Git 提交历史一般常用两个命令:
- git log - 查看历史提交记录。
- git blame [file] - 以列表形式查看指定文件的历史修改记录。
在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看。
$ git log
commit db9828a1eee14fcbf8f771cf6391f884a6e64ed5 (HEAD -> master)
Author: hhq <test@163.com>
Date: Tue May 9 19:31:02 2023 +0800
修改 hello.py 文件
commit c22a913ff825d70844a72096f025db241a58416d
Author: hhq <test@163.com>
Date: Tue May 9 19:30:04 2023 +0800
第二次版本提交
commit 04d4b8e3a972e954e66f722e8fdf6d8d67135cc5
Author: hhq <test@163.com>
Date: Tue May 9 19:24:10 2023 +0800
第一次版本提交
我们可以用 --oneline 选项来查看历史记录的简洁的版本。
$ git log --oneline
db9828a (HEAD -> master) 修改 hello.py 文件
c22a913 第二次版本提交
04d4b8e 第一次版本提交
还有以下常见参数
-
–graph:查看历史中什么时候出现了分支、合并。
-
–reverse:逆向显示所有日志。
-
–author:查找指定用户的提交日志
$ git log --author=hhq
-
–since 和 --before:指定日期,例如查看Git 项目中三周前且在四月十八日之后的所有提交
$ git log --oneline --before={3.weeks.ago} --after={2010-04-18}
如果要查看指定文件的修改记录可以使用 git blame 命令
$ git blame README
^04d4b8e (hhq 2023-05-09 19:24:10 +0800 1) # Git 测试
55de69d3 (hhq 2023-05-09 19:46:14 +0800 2) # Hhhhhq
git reset
git reset 命令用于回退版本,可以指定退回某一次提交的版本。
命令语法格式如下:
git reset [--soft | --mixed | --hard] [HEAD]
–mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。
git reset [HEAD]
实例:
$ git reset HEAD^ # 回退所有内容到上一个版本
$ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本
$ git reset 052e # 回退到指定版本
–soft 参数用于回退到某个版本:
git reset --soft HEAD
实例:
$ git reset --soft HEAD~3 # 回退上上上一个版本
–hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:
git reset --hard HEAD
实例:
$ git reset --hard HEAD~3 # 回退上上上一个版本
$ git reset –hard bae128 # 回退到某个版本回退点之前的所有信息。
$ git reset --hard origin/master # 将本地的状态回退到和远程的一样
**注意:**谨慎使用 –-hard 参数,它会删除回退点之前的所有信息。
2.4 分支
几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vakH16n6-1683717030022)(null)]
Git 分支实际上是指向更改快照的指针。有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。
基本操作
-
创建分支命令:
git branch (branchname)
-
切换分支命令:
git checkout (branchname)
当你切换分支的时候,Git 会用该分支的最后提交的快照替换你的工作目录的内容, 所以多个分支不需要多个目录。 -
合并分支命令:
git merge
你可以多次合并到统一分支, 也可以选择在合并之后直接删除被并入的分支。
开始前我们先创建一个测试目录:
$ mkdir gitdemo
$ cd gitdemo/
$ git init
Initialized empty Git repository...
$ touch README
$ git add README
$ git commit -m '第一次版本提交'
[master (root-commit) 43ddc24] 第一次版本提交
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 readme
列出分支
列出分支基本命令:
git branch
没有参数时,git branch 会列出你在本地的分支。
$ git branch
* master
此例的意思就是,我们有一个叫做 master 的分支,并且该分支是当前分支。当你执行 git init 的时候,默认情况下 Git 就会为你创建 master 分支。
如果我们要手动创建一个分支。执行 git branch (branchname) 即可。
$ git branch testing
$ git branch
* master
testing
现在我们可以看到,有了一个新分支 testing。
当你以此方式在上次提交更新之后创建了新分支,如果后来又有更新提交, 然后又切换到了 testing 分支,Git 将还原你的工作目录到你创建分支时候的样子。
接下来我们将演示如何切换分支,我们用 git checkout (branch) 切换到我们要修改的分支。
$ ls
README
$ echo 'test.com' > test.txt
$ git add .
$ git commit -m 'add test.txt'
[master 3e92c19] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ ls
README test.txt
$ git checkout testing
Switched to branch 'testing'
$ ls
README
当我们切换到 testing 分支的时候,我们添加的新文件 test.txt 被移除了。切换回 master 分支的时候,它们又重新出现了。
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt
我们也可以使用 git checkout -b (branchname)
命令来创建新分支并立即切换到该分支下,从而在该分支中操作。
$ git checkout -b newtest
Switched to a new branch 'newtest'
$ git rm test.txt
rm 'test.txt'
$ ls
README
$ touch runoob.php
$ git add .
$ git commit -am 'removed test.txt、add runoob.php'
[newtest c1501a2] removed test.txt、add runoob.php
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt
如你所见,我们创建了一个分支,在该分支上移除了一些文件 test.txt,并添加了 hhq.py 文件,然后切换回我们的主分支,删除的 test.txt 文件又回来了,且新增加的 hhq.py 不存在主分支中。
使用分支将工作切分开来,从而让我们能够在不同开发环境中做事,并来回切换。
删除分支
删除分支命令:
git branch -d (branchname)
例如我们要删除 testing 分支:
$ git branch
* master
testing
$ git branch -d testing
Deleted branch testing (was 85fc7e7).
$ git branch
* master
合并分支
git merge
一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。 你可以使用以下命令将任何分支合并到当前分支中去:
$ git branch
* master
newtest
$ ls
README test.txt
$ git merge newtest
Updating 3e92c19..c1501a2
Fast-forward
runoob.php | 0
test.txt | 1 -
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
以上实例中我们将 newtest 分支合并到主分支去,test.txt 文件被删除。
合并完后就可以删除分支:
$ git branch -d newtest
Deleted branch newtest (was c1501a2).
删除后, 就只剩下 master 分支了:
$ git branch
* master
合并冲突
合并并不仅仅是简单的文件添加、移除的操作,Git 也会合并修改。
$ git branch
* master
$ cat runoob.php
首先,我们创建一个叫做 change_site 的分支,切换过去,我们将 hhq.py 内容改为:
print('hello branch')
创建 change_site 分支:
$ git checkout -b change_site
Switched to a new branch 'change_site'
$ vim runoob.php
$ cat hhq.py
print('hello branch')
$ git commit -am 'changed the hhq.py'
[change_site 7774248] changed the runoob.php
1 file changed, 3 insertions(+)
将修改的内容提交到 change_site 分支中。 现在,假如切换回 master 分支我们可以看内容恢复到我们修改前的(空文件,没有代码),我们再次修改 hhq.py 文件。
$ git checkout master
Switched to branch 'master'
$ cat hhq.py
$ vim hhq.py # 修改内容如下
$ cat hhq.py
print('hello branch 222')
$ git diff
diff --git a/hhq.py b/hhq.py
index e69de29..36c64f7 100644
--- a/hhq.py
+++ b/hhq.py
@@ -0,0 +1 @@
+print('hello branch 222')
$ git commit -am '修改代码'
[master c68142b] 修改代码
1 file changed, 1 insertions(+)
现在这些改变已经记录到我的 “master” 分支了。接下来我们将 “change_site” 分支合并过来。
$ git merge change_site
Auto-merging hhq.py
CONFLICT (content): Merge conflict in hhq.py
Automatic merge failed; fix conflicts and then commit the result.
$ cat hhq.py # 打开文件,看到冲突内容
<<<<<<< HEAD
print('hello branch 222')
=======
print('hello branch')
>>>>>>> change_site
我们将前一个分支合并到 master 分支,一个合并冲突就出现了,接下来我们需要手动去修改它。
$ vim hhq.py
$ cat hhq.py
print('hello branch 222')
print('hello branch')
$ git diff
diff --cc hhq.py
index 36c64f7,5a5a1e1..0000000
--- a/hhq.py
+++ b/hhq.py
@@@ -1,1 -1,1 +1,2 @@@
+print('hello branch 222')
+ print('hello branch')
在 Git 中,我们可以用 git add 要告诉 Git 文件冲突已经解决
$ git status -s
UU hhq.py
$ git add hhq.py
$ git status -s
M hhq.py
$ git commit
[master d5a4c1d]] Merge branch 'change_site'
现在我们成功解决了合并中的冲突,并提交了结果。
开发中的分支管理
在开发中,一般有如下分支使用原则与流程:
- master(生产)分支
线上分支,主分支 - develop(开发)分支
是从 master 创建的分支,一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线 要求,都可以在此版本进行开发,阶段开发完成后,需要合并到 master 分支,准备上线。 - feature/xxxx分支
从develop创建的分支,一般是同期并行开发,但不同期上线时创建的分支,分支上的研发任务完 成后合并到 develop 分支。 - hotfix/xxxx分支
从 master 派生的分支,一般作为线上 bug 修复使用,修复完成后需要合并到 master、test、 develop 分支。 - 其它分支
例如 test分支(用于代码测试)、pre分支(预上线分支)等等。
2.5 标签
如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签。
比如说,我们想为我们的 test 项目发布一个"1.0"版本,可以用 git tag -a v1.0 命令给最新一次提交打上(HEAD)"v1.0"的标签。
-a 选项意为"创建一个带注解的标签"。 不用 -a 选项也可以执行的,但它不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解。 推荐一直创建带注解的标签。
$ git tag -a v1.0
当你执行 git tag -a 命令时,Git 会打开你的编辑器,让你写一句标签注解,就像你给提交写注解一样。
现在,注意当我们执行 git-log
时,我们可以看到我们的标签了:
![image-20230509220149715](https://i-blog.csdnimg.cn/blog_migrate/04796bbd3e3d92da53d4a901b91a1359.png)
如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。
例如,假设我们发布了提交 85fc7e7(上面实例最后一行),但是那时候忘了给它打标签。 我们现在也可以:
![image-20230509220303610](https://i-blog.csdnimg.cn/blog_migrate/cd9cf2f0eacbb1f38db1ba0364d39d40.png)
如果我们要查看所有标签可以使用以下命令:
$ git tag
v0.9
v1.0
指定标签信息命令:
git tag -a <tagname> -m "test.com标签"
PGP签名标签命令:
git tag -s <tagname> -m "test.com标签"
3. Git远程仓库
3.1 常用的远程仓库
前面我们已经知道了Git中存在两种类型的仓库,即本地仓库和远程仓库。那么我们如何搭建Git远程仓库 呢?我们可以借助互联网上提供的一些代码托管服务来实现,其中比较常用的有GitHub、码云、GitLab等。
-
gitHub( 地址:https://github.com/ )是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名gitHub
-
码云(地址: https://gitee.com/ )是国内的一个代码托管平台,由于服务器在国内,所以相比于 GitHub,码云速度会更快
-
GitLab (地址: https://about.gitlab.com/ )是一个用于仓库管理系统的开源项目,使用Git作 为代码管理工具,并在此基础上搭建起来的web服务,一般用于在企业、学校等内部网络搭建git私服。
GitHub配置教程:https://www.runoob.com/git/git-remote-repo.html
Gitee配置教程:见Git讲义 P11-16
在Idea中使用Git:见Git讲义 P17-23
Git讲义.pdf https://www.aliyundrive.com/s/dN8m6cDCdNx 提取码: 8gj0