Chandy

本文详细介绍了Git的使用,包括身份认证的HTTPS和SSH方式,SSH-Key的生成与配置,以及Git的基本和进阶命令,如commit、push、分支管理和冲突解决。此外,还涵盖了commit管理、版本比较、远程仓库的交互以及标签和提交转移等高级操作。
摘要由CSDN通过智能技术生成

GIT Recipe与食用笔记

关于git的安装和环境配置较简单,笔记中不再赘述,本篇Recipe主要从Git初使用烹饪至Git的高级操作

身份认证

在使用git进行版本控制前,必须预先配置好身份认证模式,否则在使用git命令时会出现certificate verify error之类的身份认证错误。

Git的身份认证有Https和SSH两种。前者同时需要账号和密码,在每次提交版本时都需要输入一遍;后者可以认为是记住密码(SSH-Key),并将密钥保存在本地。

关于Git中SSH的认证机制:

通过SSH(Secure Shell)的命令会生成一个公钥-私钥对(可以理解为相互匹配的键值对),公钥需要添加至Git服务器,私钥则需保存在本地,提交文件时通过公私密钥匹配验证身份信息

配置SSH-Key的步骤记录如下

a) 创建(或选择)一个空文件夹作为保存SSH-Key的路径,在命令行中打开,运行以下代码以验证终端是否支持SSH相关操作

ssh -V

用于制作此Recipe的Windows终端显示

OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2

在Linux远程服务器(Ubuntu)上运行该命令显示

OpenSSH_7.6p1 Ubuntu-4ubuntu0.5, OpenSSL 1.0.2n  7 Dec 2017

b) 可以先配置Git中的用户信息

git config // 查看本机是否配置了个人信息
git config --global user.name "..." // 定义全局用户名
git config --global user.email "..." // 定义全局邮箱地址

如果需要设置局部用户,则将命令中的 –global 替换成 –local

之后可以通过运行

git config --list

查看当前配置信息

c) 可以先在Git Bash中进入ssh根目录

cd ~/.ssh

应当先检查现有的SSH密钥,运行

ls -al ~/.ssh

如果没有.pub文件,则运行如下命令生成SSH密钥

ssh-keygen -t rsa -C "UserX@example.com"

(如果以前创建过.pub文件可以直接按照之后的步骤添加,半角双引号内就是使用者的邮箱,应该最好用GitHub的注册邮箱)
运行后命令行会提示设置当前子目录下的私钥保存地址,打印fingerprint并生成randomart image展示在命令行中。在没有输入文件名称时,密钥默认保存为id_rsa和id_rsa.pub文件(运行ls可查看当前文件夹目录),id_rsa.pub存储的时公钥内容(.pub: public)。

d)
处理公钥:将id_rsa.pub添加到Git服务器的SSH中(GitHub头像框处Settings->SSH and GPG keys->New SSH key,将id_rsa.pub中的内容粘贴到Key文本框,再取个名字作为tittle,点击Add SSH key添加即可)。

处理私钥:
启动SSH-Agent,会返回agent的Pid

eval $(ssh-agent -s)

添加SSH密钥至SSH-Agent,运行

ssh-add ~/.ssh/id_rsa

其中id_rsa是之前设置的SSH名称,
运行后会提示输入passphrase,就是自己设置的密码;
显示Identity added后就是添加成功了

e) 还可以通过如下命令的运行来验证SSH链接是否成功

ssh -T git@github.com

到这里差不多就配置完了

关于ssh指令还有较多参数可以设置和管理注意事项,详细可以直接参考
博客1

git初级命令

初级之初级

git clone ...

在git clone后加上GitHub上(或huggingface, Bitbucket Cloud, ect.)拷贝来的http地址或ssh地址将repository获取至本地,在终端中打开该文件地址后,应当存在.git文件夹(如果设置显示隐藏文件的话),后续的版本建立在这个基础上

运行

git status

会显示当前分支(branch)以及当前改动过的文件信息,主要用于查看当前版本更改状态

运行

git log

可以查看当前分支下的提交(commit)记录等信息

git add <document>

<document>是文件路径,将更改的文件信息添加至暂存区(staging area),如果文件很多嫌麻烦可以一键添加,运行

git add --all

几个名词的简单理解

unstaging area,staging area,工作目录,本地仓库,远程仓库,分支,工作树

1) 在含有.git文件夹的目录下,就是我们的工作目录;对原始版本直接修改,就是在unstaging area中操作,但直接在unstaging

2) staging area 即暂存区,与unstaging相对,本地文件通过add操作后进入此区域,开始参与版本控制,但这个过程不会被git log日志记录,且此时git应该还是认为本地仓库和云端仓库一致

3) 本地仓库的内容变动需要通过commit实现,同时附带一段备注消息,此时会认为本地仓库发生了更改;commit即提交,以分支为操作单元

4) 关于分支(branch),当建立了一个分支指针后,我们的修改仅限于这个分支上,在在push后会可以同时查看不同分支的信息;这里用到指针应该只是避免重复申请空间,通过索引访问区别新旧版本上一点中的commit也仅限于操作当前分支。

5) 工作树(work tree),应该可以直接认为是当前文件夹目录下的二叉树结构

暂存区(staging area)撤销操作

暂存区用于区分当前工作目录和repository中的内容,将本地工作文件添加到云端暂存区防止当前分支被污染;若git add误添加文件,可通过

git reset HEAD

将file退回到unstage区,即从staging区清除该文件,这里的HEAD是一个指定状态

如下指令

git rm file_path

根据file_path访问到文件,同时删除暂存区和分支上的文件,同时工作区也不需要(将文件从工作区一并删除)

git rm --cached file_path

删除暂存区或分支上的文件,保留工作区的源文件,只是不希望该文件参与版本控制

/这里工作区指的是本地工作目录

commit与push基本操作

可以先运行

git log

查看当前工作区域中使用git的操作记录

可以先通过status查看工作区域状态,核对添加至暂存区的文件

以下两行运行命令(均需在含.git文件夹的目录中运行)

git commit -m "msg"
git push origin (NAME)

NAME是repository中主branch的名称,如果是新建了一个分支plans想要上传,则应运行

git push origin plans

git commit 将已经加入到staging area中的文件进行确认,同时添加备注信息"msg",仍然是在本地进行操作

使用commit之后再通过status查看状态,得到

Your branch is ahead of 'origin/main' by 1 commit.

commit是在当前分支下,将本地修改附加上备注信息后添加到本地仓库中;而通过git push会将索引存入本地仓库中的文件或更新同步(上传)至云端,使得本地仓库和云端仓库同步。

以上是在只有一个分支情况下的关于commit和push操作结果的描述,这可以加深对 第4)点 的理解:
在使用多分枝控制时,需要先选择分支,再进行add,commit等操作,这些修改只会更改当前分支中的内容

关于分支(branch)操作

先再简述一下分支,参考Atlassian Git Tutorial上的图,可以理解为分支是通过节点来控制版本的。建立在了解了git push的基础上,分支相当于在本地为仓库添加修改信息后push至云端但不污染云端repository,不同的用户可以创建不同的分支,项目的管理者可以筛选接受,选择合适的分支merge进如main成为新版本

创建分支

git branch [name]

在[name]处输入分支的名字,比如我可以新建一个名字为plans的分支(之后用plans举例)

选择分支

git checkout plans

即指定我接下来的操作在哪个分支上进行,各个分支是互不影响的

Atlassian Git Tutorial上介绍branch时讲到了指针机制,在使用时可以忽略;个人理解的话,一整个社区repository的容量让开发者不足以通过直接复制开辟新的存储空间区分版本,最好的办法就是通过存储指针索引进而同时查看不同版本的架构

在当前分支上进行commit会得到类似于

Your branch is ahead of 'origin/main' by 1 commit.

的回应

合并分支(将分支plans并入主线origin中)

git merge origin/plans

当确认了plans分支中的修改后便可以将其merge到主线中,分支更换依然使用checkout命令

如果之后不再使用plans这个分支,可以考虑删除之,运行

git branch -d plans

关于分支合并,对父指针Fa和子分支So,合并命令为

git merge Fa/So

branch的进阶操作

一些便捷指令

创建并切换分支

git checkout -b xxx yyy

创建分支xxx并指明是yyy的分支

修改当前分支内容并提交至本地仓库

git commit -a -m "amended"
分支管理

由于branch比较重要,就多写一些(大雾)

分支过多时需要进行管理,一些查看分支的操作如下

git branch			// 查看本地分支,当前使用的分支会带*标记
git branch -r		// 查看远程repository分支列表
git branch -a		// 查看全部分支,远程以remotes/开头
git branch -v		// 查看分支的最后一次提交
git branch --merged	// 查看已合并到当前分支的分支
git branch --no-merged	// 查看所有未合并工作分支
分支合并

上面提到的branch操作都是针对线性的分支结构,通过merge将子合并到父上即可,事实上分支合并中存在 快进合并 :当爷孙(相差多代)分支为A, B,两者间为单一线性路径时,实际合并时只是将A处指针移动至B,跳过中间分支。这之间指针存放的分支其实还保留着,所以A向后合并至B后其实还能够向前“回退”,只要AB之间的指针没有手动删除。

当对同一个分支节点建立了不同分支时,这样非线性路径的branch结构就产生了冲突。实际合并时会先通过快进合并对线性路径合并,之后使用三路合并算法解决分支冲突。

关于 冲突 可参考博客2

一些进阶烹饪方式

commit管理

commit是提交操作,在push之前,参与commit的内容只是参与本地仓库的版本控制

必要时,我们可以通过rebase指令合并提交

git rebase -i HEAD~n

可以合并最近的n次提交
在运行该命令后,命令行会自动进入如下vi编辑模式

vi编辑模式展示
在这里插入图片描述

绿色字样pick为可修改的命令(刚进入编辑模式时无法修改,按一下a可编辑),具体参数命令行中已经给出,部分记录如下

使用rebase合并commit
指令
作用
缩写
pick保留commit内容p
reward保留commit内容,但我要修改提交的注释r
edit保留commit内容,但我要停下来修改(不止是注释)e
squash单纯将该commit与先前项合并s
fixup将该commit与前一条合并,但不保留该条注释信息f
exec执行shell命令x
drop丢弃该条commitd

编辑完成后,按Esc键+:(半角)+x(即exec命令)+Enter即可保存并退出,执行命令

另外,如果还需要修改,可运行命令

git rebase --edit-todo

会有如下 hint
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5TigdlWD-1678625156736)(2.jpg)]

按照绿色字样提示操作,可重新进入之前的vi编辑模式

特别地,我们可能再提交时输错了备注,通过如下方式更改

运行

git commit --amend

此时命令行会进入上一条commit的信息界面(vi编辑),按一下a后可修改备注;
编辑完成后,按Esc后输入:(半角冒号),再键入wq+Enter即完成修改并退出vi编辑模式

使用revert撤销提交

通过revert撤销,会保留前后的commit和history,并将本次撤销作为一次新的提交

git revert HEAD         # 撤销前一次commit
git revert HEAD^        # 撤销前前一次commit
git revert commit-id    # 撤销指定id的commit

关于commit-id

这里的commit-id要填长的Hash码

若想要撤销连续的commit,可以运行

git revert -n commit-id-A..commit-id-B

效果是:撤销A-B之间的commit使得版本回到A所在的位置(也就是撤销了A+1到B的提交,左开右闭)

错误撤销回退

如果使用revert错误撤销了commit,此时还是可以补救的,运行

git reflog

找到撤回的commit-id,通过

git reset --hard commit-id

恢复该条commit

既然用到了reset那也就再写一点,reset用法为

git reset [--soft | --mixed | --hard] [HEAD]
param
function
mixed为默认值,可不带参数:不删除空间工作空间改动代码,撤销commit,并撤销add
soft不删除工作空间改动代码,撤销 commit,不撤销 git add
hard删除工作空间改动代码,撤销 commit,撤销 git add

本地版本管理

当远程repository的拥有者更新了仓库,本地工作需要建立在新仓库的基础上,运行

git pull

使用默认参数同步云端仓库进度

具体参数如下

git pull <远程主机名> <远程分支名>:<本地分支名>

刚开始用git的时候永远是无脑push(×),因为都是在一个branch上做的而没有出现问题。

git push <远程主机名> <本地分支名>:<远程分支名>

注:这里半角冒号前后均无空格

值得注意的是,分支推送(git pull)顺序的写法是<来源地>:<目的地>,因此git pull是<远程分支>:<本地分支>,而git push是反过来<本地分支>:<远程分支>

origin就是远程主机,因此完整的git push的一种写法(从本地main到远程main)

git push origin main:main

版本比较git diff

命令

git diff

比较本地工作区和暂存区的差异,这是不加参数的默认情况,参数记录如下

git diff --cached # 比较暂存区与本地最新版本库(最近一次commit)
git diff HEAD     # 比较工作区与本地最新版本库
git diff <commit-id> <path> # 比较指定工作区目录与指定id的commit的差异
git diff --cached <commit-id> <path> # 比较指定目录下暂存区与最新commit的内容
git diff <commit-id1> <commit-id2> # 比较两个commit内容

关于commit-id

查找资料的过程中发现git diff还可用于制作补丁文件patch,干脆来记录一下补丁的打法

diff制作补丁patch

例如我在分支desargues下(我建立的主分支名字为desargues)创建了文件11.cpp,内容为

#include<bits/stdc++.h>
using namespace std;

加入暂存区并确认提交

git add 11.cpp
git commmit -m "std"

然后新建并切换到分支new

git checkout -b new

修改后的11.cpp为

#include<bits/stdc++.h>
using namespace ios;

同样先track

git add .
git commit -m "ios"

可以在git log中查看两次commit的short Hash码
在这里插入图片描述

使用diff比较两个commit的差异并将差异作为输出传入到.patch文件中

git diff b536cf48af9e5fa05fd581c05827948241e9e477 ea79e9ca874a4085f8a20ea55f735087b1659b78 > implement.patch

可以打开implement.patch文件,内容就是diff的输出,例如

在这里插入图片描述

注意,不要将补丁add或者commit,直接切换到原来的分支

git checkout desargues

运行

git apply --check implement.patch

先检查补丁是否可用,无输出即为可用;然后可以应用补丁

git apply implement.patch

参数省略

如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。

特别地,如果省略了本地分支名,会被认为是一个空分支,如

git push origin :main   # 举例,慎用!!!

这等同于删除命令

git push origin --delete main

因此,没有掌握好push的用法,也是一件比较危险的事(大雾,虽然可以撤销)

更详细讲解在博客中有记录

.gitignore的书写

通过文件忽略可以保护信息,如果只是临时指定项目行为,可修改git项目中.git/info/exclude文件,将需要忽略的文件写入。另外,可以创建.gitignore文件实现针对全局的文件。手动建立.gitignore文件后可以放在工作目录的任意位置,然后运行

git config --global core.excludesfile ~/.gitignore

配置git;
之后按照忽略规则的正则语句在.gitignore中书写即可,这里的正则表达比较简单就不记录了,可以参考英文官方文档;需要注意的一点是,书写在.gitignore中的文件名似乎不区分大小写。

需要注意的是,对于已经被track(被追踪,即被纳入版本管理范围),通过修改.gitignore是不能将之忽略的,需要先清除本地track的索引缓存(即将所有文件改为未track的状态)再commit实现忽略

git rm -rf --cached .
git add .
git commit -m msg

详细中文讲解参考博客

特别地,命令

git add -f

可以track被.gitignore指定要忽略的文件:从这个角度看,add操作将某文件添加至暂存区其实就是开始使用git追踪它

remote管理远程仓库

命令

git remote

是针对远程repository的操作,可以用于查看当前工作目录下的项目在远程仓库中的信息

git remote -v

如在xlab-training-program中运行结果为

在这里插入图片描述

顺便提一嘴,这里的origin是远程仓库的别名

复制这里的link,运行

git remote show [link]

即可查看远程仓库信息,例如

在这里插入图片描述

另外,也可以用remote实现提交push的操作

git remote add [name] [link]

name是远程主机地址,前面记录过,可以用origin来指代;上述命令等效于

git push -u origin [branch-name]

这里branch-name是分支名称,比如可以填main或者前面示例分支plans

注:在搜资料的时候看到很多地方用了master,感觉弄不是很懂,去搜origin,master以及main的区别时在百度上发现了2020年GitHub使用main取代master表达的新闻 (乐)

在这里插入图片描述

这下就没啥问题了

关于remote的其他命令还有

git remote rm [name] # delete repository
git remote rename ori_name new_name # rename

关于fetch与pull

简单来讲,git fetch和git pull都能将远程repository中的更新同步到本地,可以认为

git fetch = git pull + git merge

要弄清这两者的区别,先熟悉几个概念:

1) FETCH_HEAD 是一个存储版本指针的文件,记录远程仓库已获取部分的末尾地址,位置为.git/FETCH_HEAD

2) commit-id 每个commit都有一个id编码,rebase处vi编辑模式 有id示例,该编码是一个可以唯一识别版本的序列号,如何查看commit-id

在以上两个概念的基础上,使用fetch控制版本的过程为

git fetch origin plans:tmp
git diff tmp
git merge main/tmp
git branch -d tmp

先拉取远程版本信息的commit-id等内容到本地新建的临时分支tmp中,比较tmp与当前本地仓库版本信息的不同,diff将末尾分支索引保存到.git/FETCH_HEAD中,再将这个tmp并入本地的plans分支上;tmp应该用不到,可以考虑删掉

而如果使用pull的话,只需运行

git pull origin main:plans

这就是为什么说pull=fetch+merge,merge的是那个临时分支tmp

标签的使用

打标签的一个用途是记录当前版本的 里程碑意义 (bushi),参考博客,有【轻量标签】和【附注标签】两种用法,个人认为这篇博客记录的非常详细和完备,因此这里不再赘记(大雾)

提交转移

之前查资料的时候看到一个很有意思的命令cherry-pick,用于多branch下转移commit,这里需要用到commitHash

git cherry-pick <commitHash>

会将指定的提交应用到当前分支,commitHash是提交的Hash码(short)即前面提到的commit-id;运行命令后,当前分支下产生一个新的commit(内容一样Hash值不同),注意要预先切换好分支。

关于产生新提交的理解是,在当前branch尾部添加一个以指定Hash码commit为提交的新分支

另外,一次cherry-pick可以指定转移从A到B之间的多个提交Hash

git cherry-pick [Hash-A] [Hash-B]

这两个提交在时间上必须从早到晚,否则命令无法执行(不报错)

上一命令,是左开右闭的区间值(有点反常),如果要包括左边的值,命令修改为

git cherry-pick [Hash-A]^..[Hash-B]

以上cherry-pick的内容参考了博客

附注

想不出来这部分放哪儿

查看commit-id

运行

git rev-parse HEAD

将获取完整commit的Hash码,例如 3ba8bc5be876878bcd3d65bd04c562b390b80ada

运行

git rev-parse --short HEAD

返回简化的Hash码,即commit-id,与vi编辑模式中显示的commit内容前的码是同一个

关于产生新提交的理解是,在当前branch尾部添加一个以指定Hash码commit为提交的新分支

另外,一次cherry-pick可以指定转移从A到B之间的多个提交Hash

git cherry-pick [Hash-A] [Hash-B]

这两个提交在时间上必须从早到晚,否则命令无法执行(不报错)

上一命令,是左开右闭的区间值(有点反常),如果要包括左边的值,命令修改为

git cherry-pick [Hash-A]^..[Hash-B]

以上cherry-pick的内容参考了博客

附注

想不出来这部分放哪儿

查看commit-id

运行

git rev-parse HEAD

将获取完整commit的Hash码,例如 3ba8bc5be876878bcd3d65bd04c562b390b80ada

运行

git rev-parse --short HEAD

返回简化的Hash码,即commit-id,与vi编辑模式中显示的commit内容前的码是同一个

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值