git详解

详细介绍git

git一图流

image-20211207151102904

git详解

Git与svn对比

SVN(Subversion)是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就郁闷了。
下图就是标准的集中式版本控制工具管理方式:

image-20230103162133191

集中管理方式在一定程度上看到其他开发人员在干什么,而管理员也可以很轻松掌握每个人的开发权限。
但是相较于其优点而言,集中式版本控制工具缺点很明显:

  • 服务器单点故障
  • 容错性差

Git

Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
下图就是分布式版本控制工具管理方式:

image-20230103162249584

git工作流程

  1. 从远程仓库中克隆 Git 资源作为本地仓库。
  2. 从本地仓库中checkout代码然后进行代码修改
  3. 在提交前先将代码提交到暂存区。
  4. 提交修改。提交到本地仓库。本地仓库中保存修改的各个历史版本。
  5. 在修改完成后,需要和团队成员共享代码时,可以将代码push到远程仓库。

下图展示了 Git 的工作流程:

image-20230104113924564

Git安装

下载地址:https://git-scm.com/download

关键词理解

在初始化git版本库之后会生成一个隐藏的文件 .git ,可以将该文件理解为 git 的版本库 repository,而我们自己建立的项目文件夹即工作区 working directory , 在 .git 文件夹里面还有很多文件,其中有一个 index 文 件 就是暂存区也可以叫做 stage , git 还为我们自动生成了一个分支 master 以及指向该分支的指针head ,如下图

image-20230112111626807

  • 工作区: 存储项目文件的目录, 版本库需要创建到工作区中

  • 版本库: 创建出的隐藏目录 .git

    • stage - 暂存区
      当往工作区中添加了新文件之后, 需要将工作区文件添加到暂存区

    • master - 主分支

      默认只有这一个, 进行版本管理
      HEAD - 操作master分支的指针

    • 暂存区和分支的关系

      当暂存区的文件内容发送变化, 需要将其提交的master分支
      只有提交之后才会形成一个节点(一个版本)

可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

使用git管理文件

使用git help git关键词可以查询git关键词的作用

创建版本库

什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。由于git是分布式版本管理工具,所以git在不需要联网的情况下也具有完整的版本管理能力。

在要使用git管理的目录中点击右键中选择Git Bash来启动,创建仓库执行命令:**git init**

版本库创建成功,会在此目录下创建一个.git的隐藏目录

  • 版本库.git目录就是版本库,将来文件都需要保存到版本库中。
  • 工作目录:包含.git目录的目录,也就是.git目录的上一级目录就是工作目录。只有工作目录中的文件才能保存到版本库中。

添加暂存区并提交

添加新文件到暂存区并提交

  1. 添加改动到暂存区 git add .(.表示所有变动,但不包含已删除的文件 git add -A才是真正的所有改动)
  2. 暂存区提交到分支 git commit -m '注释'

第一次使用git执行commit之前需要设定个人资料,点击跳转参考

还原修改

还原的本质 : 将工作区中修改的文件还原成想要的提交的版本

还原有三种情况

  • 只是修改了文件,没有任何 git 操作

    1
    2
    3
    git checkout -- aaa.html // 指定还原`aaa.html`文件

    git checkout -- * // 还原所有文件
  • 修改了文件,并提交到暂存区(即:编辑之后,进行git add 但没有 git commit -m "留言xxx"

    1
    2
    3
    4
    5
    git log --oneline            #只显示提交ID和提交信息的第一行,可省略

    git reset HEAD // 回退到当前版本

    git checkout -- aaa.html
  • 修改了文件,并提交到仓库区(即:编辑之后,进行git add 并且 git commit -m "留言xxx"

    1
    2
    3
    4
    5
    git log --oneline    #只显示提交ID和提交信息的第一行,可省略

    git reset HEAD^ // 回退到上一个版本,注意看HEAD后面有个^ HEAD^是回退到上个版本 HEAD^^是回退到上上个版本HEAD~数字 是回退到数字个版本

    git checkout -- aaa.html

前两种情况使用了还原功能后,修改内容就丢失了,无法找回.原因是真正保存下来的其实是每次提交的状态

另外有一种更常用的还原:

git restore 文件名 : 撤消工作区的修改返回到最近一次add(缓存区)的版本或者最近一次commit(当前版本库)的版本

git restore --stage <file>git restore <file>两个命令的区别

  • 对于git restore <file>命令,会撤销文件的修改,使文件恢复到暂存区或当前版本库(取决于文件在修改前的状态);
  • 对于git restore --staged <file>命令,把文件从暂存区撤回到工作区,保留文件最后一次修改的内容;

查看相关信息

  • git log 查看版本库中提交的各个节点信息
  • git status 查看当前状态(修改了什么,追踪了什么(暂存)还未提交),还可以查看是否同步了远程仓库的最新内容

对比修改内容

git diff的重点

文件的流转方向是由工作区创建,add进入暂存区,commit进入仓库。

  • git diff 比较暂存区与工作区文件的区别。
  • git diff --cached 比较仓库(版本库)与暂存区文件的区别。

对比未暂存修改

此时比较的是: 已暂存(staged)和 已追踪未暂存(modified) 之间的修改部分。
此时执行 git status 查看文件状态,git diff,显示内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#此时 hello.txt 中已经有一行内容了,内容为hello world,我们将其改为了hello
$ git status
On branch master
No commits yet

Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: hello.txt

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: hello.txt


$ git diff
diff --git a/hello.txt b/hello.txt
index 95d09f2..b6fc4c6 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-hello world
No newline at end of file
+hello
No newline at end of file
#文件名后面 + 和 - 的数量是这个提交造成的更改中增删的项

对比已暂存修改

此时比较的是: 提交至仓库的版本 和 暂存区文件 之间的修改部分

git diff --cached 命令

注意:--staged--cached 是同义词
git diff --cached 等于 git diff --staged

1
2
3
4
5
6
7
8
9
10
11
12
13
#hello.txt 的内容为 hello。此时我们修改内容为 hi
$ git add hello.txt

$ git diff --cached
diff --git a/hello.txt b/hello.txt
index b6fc4c6..32f95c0 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-hello
No newline at end of file
+hi
No newline at end of file

对比本地与远程仓库的区别

git diff 本地仓库名 远程仓库名/远程分支名 (远程与本地顺序可颠倒)

如: git diff master origin/master

添加忽略列表

有些文件或文件夹不需要git追踪,因此可以将他们添加到忽略列表

一般库文件和可执行文件,不需要git追踪

需要在项目根目录新建**.gitignore**文件(也就是与.git文件夹同级)
文件中写上忽悠的文件或文件夹,例如:

1
2
3
4
5
.vs
npoi.fast/bin
npoi.fast/obj
npoi.fast.test/bin
npoi.fast.test/obj

如果要忽略的文件或文件夹已提交过,请使用命令git rm -r --cached filename (其中filename换成文件或文件夹名,如上述.vsnpoi.fast/bin)

已经添加至 git 仓库的文件(commit 后的),是不能被 .gitignore 文件所影响的,需要先 git rm --cached 让其脱离 git 仓库。git rm --cached 后还需要commit

删除相关

git rm 等同于 rm + git add

git rm --cached会保留原文件,只删除对文件的追踪状态,常用于已提交后添加忽略的情况

与远程仓库交互

在线代码托管平台: Github 码云 等等

image-20211207131020235

本地同步到远程

这里指的是本地和远程的分支在过去节点就有差异的合并

下面介绍了两种本地同步到远程的方式,一种会产生合并分支;一种不会产生合并分支,即可以保持线性.

本地库上传到远程库参考

不产生合并分支的方式

[注意] 上传到远程库最稳妥的方式是push之前先pull

如果本地和远端本身就有不同,则可以通过git pull --rebase <远程主机名> <远程分支名> 将远程的数据拉到本地自动产生一个本地节点(是作为原本节点之前的节点(而不是最新的节点),符合rebase的语义),本地最新的节点此时既有原本远程节点的数据,也有改动数据,然后就可以正常push提交了

更流程化的做法如下:

  1. 当在使用 git pull --rebase 命令时,如果发生冲突,需要手动解决冲突并继续rebase操作。以下是解决冲突的一般步骤:
  2. 运行 git pull --rebase 命令时,如果发生冲突,Git会停止rebase操作并提示冲突的文件。
  3. 打开冲突的文件,手动解决冲突。在冲突标记(<<<<<<<,=======,>>>>>>>)之间编辑文件,将冲突部分修改为期望的内容。
  4. 保存文件后,运行 git add -u ,命令将解决冲突后的文件标记为已解决。
  5. 运行 git rebase --continue 命令继续rebase操作。Git会继续应用之前的提交,直到完成rebase操作。
其他方式

如果不使用 git pull --rebase ,而本地分支和远程分支有差异,您可以通过以下步骤提交代码:

  1. 首先,使用 git pull 命令拉取远程分支的最新代码到本地。这将自动合并远程分支的代码到本地分支,如果有冲突需要手动解决。
  2. 解决可能出现的冲突。在解决完冲突后,使用 git add 命令将解决冲突的文件标记为已解决。
  3. 运行 git commit 命令提交解决冲突后的代码。
  4. 如果需要将本地提交推送到远程分支,可以使用 git push 命令将本地提交推送到远程分支。 通过以上步骤,您可以在本地和远程分支有差异的情况下,手动合并代码并提交到远程分支。

请注意,这种方式可能会产生合并提交,如果希望避免产生合并提交,可以考虑使用 git pull --rebase 或其他方法来保持提交历史的线性和清晰。

远程同步到本地

远程库下载到本地库: git clone ssh链接或https链接

远程库更新到本地库: git pull <远程主机名> <远程分支名>:<本地分支名> (将<远程主机名><远程分支名>分支拉取过来,与<本地分支名>分支合并)

git pull 等同于 git fetch + git merge (git fetch是把远程仓库的内容下载到本地作为一个本地的子分支)

克隆clone和拉取pull区别

  • 本地仓库还没有的时候使用克隆
  • 本地仓库已经存在了,从远程仓库下载文件使用拉取

fetch,pull,clone详解点击跳转

  • fetch使用格式: git fetch <repositoryUrl>
  • merge使用格式: git merge <需要合并到当前分支的目标分支名>

推送本地仓库文件到远程仓库注意

  • 如果远程仓库没有任何分支,可以将本地仓库直接推送到远程仓库,不会报错;

  • 若远程仓库有master分支,则本地仓库推送master分支的时候会报错

    解决方法:首先优先将远程仓库的文件”获取”(fetch)到本地仓库,将自动在本地仓库建立了默认名字为**FETCH_HEAD**的子分支,然后将该子分支合并到master主分支(可能需要解决冲突),最后再执行推送操作(push)就可以了

注意: fetch指令生成的FETCH_HEAD子分支无法用git branch查看到

rebase指令详解跳转 (不推荐使用)

SSH协议配置

除了https协议连接,还可以使用ssh协议进行连接

加密的方式是非对称加密,需要生成一对密钥

  • 客户端拿私钥
  • github服务器拿公钥

生成SSH协议密钥对

生产秘钥对的命令: ssh-keygen -t rsa (rsa为非对称加密算法)

也可以ssh-keygen -t rsa -C "这里输入生成的sshkey的名称"

将生成id_rsa(私钥)和id_ras.pub(公钥)

公钥添加到 github 账户

github中设置公钥: 点击头像-Settings-SSH and GPG keys-New SSH keys中起个题目并且填入id_ras.pub中的key,最后点击Add SSH key

SSH协议私钥设置到本地

1
2
ssh-agent bash
ssh-add ~/.ssh/id_rsa # 这里如果文件名被改过要写你自己定义的文件名 (~/.ssh/id_rsa为私钥文件路径)

返回如下结果表示设置成功:

1
Identity added: id_rsa (your_email@example.com)

测试SSH协议连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#输入:
#github
ssh -T git@github.com
#码云
ssh -T git@gitee.com
#返回:
The authenticity of host 'github.com (20.205.243.166)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
#输入:
yse
#返回:
Warning: Permanently added 'github.com,20.205.243.166' (ECDSA) to the list of known hosts.
Hi xxxxxx You've successfully authenticated, but GitHub does not provide shell access.
#如果 xxxxxx 是github用户名,表示ssh链接成功

配置 git的push&pull 使用 SSH协议 连接

在仓库中输入git remote -v查看当前使用的是什么协议,如果以git开头表示SSH协议,下面是使用https协议返回的结果:

1
2
origin  https://xxxxx.git (fetch)
origin https://xxxxx.git (push)

输入 git remote set-url origin git@github.com:xxxxx.git 修改https协议为SSH协议,git@github.com:xxxxx.git取自github库

接下来使用push&pull就是使用的SSH协议

分支操作

git中默认只有一个分支:master

如果创建了分支,各个分支都是独立的,互不影响的

image-20230130173124159

当前所在的分支,其实是由 HEAD 决定的

命令名称 作用
git branch 分支名 创建本地分支
git branch 查看本地有哪些分支
git branch -d 分支名 删除本地分支
git push <主机名> -d <分支名> 删除远程分支,主机名不填默认是origin
git branch -v 查看本地分支+上次提交的信息
git branch -vv 查看本地分支+上次提交的信息+本地和远程分支的关系
git branch -vv -a 查看本地分支+上次提交的信息+本地和远程分支的关系+远程分支(如果不想显示提交的信息,也可以去掉-vv参数)
git branch -r 只查看远程分支
git checkout 分支名 切换本地分支
git checkout -b 分支名 创建本地分支并切换
git merge 分支名 把指定的分支合并到当前分支上
git branch -m 旧分支名 新分支名 修改本地分支名称
git merge --abort 回到解决合并冲突之前的状态
git branch -f 分支名1 分支名2 更新分支1以指向分支2
git branch -B 分支名1 分支名2 更新分支1以指向分支2并且切换到分支1
解决冲突

跳转参考解决冲突具体代码操作

合并中有冲突的数据会显示为如下格式:

1
2
3
4
5
<<<<<<< HEAD
hello, git!!! master test!
=======
hello, git!!!hot-fix test!
>>>>>>> hot-fix

上面的HEAD分支的内容和下面hot-fix分支的内容,该处有冲突,需要手动解决冲突后再提交

git常用指令

常用环境设定

1
2
3
4
5
6
7
//编辑器更换:
git config --global core.editor "code --wait"
//git缩写:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
git config --global alias.ci commit

查看所有config的设定

  • Mac:~/.gitconfig
  • Win:C:\Users\$USER

git版本查看

1
git --version

设定个人资料

1
2
3
4
5
6
//输入姓名
git config --global user.name "gon"
//输入个人的email
git config --global user.email "gonsakon@gmail.com"
//查询git设定内容
git config --list

基本指令架构

image-20211207131020235

上传指令

  1. 初始化git数据库:git init

    文件夹中多出一个.git文件夹,表明该文件夹已经生成了git数据库了(需要显示隐藏文件才能显示出来)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //macOS下打开隐藏文件显示
    defaults write com.apple.finder AppleShowAllFiles TRUE
    // 默认显示苹果所有文件 true
    killall Finder// 这一步相当于确定
    //关闭隐藏文件显示
    defaults write com.apple.finder AppleShowAllFiles FALSE
    killall Finder // 这样就恢复成初始状态了

    //也可以在访答中键入command+shift+.
  2. 关联远程库: git remote add origin https://github.com/your-username/my-repo.git命令将本地仓库与远程GitHub仓库关联起来。将your-username替换为你的GitHub用户名。

  3. 查询当前状态:git status

  4. 将有修改的档案加入到索引(暂存区):git add . (但不包含删除改动, git add -A才是真正的所有改动)

  5. 将索引档案变成一个更新(COMMIT):git commit -m "修改内容的描述"

  6. 将最新的更新修改为当前索引档案(这个命令会将你的更改添加到最新的提交中,而不是创建一个新的提交): git commit --amend -m "要修改的修改内容的描述"(不加-m加描述的部分则会打开文本编辑器,让你编辑上一次提交的描述)

  7. 观察commit历史记录:git log

  8. 下载远程数据库:git clone 数据库网址

  9. 更新远程数据库:git push origin master (此处的master为远程仓库的分支名)

1
2
3
4
5
6
7
//上传步骤
git add .//添加当前目录的所有文件到暂存区
git commit -m "修改内容的描述"
git push <远程主机名> <本地分支名>:<远程分支名>
//如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程主机名> <本地分支名>
git push --force <远程主机名> <本地分支名>:<远程分支名>//强制推送,不管任何事

[注意] 最好的方式是push之前先pull

远程储存库操作

  • 注册远程储存库origins名称对应远程储存库网址:git remote add origin 远程储存库网址(origin是自己取的远程储存库名字,怎么取都可以)
  • 更新资料到远程master分支:git push -u origin master(-u可以省略)
1
2
3
//上传到已经存在的远程储存库
git remote add 自己取的名字 远程数据库的git的url//注册远程储存库名称对应远程储存库网址
git push -u 自己取的名字 master(-u可以省略)

git版本控制

git版本细节

  • branch:分支,默认分支叫master
  • HEAD:当下的本地版本位置
  • origin:默认远程储存库
  • 回到某个版本内容:git checkout commit编号
  • 返回最新的版本:git checkout master(分支名称)
1
2
3
git log//查看当前所有的commit编号
git checkout 想回到的commit节点的哈希值//返回到指定哈希值的commit节点
//Git 对哈希的处理很智能。你只需要提供能够唯一标识提交记录节点的前几个字符即可

image-20211209200758510

commit编号就是个哈希值

image-20211209202104826

git checkout commit编号与直接在上图左侧双击commit行均为使得文件恢复到与commit时的样子,二者效果一致。

还原技巧

src=http___upload-images.jianshu.io_upload_images_4311354-6a4562939fec66c0.png&refer=http___upload-images.jianshu

Untracked:表示未跟踪的

未跟踪情况下

新建文件的时候,清空未跟踪的内容:

  • 显示此次清除的未跟踪内容:git clean -n
  • 强制清除未跟踪内容:git clean -f

还原工作目录上已更改的内容:

1
2
git checkout -- <file文件名>//将该文件已更改的内容还原
git checkout .//所有更改内容还原

已跟踪情况下

git reset 通过把分支记录回退几个提交记录来实现撤销改动。你可以将这想象成“改写历史”。git reset 向上移动分支,原来指向的提交记录就跟从来没有提交过一样。

已经加入到暂存区的改动,退回到未加入缓存区状态:git reset HEAD

git reset head^^,两个^表示返回两个commit记录的节点转为未跟踪状态,多少^表示多少个commit记录节点。

git reset 很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的,取而代之的是git revert xxx

image-20211210151213508image-20211210151908657

Git分支(branch)

为什么要用分支?

  • 多人协作时,不可能都在master
  • 可以让master都是正式版资料,可以开分支来做测试或开发,让这些流程不影响正式主机分支
1
2
3
4
5
6
7
git branch 分支名//新建分支
git branch//查看当前有多少个分支
git checkout 分支名//切换到别的分支
git branch -d "分支名称"//删除分支,-D是强制删除
//如果你想创建一个新的分支同时切换到新创建的分支的话,可以通过 git checkout -b <your-branch-name> 来实现。
git merge 合并的分支名//提交新节点为合并分支,快转
git merge 要合并的分支名 --no-ff //合并分支,非快转

git checkout -B master详解:

这个命令会创建一个新的master分支,或者如果master分支已经存在,它会更新master分支到当前HEAD注意,如果master分支已经存在并且有未提交的更改,这个命令会覆盖那些更改。在运行这个命令之前,确保你的工作目录是干净的,或者你已经提交了所有的更改。如果你只是想创建一个新的分支指向当前提交,你可以使用git checkout -b new_branch_name。这将创建一个新的分支并检出到那个分支,而不会影响master分支。请根据你的需求选择合适的命令。

  • git checkout -b <branch>: 这个命令会创建一个新的分支,并且切换到这个新创建的分支。如果已经存在一个同名的分支,Git会返回一个错误。
  • git checkout -B <branch>: 这个命令和-b选项类似,但是如果存在一个同名的分支,它不会返回错误,而是将这个分支重置为当前HEAD。也就是说,如果分支已经存在,-B选项会将其重置为当前的HEAD,如果分支不存在,它会创建一个新的分支。

相对移动

  • 使用^向上移动1个提交记录
  • 使用~<num>向上移动多个提交记录,如~3

可以直接使用 -f 选项让分支指向另一个提交。例如:

1
git branch -f main HEAD~3

上面的命令会将 main 分支强制指向 HEAD 的第 3 级父提交。

git切换节点面临的问题

Git不允许切换分支时覆盖未提交的更改,以避免意外丢失工作

切换节点后,切换的节点又产生了改动,想要切换原节点会报错:下面三种方法解决:

  1. 提交更改:如果您希望保留当前分支上的更改,请先使用git add命令将更改添加到暂存区,然后使用git commit命令提交更改。提交后,您就可以使用git checkout 原节点切换到原节点了。

  2. 存储更改:如果您不想提交当前分支上的更改,而是暂时保存它们以便稍后使用,请使用git stash命令将更改存储起来。运行git stash将存储更改并将工作目录恢复到干净的状态,然后您就可以使用git checkout 原节点切换到原节点了。在需要恢复更改时,可以使用git stash apply命令将存储的更改重新应用到工作目录。

  3. 如果您不想保留当前分支上的更改,

    使用强制切换:您可以使用-f--force选项来强制切换分支,忽略未提交的更改。运行以下命令将当前分支切换到原节点,并丢弃未提交的更改:

    1
    git checkout -f 原节点

    请注意,这将不可逆地丢弃当前分支上的所有未提交更改,请确保您不再需要这些更改。

git标签

在Git中,标签(tag)是一种用于给特定提交打标签的机制,通常用于标记重要的版本或发布。标签可以帮助开发者快速识别和引用特定的提交历史。

推送标签的好处:

  1. 版本管理:标签通常用于标记软件的发布版本(例如v1.0、v2.0等),推送标签后,其他人可以轻松找到和下载这些特定版本。
  2. 协作:在团队合作中,推送标签可以确保所有成员都能看到相同的版本标记,避免版本混淆。
  3. 历史记录:标签提供了一个清晰的历史记录,帮助开发者理解项目的演变。

标签有两种类型:

  1. 轻量标签(Lightweight Tag):相当于一个指向特定提交的指针,类似于一个分支,但不随时间变化。创建轻量标签的命令是:
    git tag <tagname>
  2. 注释标签(Annotated Tag):包含更多信息,比如标签的作者、日期和附加注释。注释标签是推荐使用的,因为它们提供了更丰富的上下文。创建注释标签的命令是:
    git tag -a <tagname -m "your message">

当你创建标签时,Git会默认将标签指向当前的HEAD(即当前分支的最新提交)。例如,如果你在某个分支上创建标签,标签就会指向该分支的最新提交。

常用命令

  • 列出所有标签
    git tag

  • 查看特定标签的信息
    git show <tagname>

  • 列出所有标签及其指向的提交

    git tag -n

  • 推送标签到远程仓库:(查看标签所指向的具体提交信息,包括提交的哈希值、作者、日期以及提交信息)
    git push origin <tagname>

  • 推送所有标签到远程仓库
    git push origin --tags

标签在版本控制中非常有用,特别是在发布软件时,可以清晰地标记每个版本,方便团队成员和用户进行引用和下载。

git看这个就行

操作逻辑

git操作记录

如何让节点在分支间移动

git cherry-pick

git cherry-pick 是一个强大的 Git 命令,它允许你将一个或多个提交从一个分支选出(cherry-pick)并应用到你当前工作的分支上。这个命令非常有用,特别是在你想要将特定的更改从一个分支移植(或复制)到另一个分支,而不需要合并整个分支的历史时。

使用方式

基本的 git cherry-pick 命令格式如下:git cherry-pick <commit-hash>,其中 <commit-hash> 是你希望复制过来的提交的哈希值。你可以通过 git log 命令查看提交的哈希值。

多个提交

如果你想一次性应用多个提交,只需在命令后面列出所有想要应用的提交的哈希值,用空格隔开:git cherry-pick <commit-hash1> <commit-hash2> <commit-hash3>

会首先被应用,然后是 ,最后是 。Git 会依次将每个提交的更改应用到当前分支,并在目标分支上创建相应的新提交

也可以使用范围操作符用来指定一连串的提交,像这样:git cherry-pick <start-commit-hash>^..<end-commit-hash>

解决冲突

在 cherry-picking 过程中可能会遇到冲突。当发生冲突时,Git 会停止应用提交直到你解决冲突。解决冲突后,你需要通过以下命令继续:git cherry-pick --continue如果你决定不应用当前的 cherry-pick 操作,并想要取消它,可以使用:git cherry-pick --abort这将会停止 cherry-pick 操作,并将分支恢复到开始 cherry-pick 之前的状态。

选项

git cherry-pick 命令还有一些有用的选项,如:

  • --edit-e): 在提交前打开编辑器,允许你编辑提交信息。
  • --no-commit-n): 应用更改,但不产生新的提交。这允许你手动创建一个包含多个 cherry-pick 更改的单一提交。
  • --signoff-s): 在提交信息的末尾添加一个签名行,证明你是此次提交的作者。

示例

假设你有一个提交哈希值为 abcd123 的修复,你想将这个修复应用到当前分支上,你可以运行:git cherry-pick abcd123如果在应用过程中遇到合并冲突,解决冲突后,运行:git cherry-pick --continue这将提交更改,并将你的分支更新到包含新修复的状态。

git cherry-pick 是一个非常实用的工具,特别是在处理涉及多个分支的复杂项目时。正确使用可以在保持项目清晰度的同时,有效管理分支之间的具体更改。

不小心遗失节点

Git 提供了工具来帮助你恢复丢失的提交,你可以尝试以下方法

不知道丢失节点哈希值

  1. 使用 git reflog 查找丢失的提交:
    Git 的 reflog 记录了对于 HEAD 的所有移动,包括提交和 rebase 操作。你可以使用 git reflog 命令来查找丢失的提交。

  2. 在 reflog 输出中,查找失去的提交对应的 HEAD@{n} 引用。一旦找到它,你可以通过以下命令来恢复:

    git checkout -b 分支名 "HEAD@{n}"

    这将会创建一个新的分支并检出到丢失的提交状态

  3. 然后可以使用git cherry-pick将节点合并过来

  4. 再使用 git branch -d 分支名 删除第3步生成的临时分支

就成功将丢失的节点找回来合并到分支上了

知道丢失节点哈希值

  1. git checkout -b 分支名 节点哈希值

    这将会创建一个新的分支并检出到丢失的提交状态

  2. 然后可以使用git cherry-pick将节点合并过来

  3. 再使用 git branch -d 分支名 删除第1步生成的临时分支

合并本地的多个节点

往往在本地提交的多个节点信息,需要合并成一个节点作为一个相对完整的整体再推送到远程服务器上

以合并本地最新的两个节点为例,使用 git rebase 执行交互式变基(interactive rebase)。以下是操作步骤:

  1. git rebase -i HEAD~2

    这将会打开你的默认文本编辑器,并且显示最近的两个提交

    1
    2
    3
    pick 40e39bd 更新了曲线相似度相关代码,基本功能已实现完毕
    pick 62e4c9a 基本功能都已实现
    ...
  2. 将某个节点的pick改成squash,表示合并这个节点到前一个提交之中

    • pick 是默认的操作,意味着”选择”这个提交。当你将某个提交前面的命令设置为 pick,你告诉 Git 保留这次提交的更改和它的提交信息。基本上,你是在说,“就像我原来提交的那样保留这个更改”。
    • squash 操作会将当前提交与前一个提交合并。选择 squash 命令的效果是使当前提交的更改被合并到上一个使用 pick 命令的提交中,并且允许你整合这两个提交的提交信息。在 rebase 的过程中,如果你将一个提交标记为 squash,Git 会将它的更改与前一个提交合并,并在最后提示你修改最终的提交信息。(因此最靠前的节点不能是squash,因为之前没有pick的节点与其合并了,会报错)
  3. 保存并关闭编辑器。Git将会开始rebase过程,并且会打开另一个编辑器让你有机会重写合并提交的提交信息。

  4. 如果有冲突,会要求解决冲突,然后可以通过git rebase --continue继续rebase过程

至此完成

最新提交节点改名

git commit --amend

注意此改名,会将未提交修改带入节点中

撤销特定节点改动

在 Git 中,可以使用 git revert 命令来撤销某个特定提交(节点)所做出的改动。

git revert 会创建一个新的提交来抵消指定提交的影响,从而使项目状态回到该提交之前的样子。

新建项目的时候先修改.gitignore文件

对于那些之前已被追踪但现在想忽略的文件或目录,可以使用 git rm --cached <file/directory> 命令将其从版本库的追踪中移除,但保留本地文件(仅移除追踪状态)。

如果是需要递归处理目录,还得加-r

两个大项目之间切换防止互相影响

清理工作区:在切换到不需要该 dll 的分支之前,先清理工作区,确保没有残留的来自另一个分支的文件。可以使用 git clean -fdx(谨慎使用,确保不会误删重要文件)

以下是对 git clean -fdx 命令各部分的解释:

git clean:执行清理操作。

  • -f:表示强制(force),即强制进行清理,不进行额外提示。
  • -d:表示同时清理未跟踪的目录。
  • -x:表示连忽略文件(在 .gitignore 中指定的)也一起清理。

需要注意的是,这个命令会较为彻底地清理工作区,可能会误删一些你还需要的未跟踪文件,所以使用时要非常谨慎,最好先确保工作区没有重要的未跟踪文件。

取消最新提交节点,还原为修改

1
git reset --soft HEAD~1

还原一个节点

1
git reset --hard HEAD~1  #这个是丢弃更改

修改gitignore后让忽视内容真正从项目移除

需要使用命令git rm -r --cached <directory - name>,其中<directory - name>是要忽略的目录名称。例如,如果要忽略logs目录,可以运行git rm -r --cached logs。这个命令不会删除本地文件系统中的文件或目录,只是将它们从 Git 的缓存中移除,让.gitignore规则生效。

本地变动提交到远程的标准操作

1
2
git pull -r origin main  # 拉取远程 main 分支的更新,并进行 rebase
git push origin main # 将你的更改推送到远程 main 分支

含义git pull -rgit pull --rebase 的缩写。它的作用是从远程仓库获取最新的更改,并将这些更改应用到你当前的工作分支上。与普通的 git pull 不同,git pull -r 会使用 rebase 而不是 merge。(不会包含merge节点,而是先将改动拉过来,才应用自己的改动,提交历史会比较清晰)

工作原理:当你执行 git pull -r 时,Git 会先获取远程分支的更新,然后将你的本地提交“移动”到这些更新之后。这可以保持提交历史的线性,避免产生多余的合并提交。

强制重置回历史上任何一个提交点

当你执行 git pull遇到冲突,并且在解决过程中搞砸了,想要完全回到拉取之前的状态

核心思路: 利用 Git 的引用日志 (reflog) 找到 pull之前那个“干净”的提交点,然后强制重置回去。

最佳解决方案:使用 git reset --hard

这是最直接有效的方法,它会丢弃所有未提交的更改,包括你为解决冲突所做的所有尝试,让你的工作区完全回到拉取前的状态。

1
2
3
4
5
6
7
git reflog

#最近的操作历史会显示在最上面
HEAD@{0}: pull: Merge made by the 'ort' strategy.
HEAD@{1}: commit: My awesome work before pulling
HEAD@{2}: checkout: moving from feature-a to main
...

以回退到pull之前为例: 你需要找到 pull操作之前的那一行记录。通常是紧挨着 pull记录下面的那一行(比如上面的 HEAD@{1})。记下它的索引(如 HEAD@{1})或提交哈希值(如 abc1234

执行硬重置: 使用你在上一步中找到的索引或哈希值,运行 reset命令:

1
2
3
4
5
# 使用索引(推荐,更直观)
git reset --hard HEAD@{1}

# 或者使用具体的提交哈希值
git reset --hard abc1234

--hard选项会强制将你的工作目录和暂存区都重置到指定的提交点,就像什么都没发生过一样

行完这一步后,你的仓库就已经完美地回到了拉取之前的状态

同样有效的方法: 使用 git reset --hard ORIG_HEAD

Git 在进行危险操作(如合并)时,会将之前的 HEAD 位置保存在一个叫 ORIG_HEAD的临时引用中。这通常就是你拉取之前的状态。

1
git reset --hard ORIG_HEAD

这个命令的效果和上面基于 reflog的 reset 是一样的。

项目切换远程仓库流程

更详细的项目迁移到新的一个空的远程仓库流程可以参考[[运维#迁移流程|此处]]

1
2
3
4
5
6
#修改origin指向的链接
git remote remove origin
git remote add origin https://......
git remote remote -v #查看远程仓库
git fetch #提取远程仓库信息
git branch --set-upstream-to="origin/远程分支名" #使当前分支追踪指定的远程分支名

使用git版本号作为程序版本号

git和github

  • Git:一个分散式版本控制软件,可以由它产生一个储存库(git Repository)
  • Github:支持git程序编程存取和远程托管储存库的平台服务

热门远程储存库

  • Github:拥有GitHube Pages功能,可拥有私人[[数据库]],免费方案是3人以下
  • Bitbucket:可拥有私人[[数据库]],免费方案是五人以下团队
  • GitLab:自架Git服务器,有提供web视觉化管理界面,常用语企业内部开发

github上贡献代码

  1. [先提一个issues(可选)],然后fork对方的项目

  2. 将自己fork的项目git clone下来

  3. 安装相关依赖,确保测试案例都通过

  4. 进行代码编写与修改

  5. git branch查看对方的分支

  6. git checkout -b 新分支的命名(新建一个新特性的新分支)

  7. git add -A 添加所有改动

  8. git commit -m “描述改动”

  9. git push –set-upstream origin 新分支的命名 (提交到远端的新分支)

    GitHub在2021年8月13日移除了对密码认证的支持。如果你在尝试推送到或从你创建的代码库中拉取,但认证失败,你可能会看到像git@github.com: Permission denied (publickey)Host key verification failed这样的错误。

    解决方案如下:

    1. 登录你的GitHub账户。点击右上角的个人资料图片,然后选择设置
    2. 在左侧的侧边栏中,点击开发者设置
    3. 在左侧的侧边栏中,点击个人访问令牌
    4. 点击生成新的令牌
    5. 令牌描述字段中,输入一个描述,例如“新的访问令牌”。
    6. 选择范围部分,选择你想要此令牌授予的权限。如果你不确定,你可以先选择所有的复选框。
    7. 点击页面底部的生成令牌
    8. 在下一个页面中,你会看到你的新令牌。复制此令牌,因为你将无法再次查看它。
    9. 现在当你尝试推送到你的仓库时,当Git提示你输入密码时,你应该输入你刚刚创建的个人访问令牌,而不是你的GitHub密码。
  10. 到fork的项目中,可以点击 Compare & pull request按钮

    image-20231124141648973

  11. 设置推送请求,如图

    image-20231124143141499
  12. 等待原作者通过

github上的开源协议

下图出处

94497eee-e34a-4239-8361-b27bc9c299ee-image

img

类似MIT这样的协议,也还是需要版权声明的

版权声明

如果发行的仅仅是可执行软件(不带源码),那就要在软件的某个界面上说明

比如说谷歌浏览器的关于界面中,Google Chrome的诞生离不开Chromium开源项目以及其他开源软件

image-20241125161813840

点开”开源软件”字眼会打开一个页面,列出了一长串的开源软件,其LICENSE和主页(或代码托管地)

image-20241125161936240

详解参考此处

给自己的项目添加开源协议

项目页中点击add file,输入LICENSE就会出现Choose a license template按钮,如下图:

image-20250105170823405

就会出现很多模板供你选择,选好模板后,点击Review and submit后再点击Commit changes...

其实就是在项目下增加了一个LICENSE文件

github action

简单来说可以

  1. 自己服务器上的应用部署过程自动化
  2. 合作开发的时候自动测试代码

详细来说

根据持续集成的设计,代码从提交到生产,整个过程有以下几步。

(1)提交

流程的第一步,是开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交(commit)。

(2)测试(第一轮)

代码仓库对commit操作配置了钩子(hook),只要提交代码或者合并进主干,就会跑自动化测试。 测试有好几种。

  • 单元测试:针对函数或模块的测试
  • 集成测试:针对整体产品的某个功能的测试,又称功能测试
  • 端对端测试:从用户界面直达数据库的全链路测试

(3) 构建

通过第一轮测试,代码就可以合并进主干,就算可以交付了。 交付后,就先进行构建(build),再进入第二轮测试。所谓构建,指的是将源码转换为可以运行的实际代码,比如安装依赖,配置各种资源(样式表、JS脚本、图片)等等。 常用的构建工具如下。

  • Jenkins
  • Travis
  • Codeship
  • Strider

(4) 测试(第二轮)

构建完成,就要进行第二轮测试。如果第一轮已经涵盖了所有测试内容,第二轮可以省略,当然,这时构建步骤也要移到第一轮测试前面。

第二轮是全面测试,单元测试和集成测试都会跑,有条件的话,也要做端对端测试。所有测试以自动化为主,少数无法自动化的测试用例,就要人工跑。

需要强调的是,新版本的每一个更新点都必须测试到。如果测试的覆盖率不高,进入后面的部署阶段后,很可能会出现严重的问题。

(5) 部署

通过了第二轮测试,当前代码就是一个可以直接部署的版本(artifact)。将这个版本的所有文件打包( tar filename.tar * )存档,发到生产服务器。

(6) 回滚

一旦当前版本发生问题,就要回滚到上一个版本的构建结果。最简单的做法就是修改一下符号链接,指向上一个版本的目录。

GitHub Actions 是什么?

Github Actions是由Github创建的 CI/CD服务。 它的目的是使所有软件开发工作流程的自动化变得容易。 直接从GitHub构建,测试和部署代码。CI(持续集成)由很多操作组成,比如代码合并、运行测试、登录远程服务器,发布到第三方服务等等。GitHub 把这些操作就称为 actions。

很多操作在不同项目里面是类似的,完全可以共享。GitHub 允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。

如果你需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。

GitHub 做了一个GitHub Marketplace ,可以搜索到他人提交的 actions。另外,还有一个Awesome Actions的仓库,也可以找到不少 action。

基础概念

GitHub Actions 有一些自己的术语。

  • workflow (工作流程):持续集成一次运行的过程。
  • job (任务):一个 workflow 由一个或多个 job 构成,含义是一次持续集成的运行,可以完成多个任务。
  • step(步骤):每个 job 由多个 step 构成,一步步完成。

虚拟环境

GitHub Ac­tions 为每个任务 (job) 都提供了一个虚拟机来执行,每台虚拟机都有相同的硬件资源:

  • 2-core CPU, 7 GB RAM 内存, 14 GB SSD 硬盘空间
  • 硬盘总容量为90G左右,可用空间为30G左右

使用限制

  • 每个仓库只能同时支持20个 workflow 并行。
  • 每小时可以调用1000次 GitHub API 。
  • 每个 job 最多可以执行6个小时。
  • 免费版的用户最大支持20个 job 并发执行,macOS 最大只支持5个。
  • 私有仓库每月累计使用时间为2000分钟,超过后$ 0.008/分钟,公共仓库则无限制。
  • 操作系统方面可选择 Win­dows server、Linux、ma­cOS,并预装了大量软件包和工具。

TIPS: 虽然名称叫持续集成,但当所有任务终止和完成时,虚拟环境内的数据会随之清空,并不会持续。即每个新任务都是一个全新的虚拟环境。

workflow 文件

GitHub Ac­tions 的配置文件叫做 work­flow 文件,存放在代码仓库的.github/workflows 目录中。

work­flow 文件采用 YAML 格式,文件名可以任意取,但是后缀名统一为.yml,比如 build.yml。一个库可以有多个 work­flow 文件,GitHub 只要发现.github/workflows 目录里面有.yml 文件,就会按照文件中所指定的触发条件在符合条件时自动运行该文件中的工作流程。

在 Ac­tions 页面可以看到很多种语言的 work­flow 文件的模版,可以用于简单的构建与测试。下面是一个简单的 work­flow 文件示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: Hello World
on: push
jobs:
my_first_job:
name: My first job
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master
- name: Run a single-line script
run: echo "Hello World!"
my_second_job:
name: My second job
runs-on: macos-latest
steps:
- name: Run a multi-line script
env:
MY_VAR: Hello World!
MY_NAME: P3TERX
run: |
echo $MY_VAR
echo My name is $MY_NAME

更多细节参阅

与gitlab交互

如何设置ssh key

SSH 秘钥默认储存在账户的主目录下的 ~/.ssh 目录

如:C:\Users\用户\.ssh\

输入命令: ssh-keygen -t rsa -C “your_email@youremail.com”

生成两个文件:

  • id_rsa 私钥
  • id_rsa.pub 公钥

cat id_rsa.pub将这里面的内容复制粘贴到下面图片中的key中

image-20240429150438631

成功后如图:

image-20240429152541770

这样就可以了

之后可以正常使用git与gitlab交互

初次提交到gitlab新项目

一个新项目,不能直接提交代码到master分支(无权限),而应该是新建其它分支,将项目push到新建的分支上,后期再进行merge(发起合并请求)

报错为:![remote rejected]master -> master(pre-receive hook declined) error: failed to push some refs to https:…

git push不上去的原因在于所push的分支权限为protected,只有项目的管理员或者项目的管理员指派的具有相应权限的人才能进行push

具体做法:

1
2
3
4
5
6
git add .
git commmit -m "..."
git branch -m "分支名"#建立新分支并切换过去
#上面这句等同于:git branch 分支名 + git checkout 分支名
git remote add origin 远程仓库地址
git push -u origin 分支名#将新分支上传到远程仓库

图形化git管理软件

SourceTree

image-20211207185614938

新建-创建本地仓库的意思就是 git init

新建-添加已经存在的本地仓库:已经git init的文件夹添加进SourceTree

多人git协作参考

多人git协作参考