项目初始化

mkdir demo
cd demo
git init

其他参数

--initial-branch 自定义初始化的分支,不一定是master
--bare 创建一个裸仓库(纯git目录 没有工作目录)
--template 可以通过模板来创建预先构建好的自定义git目录

工作区和暂存区

工作区就是本地目录(除了.git的隐藏目录),而我们所说的暂存区就在.git文件夹里面,常用的命令git add命令就是把文件提交到版本库中,go commit就是把暂存区的内容合并到当前分支上。

image.png

.git目录解析

关于.git目录,我们可以通过tree .git来查看具体的内容是什么:

image.png

蓝色标识的是文件夹,可以进一步用tree来展开;

接下来,我们可以具体来看看其中具体的文件里面的内容是什么:

cat .git/HEAD

image.png
可以看到HEAD文件的内容就是HEAD指针(当前指针)指向的分支是那一条,这里就是指向master分支

Git remote

接下来,我们再通过以下命令来添加远程仓库

git remote add origin-ssh git@github.com:git/git.git
git remote add origin-http https://github.com/git/git.git

查看下远程仓库的情况,检查是否添加成功

git remote -v

image.png

也就是说我们可以对上面的仓库进行fetch/pull和push的操作了

添加后,我们再打开刚刚.git文件夹里的config配置文件

cat .git/config

image.png

可以看到config文件里已经有了远程仓库的信息

如果仓库名字错了,要修改也可以通过

git remote rename <old> <new>

来修改,更多的操作请按照git remote -h来查阅

如果我们想给同一个Origin设置不同的pushFetchURL怎么办呢?可以通过下面的语句来自定义pushFetch的URL

git remote add origin git@github.com:git/git.git
git remote set-url --add --push origin git@github.com:my_repo/git.git

上面的第一句是正常的添加远程仓库,仓库名为origin,下面这一句就是把origin仓库下的push的URL进行了修改,调用git remote -v结果如下:

image.png

连接远程仓库

很多人会有这样的问题,我配置了Git后,为什么还是不能从远程仓库中拉取代码?其中的一个原因,就是没有配免密认证。

HTTP Remote

URL格式: https://github.com/git/git.git

免密配置的方法:

内存:git config --global credential.helper 'cache --timeput=3600'

硬盘:git config --global credential.helper "store --file /path/to/credential-file" 不指定目录的情况下,默认是~/.git-credentials

但是http协议下的数据传输并不安全,传输双方用同一套密钥来解密数据,所以更多用采用公私钥加密的SSH来进行传输

SSH Remote

URL格式:git@github.com:git/git.git

免密配置:

SSH可以通过公私钥的机制,讲生成的公钥放在服务端,从而实现免密访问,如果是用github的话就是把自己的公钥放在github上

目前使用的Key的类型四种,分别是dsa, rsa, ecdsa, ed25519;默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa和rsa了,所以有的时候如果自己明明配置了SSH免密认证,仍然拉取不到的话,有可能是因为服务端默认拒绝dsa和rsa,这个时候改成ed25519就行

生成ed25519的方法如下:

ssh-keygen -t ed25519 -C "you_email@example.com"

最后在 ~/.ssh(默认路径)下就能看到id_ed25519的私钥和id_ed25519.pub的公钥,我们把公钥的内容上传到github上就行(具体上传的方法自行百度/Google)

Git常见命令下.git目录的变化

我们通过下列命令生成readme文件,并添加到暂存库中

touch readme.txt
vim readme.txt      // 输入hello world
git add .

先通过git status查看下git的状态

image.png

这时再通过tree .git查看目录变化

image.png

我们可以到objects下多了个条信息

我们可以用下面的命令来查看这条信息是啥

git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

image.png
说明这条信息存的就是刚刚提交到暂存库的readme.txt文件的内容

然后再用下面的命令把暂存库的内容提交到当前分支(master)上

git commit -m "add readme"

此时的.git目录又多了两条信息

image.png
我们可以依次用cat-file -p来查看具体的内容

image.png

可以看到这里提到的是刚刚commit的人的信息和comment:add readme,可以猜设是commit的信息

为了验证,我们用git log来看看commit的信息

image.png

可以发现,那串字符就是刚刚commit的id,对于那条信息内还有一条内容tree: …,可以发现后面的字符就是commit后.git文件夹的新增的另一条信息

用同样的命令查看:

image.png

这条信息里blob后面跟着的那串字符就是第一次add后的.git文件夹里新增的信息, 对应的也是相应的文件名readme.txt

讲到这里,我们可以引出git的三个比较重要的Object模型

  • Blob:存储文件的内容
  • Tree:存储文件的目录信息
  • Commit:存储提交信息,一个Commit可以对应唯一的版本号
  • 除此之外还有一个tag的object,下面会有介绍

如何把这三个信息串联在一起呢,其实我们刚刚就是顺着这条路下来的:

  1. 通过Commit寻找到Tree信息,每个Commit都会存储对应的Tree ID,commit的id号可以通过git log来得到

image.png

  1. 通过Tree存储的信息,获取对应的目录树信息,即目录下有哪些文件

image.png

  1. 从 tree中获得的blob ID,通过bolb ID可以获取对应文件的内容

image.png

下面这张图展现的更为清晰:

image.png

Refs

在上面commit后,我们也能发现.git目录的refs/heads目录下多了个分支名master

通过cat命令查看:

image.png

可以发现内容就是master分支上commit的id号

用下面的命令切换到一个新分支test

git checkout -b test

此时heads目录下多了test分支的信息

image.png

即refs的内容就是对应Commit ID,因此把ref当作指针,指向对应的Commit就表示当前ref的版本;

refs/head前缀表示的是分支,ref/tag前缀表示的是标签

Branch:

git checkout -b 可以创建一个新分支,新分支一般用于开发阶段,可以不断添加commit进行迭代的

Tag:

标签一般表示一个稳定的版本,例如v0.0.1;指向的commit一般不会变更,通过git tag命令生成tag

通过git tag v0.0.1的命令后,.git目录变化如下

image.png
通过cat查看信息:

image.png

同样指向当前分支上最新的commit ID,即把这次commit的版本作为tag为v0.0.1的版本

我们还可以给标签添加备注:

git tag -a v0.0.2 -m "my add feature 1"

此时.git目录下的refs/tag下会新增v0.0.2的文件,查看信息发现不是当前分支最新的commit ID,而这串字符也新增在Objects下,说明这是一个Object

image.png

cat-file -p查看后:

image.png

可以发现这里存的就是标签备注的内容,创作者,以及tag对应的commit ID

追溯历史版本

在Ref里讲到,通过Ref指针,我们可以获取当前分支的最新版本,而在object里面,如果在第一次commit后对文件修改又commit的话(通过commit的串联),那么此时此时commit ID的信息里就会多一个parent字段,就是上一个commit版本

修改历史版本

  1. commit -amend:通过这个命令可以修改最近一次的commit信息,修改后commit id会变

    修改后生成一个新的commit id,并且ref指针对应的分支也会指向修改后的,但是原先的commit 信息还会在objects里面,不会被删除

  2. rebase:通过git rebase -i HEAD~3可以实现对最近三个commit的修改,可以的修改如下:

    • 合并commit
    • 修改具体的commit message
    • 删除某个commit
  3. filter - branch

    该命令可以指定删除所有提交中的某个文件或者全局修改邮箱等操作

Git GC

刚刚修改历史版本部分提到,通过commit -amend修改后原先的commit object没有被删除,但是又没有ref指向它,那么它就变成了悬空的object,也就是没有意义,会浪费仓库的体积

可以通过下面的命令来检查仓库内悬空的Object的情况

git fsck --lost--found

image.png

dangling commit后面的字符就是悬空的object的ID

这时我们可以通过git gc命令来删除一些不需要的object,以及会对object进行一些打包压缩来减少仓库的体积。Reflog是用来记录操作日志,防止误操作后数据丢失,通过reflog来找到丢失的数据,这里我们在执行git gc前,需要手动设置日志为过期;通过还要设置prune=now,指定修剪多久之前的对象,默认是两周前

git reflog expire --expire=now --all
git gc --prune=now

image.png

可以通过tree .git来查看修剪的结果

Git Clone & Pull & Fetch

  • Clone

    拉取完整的仓库到本地目录,可以指定分支和深度

  • Fetch

    将远端某些分支最新代码拉取到本地,不会执行merge操作,会修改refs/remote内的分支信息,如果需要和本地代码合并需要手动操作

    这也是为什么经常有人Fetch了远端分支,发现自己本地的分支没有变化,Fetch这会把代码拉取到本地的远端分支,但不会合并到当前分支

  • Pull

拉取远端某分支,并和本地代码合并,操作相当于git fetch + git merge,也可以通过git pull --rebase来完成git fetch + git rebase操作,可能存在冲突需要解决

Git Push

把本地分支上的代码同步到远程仓库中

常用命令

一般使用git push <remote repository> <local repositoty>

例如:

git push origin master

意思把master分支上的代码同步到origin远程仓库中

分支管理类工作-Github Flow

假设我们已经在github上新建了一个repositoty,通过通过ssh clone到了本地,并且认为此时的master分支为工作中的主分支,那么我们touch一个readme,通过add-commit-push到远程仓库,此时我们刷新github可以看到刚刚push上来的readme文件

回到本地,我们新建一个分支feature,feature分支就用了模拟平常团队开发时,其他人的一个开发分支

git checkout -b feature

在这个分支上,他人可以对feature进行修改,然后通过add-commit-push上传到远程仓库

注意这里的push的本地repositoty是feature branch,而不是master

git push origin feature

因为github上默认了第一次push上来的branch为defalut 主分支,那么后续其他推送的分支,github上都会有提示有新的分支推送,这时创建feature分支的人可以创建一个feature到master的Pull Request (PR),repositoty的owner可以在pull request界面执行CI / CA / CR等操作(通常由另一个人来进行code review),确认无误后就可以进行merge操作,将feature分支的内容和master分支内容进行一个合并。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐