git学习笔记

1.     git基础概念

         git客户端并不只是提取最新版本的文件快照,而是把代码仓库完整的镜像下来,git核心本质上是一个键值对数据库。可以向该数据库插入任意类型的内容,他会返回一个键值,通过该值可以在任意时刻再次检索该内容。

1.1.      Git发展史

1.2.      工作区

         工作区是当前工作空间,也是当前能在本地文件夹下面看到的文件结构。初始化工作空间或者工作空间 clean 的时候,文件内容和 index 暂存区是一致的,随着修改,工作区文件在没有添加到暂存区时候,工作区将和暂存区是不一致的。

1.3.      暂存区

         暂存操作会对先每一个文件计算校验和checksumGit 使用SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个SHA-1 哈希值,作为指纹字符串,该字串由40 个十六进制字符,并将此结果作为数据的唯一标识和索引),然后把当前版本的文件快照保存到本地Git 仓库中(Git 使用blob 类型的对象存储这些文件内容快照),并将校验和加入暂存区域。注意:所有保存在Git 数据库中的东西都是用此哈希值来作索引的,不是靠文件名。

1.4.      本地库

         git 是分布式版本控制系统,和其他版本控制系统不同的是他可以完全去中心化工作,你可以不用和中央服务器进行通信,在本地即可进行全部离线操作,包括 loghistorycommitdiff 等等。完成离线操作最核心是因为 git 有一个几乎和远程一样的本地仓库,所有本地离线操作都可以在本地完成,等需要的时候再和远程服务进行交互。

1.5.      远程仓库

         中心化仓库,所有人共享,本地仓库会需要和远程仓库进行交互,也就能将其他所有人内容更新到本地仓库把自己内容上传分享给其他人。结构大体和本地仓库一样。



2.     .git目录下文件的介绍

         hooks                 (钩子函数的一个库 类似于回调函数)

         info                      (包含一个全局性的排除文件)

         objects                (目录存储所有数据内容)

         refs                      (目录存储指向数据(分支)的提交对象的指针)

         config                  (文件包含项目特有的配置选项)

         description          (显示对仓库的描述信息)

         HEAD                (文件目前被检出的分支)

         logs                    (日志信息)

         index                   (文件保存暂存区的信息)



 

3.     Git的四个对象

         git 主要有四个对象,分别是 BlobTree Commit Tag 他们都用 SHA-1 进行命名。可以用 git cat-file -t {hash}查看每个 SHA-1 的类型,用 git cat-file -p {hash}查看每个对象的内容和简单的数据结构。git cat-file git 的瑞士军刀,是底层核心命令。

3.1.      git 对象

         git对象的类型为blob。他只用于存储单个文件内容,一般都是压缩过二进制的数据文件,不包含任何其他文件信息,比如不包含文件名和其他元数据。

可以用下面命令返回一个内容的hash值用来标识这句话,但是并没有实际保存。内容不一样对应的hash值不一样。

          echo "hello" | git hash-object --stdin

下面命令使用 -w 的选项,同样会返回一个hash值用来标识这句话,但也会实际保存一个blob对象的文件。

          echo "hello" | git hash-object -w --stdin

         查看有没有存在 可以通过 find . -type f 找对应hash的文件,里面的内容是压缩的,通过 git cat-file -p {hash} 查看内容。使用 git cat-file -t {hash} 查看git对象的类型为 blob

         上面的操作都是通过标准输入执行,下面我们新建一个名为a.txt的文件,并将其添加到git数据库中生成一个git对象。

          git hash-object -w a.txt

         如果文件更改git数据库里面不会自动的添加要手动添加过去 这时会再添加一个git对象,也就是说文件的改动不会修改原blob对象, 他会再次把该文件添加为一个新的blob对象。使用下面命令添加修改过的文件。

          git hash-object -w a.txt

         实质上Git对象是一个KYEVALUE hash/value)类型数据库,git对象不能当作项目的一次快照,只是组成项目的一部分,那么将存在下面问题。记住文件的每一个(版本)对应的hash值并不现实,在git中,文件名并没有被保存,只能通过hash检索。而且。注意:此时的操作只是针对本地库进行操作,并不涉及暂存区。

3.2.      树对象

         树对象类型为Tree。对应文件系统的目录结构,里面主要有:子目录 (tree),文件列表 (blob),文件类型以及一些数据文件权限模型等。树对象能够解决文件名保存的问题,也允许我们将多个文件组织到一起。暂存区中文件名字不变,如果改变文件的内容,就会重新生成一个hash。可以通过update-indexwrite-treeread-tree 等命令构建树对象。树对象存在以下问题:

Ø  不知道hash值对应的是哪一个版本

Ø  不知道这个版本的一些基础信息

3.3.      提交对象

         提交对象类型为Commit。他是一次修改的集合,是当前所有修改的文件的一个集合,可以类比一批操作的“事务”。是修改过的文件集的一个快照,随着一次提交(commit)操作,修改过的文件将会被提交到本地库中。通过提交对象,在版本化中可以检索出每次修改内容,是版本化的基石。提交对象有如下特点:

Ø  提交对象完美的解决了上面的问题

Ø  本质就是给树对象做一层包裹包含项目的基础信息

Ø  commit-tree创建一个提交对象,为此需要指定一个树对象的hash,以及该提交的父提交对象 

Ø  echo "First commit" | git commit-tree 019fb2c52 -p d248eb19a125c

Ø  真正代表一个项目的是一个提交对象(数据和基本信息)这是一个链式的!!

3.4.      tag 对象

         tag 是一个“固化的分支”,一旦打上 tag 之后,这个 tag 代表的内容将永远不可变,因为 tag 只会关联当时版本库中最后一个 commit 对象。分支随着不断的提交,内容会不断的改变,因为分支指向的最后一个 commit 不断改变。所以一般应用或者软件版本的发布一般用 tag

         tag 的两种类型

Ø  ightweight (轻量级)

         创建命令:git tag tagName

         这种方式创建的 Taggit 底层不会创建一个真正意义上的 tag 对象,而是直接指向一个提交对象,此时如果使用 git cat-file -t tagName 会返回一个 commit 对象。

Ø  annotated (含附注)

         创建命令:git tag -a tagName -m ''

         这种方式创建的标签,git 底层会创建一个 tag 对象,tag 对象会包含相关的提交对象信息和标签等额外信息,此时如果使用 git cat-file -t tagName 会返回一个 tag 对象。如果想对之前的提交打标签,那么只需要找到对应的hash即可。



 

4.     仓库配置

         在进行仓库配置的时候,如果指定 --system ,则是系统级别的配置,将会对所有的用户生效。指定 -global 的时候,会对当前用户生效。没有指定 --system 或者 --global 的时候,只在当前仓库生效。

4.1.      中文配置

         git status查看有改动但未提交的文件时总只显示数字串,显示不出中文文件名。在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码。将git 配置文件 core.quotepath项设置为false,即可解决。quotepath表示引用路径。

git config --system core.quotepath false

4.2.      项目级别

仓库级别仅在当前本地库范围内有效,信息保存位置:.git/config 文件

git config user.name zhangsan

git config user.email zsadmin@admin.com

4.3.      系统用户级别

登录当前操作系统的用户范围,信息保存位置:~/.gitconfig 文件。注意用户名称和邮箱不一定是一样的。

git config --global user.name zhangsan

git config --global user.email zsadmin@admin.com

4.4.      命令别名配置

git log --oneline --decorate --graph --all 配置别名为: git logall  (用户级别配置)

git config --global alias.logall "log --oneline --decorate --graph --all"

4.5.      查看配置

查看系统config

    git config --system --list

查看当前用户(global)配置

    git config --global  --list

查看当前仓库配置信息

    git config --local  --list

4.5.1.          可以使用如下方式

         这种方式可以查看同时也可以编辑

git config --global --edit

4.6.      其他配置

4.6.1.          配置ssl证书

         该项建议添加为系统级别配置。/etc/pki/git/ca.crt 为实际证书绝对路径。也可以忽略ssl验证,两者选一即可。建议添加CA证书,如果找不到CA证书,就只能忽略ssl验证。

# 配置CA证书

git config --system http.sslcainfo "/etc/pki/git/ca.crt"

 

# 或略ssl验证

git config --system http.sslverify false

4.6.1.          Git 换行符自动转换

         在各操作系统下,文本文件所使用的换行符是不一样的。UNIX/Linux 使用的是 0x0ALF)。但 DOS/Windows 一直使用 0x0D0ACRLF)作为换行符。Git提供了一个“换行符自动转换”功能。这个功能默认处于“自动模式”,当你在签出(拉取)文件时,它试图将 UNIX 换行符(LF)替换为 Windows 的换行符(CRLF);当你在提交文件时,它又试图将 CRLF 替换为 LF。可以关闭它,按个人需求设置。

#提交检出均不转换(不建议配置)

git config --global core.autocrlf false

 

#提交时转换为LF,检出时转换为CRLF(建议配置)

git config --global core.autocrlf true

 

#提交时转换为LF,检出时不转换(建议配置,推荐配置)

git config --global core.autocrlf input

 

#拒绝提交包含混合换行符的文件(建议设置)

git config --global core.safecrlf true

 

4.7.      级别优先级

         就近原则:项目级别优先于系统用户级别, 二者都有时采用项目级别的签名,如果只有系统用户级别的签名,就以系统用户级别的签名为准,二者都没有不允许

 



5.     基本操作

5.1.      底层命令

         调用底层命令完成一次版本的提交。初始化版本库,创建一个文件a.txt。作为初始版本。调用git cat-file命令查看仓库中对象实体的类型、大小和内容的信息。

git cat-file (-| -s | -e | -p | <type> | --textconv ) <object> ...

<type> can be one of: blob, tree, commit, tag

    -t                    show object type (查看类型)

    -s                    show object size(查看大小)

    -p                    pretty-print object's content(查看内容)

......

创建a.txr 内容为version 1,并创建为blob对象。

echo "version 1" >> a.txt

git hash-object -w a.txt

使用update-index a.txt 的首个版本创建一个暂存区,并通过write-tree生成树对象。

git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 a.txt

git ls-files -s

git write-tree

         命令说明:

                   文件模式为100644 表明这是一个普通文件

               文件模式为100755 表明这是一个可执行文件

               文件模式为120000 表明这是一个符号连接

               --add 因为此前该文件并没有在暂存区中 首次要加add

              --cacheinfo 因为要添加的文件在git数据库中,没有位于当前目录下

新增new.txt,将new.txta.txt 文件的第二个版本分别塞进暂存区。并通过write-tree生成第二个树对象。

echo 'new file' >> new.txt

echo 'version 2' >> a.txt

git hash-object -w a.txt

git update-index --cacheinfo 100644 0c1e7391ca4e59584f8b773ecdbbb9467eba1547  a.txt

git hash-object -w new.txt

git update-index --add --cacheinfo 100644 fa49b077972391ad58037050f2a75f74e3671e92 new.txt

git ls-files -s

git write-tree

将第一个树对象加入到第二个树对象,使之成为一个新的树对象。

git read-tree --prefix=bak 4d146fee4a1d58fb49e94a4b5fbec352653fce30

git ls-files -s

git write-tree

         生成树对象即是对暂存区做一个快照放到git数据库中,对象类型是一个树对象,树对象里面的内容是暂存区的快照,即项目快照。可以认为是项目的一个版本。

         使用commit-tree 命令创建一个提交对象,为此需要指定一个树对象的哈希值,以及该提交对象的父提交对象,第一次没有则无需指定。

echo "First commit" | git commit-tree 4d146fee4a1d

echo "Second commit" | git commit-tree 3a85019f136e -p 361fb3efc75bae5

echo "Third commit" | git commit-tree 34111a1c2fae -p a1b377723c0ef861

83baae61804e65cc73a7201a7252750c76066a30     文件a.txt 第一个版本

4d146fee4a1d58fb49e94a4b5fbec352653fce30     第一个树对象的哈希

0c1e7391ca4e59584f8b773ecdbbb9467eba1547     文件a.txt 第二个版本

fa49b077972391ad58037050f2a75f74e3671e92     文件new.txt的第一个版本

3a85019f136efc5b9f75fd21c9d458df8ea23d3a     第二个树对象的哈希

34111a1c2fae9d429e173d91d90cae6c7b679e31     第三个树对象的哈希

361fb3efc75bae5e683497d09cb72c3a2a1d6810     第一个提交对象

a1b377723c0ef8614b3380772ec35539bbb958c1     第二个提交对象

a898a5484ce29891fa50a61c36cde47f25638152     第三个提交对象

         此时我们版本库结构如下,共有三次提交,三个项目版本。

         使用如下命令,更新master(如果你在其他分支上,则需要指定为其他分支)分支的指针,指向我们的提交对象对象,完成一次真正的提交工作。

git update-ref refs/heads/master 361fb3efc75

git update-ref refs/heads/master a1b377723c0

git update-ref refs/heads/master a898a5484ce

         通过底层命令我们得知,生成树对象,就意味着一次版本的生成,暂存区的文件是会被覆盖的,也就是说将文件添加到暂存区是生成树对象的过程,且该过程并不是将工作区文件塞到暂存区,而是先存到本地库,然后在从本地库读到暂存区。对于本地库每次操作都是新增,所以才能恢复到任意时刻的版本,只要找到对应的哈希,前提是文件已提交到本地库。对于上面的操作,只需要使用两个上层命令即可完成。

5.2.      上层命令

         通过底层命令我们完成版本控制,但是该过程及其的繁琐,如果一次哈希或文件名写错,将会污染整个版本库,所以日常我们使用上层命令操作即可,其实上层命令即使对底层命令的分装。

看工作区、暂存区状

git status

将工作区的“新建/修改添加到暂存区

git add [file name]

git ls-files -s  查看暂存区的当前状态

提交到本地库

git commit -m "commit message" [file name]

git log

修改提交信息

git commit --amend

修正本次提交所使用的用户身份

git commit --amend --reset-autho

查看日志

git log

git log --pretty=oneline --abbrev-commit

git log --pretty=oneline

git log --oneline

git reflog

 

HEAD@{移动到当前版本需要多少步}

前进后退

         本质是HEAD指针的移动

l   基于索引值操作[推荐]

git reset --hard [局部索引值]

git reset --hard a6ace91

l   使用^符号:只能后退

git reset --hard HEAD^

注:一个^表示后退一步,n 个表示后退 n

l   使用~符号:只能后退

git reset --hard HEAD~n

注:表示后退 n

Reset 三个参数的比较

--soft 参数

         仅仅在本地库移动HEAD指针

--mixed 参数

         在本地库移动HEAD指针

         重置暂存区

--hard 参数(建议使用该参数)

         在本地库移动HEAD指针

         重置暂存区

         重置工作区

删除文件并找回

Ø  前提:删除前,文件已经提交到本地库

Ø  操作:git reset --hard [指针位置(即commit哈希值)]

Ø  删除操作已经提交到本地库:指正位置指向历史记录

Ø  删除操作尚未提交到本地库:指正位置使用HEAD

Ø  可在.git/logs/HEAD查看所有commit的哈希值。

比较文件差异

Ø   git diff [文件名]

                            将工作区的文件和暂存区的文件进行比较

Ø   git diff[本地库中历史版本][文件名]

                            将工作区中的文件和本地库历史记录比较

Ø  不带文件名则比较多个文件

标签操作

为某一历史提交打标签:

     git log --pretty=oneline --abbrev-commit

     git tag  -a v0.9 f52c633 -m  '第一次发布'

如果标签打错了,也可以删除:

     git tag -d 0.1

         因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。如果要推送某个标签到远程,使用命令git push origin <tagname>

     git push origin v1.0

         或者,一次性推送全部尚未推送到远程的本地标签:

     git push origin --tags

         如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除,然后在删除远程。要看看是否真的从远程库删除了标签,可以登陆远程git查看。

     git tag -d v0.9

     git push origin :refs/tags/v0.9

切换到某个标签

     git checkout v0.9

Rebase

         https://www.liaoxuefeng.com/wiki/896043488029600/1216289527823648分支管理

切换分支一定要确保暂存区是干净的。

存储

Ø  git stash save "save message" 执行存储时,添加备注,方便查找。

Ø  解决的问题 不想过多的创建提交比如iss53那个分支

Ø  git stash list 查看存储

Ø  git stash apply  拿出栈顶的元素 但是不会消除

Ø  git stash drop stash@{0}

5.3.      什么是分支

         在版本控制过程中,使用多条线同时推进多个任务。

5.4.      分支的好处

Ø  同时并行推进多个功能开发,提高开发效率

Ø  各个分支在开发过程中, 如果某一个分支开发失败, 不会对其他分支有任何影响。失败的分支删除重新开始即可。

5.5.      分支的操作

1)         创建分支

git branch [分支名]

2)         查看分支

git branch -v

3)         切换分支

git checkout [分支名]

4)         合并分支

第一步:切换到接受修改的分支(被合并,增加新内容)上

    git checkout [被合并分支名]

第二步:执行 merge 命令

    git merge [有新内容分支名]

5)         删除分支

git branch -d home                # 删除本地分支 (home)

git push origin --delete home     # 删除远程分支 (home)

6)         解决冲突

冲突的表现

        

         冲突的解决

               第一步:编辑文件,删除特殊符号

              第二步:把文件修改到满意的程度,保存退出

              第三步:git add [文件名]

              第四步:git commit -m "日志信息"

                       注意:此时 commit 一定不能带具体文件名。这种操作会导致分支较乱。会产生下图效果。最好的方法是使用rebase 这样操作后分支始终保持一条线。

https://blog.lilydjwg.me/2015/2/8/create-git-commits-with-plumbing-commands.79611.html

git ls-tree -r master 相当于(git ls-tree -r 'master^{tree}' 分支名实际上是指向这个分支上的最后一个对象的符号引用)

5.6.      导出代码

         生成一个可供发布的压缩包,从命名树创建文件的存档。创建包含指定树的树结构的指定格式的存档,并将其写入标准输出。如果指定了<前缀>,则它将预置为归档文件中的文件名。

--format=<fmt>  

结果存档的格式:tarzip。如果没有给出这个选项,并且指定了输出文件,那么如果可能的话,从文件名中推断格式(例如,写入“foo.zip”使得输出为zip格式)。否则,输出格式是tar

示例:创建一个包含当前分支上最新提交内容的tar归档文件,并将其提取到/var/tmp/junk目录中。

git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)

示例:为v1.4.0版本创建一个压缩tarball

git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz

示例:同上,但使用内置的tar.gz处理。

git archive --format=tar.gz --prefix=git-1.4.0/ v1.4.0 > git-1.4.0.tar.gz

示例:与上面相同,但格式是从输出文件中推断出来的。

git archive --prefix=git-1.4.0/ -o git-1.4.0.tar.gz v1.4.0

示例:配置一个“tar.xz”格式来制作LZMA压缩的tarfiles。使用它来指定--format=tar.xz或创建一个输出文件-o foo.tar.xz

git config tar.tar.xz.command "xz -c"

示例:

git archive --prefix=git/ --output ./output.tar.gz master

git archive --prefix=git/ --format=tar master |gzip >git-1.4.0.tar.gz

 

 

 



6.     本地库配置远程仓库

6.1.      配置远程仓库地址

         配置远程地址后可以拉去远程代码,其中origin 是一个别名,可以写别的。只是习惯这样写。

6.1.1.          添加一个远程地址

git remote add origin [url]

6.1.2.          修改命令

git remote origin set-url [url]

6.1.3.          删除远程地址

git remote rm origin

6.1.4.          查看远程地址配置

git  remote -v

6.2.      远程跟踪分支

         从远程分支 checkout 出来的本地分支,称为跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git pushGit 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。

         在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master之外的其它分支。刚才我们已经看到了这样的一个例子:git checkout -b [分支名] [远程名]/[分支名]。如果你有 1.6.2 以上版本的 Git,还可以用 --track 选项简化,本地分支可以和远程分支不同名。

git checkout --track origin/develop

6.2.1.          配置远程跟踪分支

         其中 <branch> 填写实际远程分支名,但一般情况远程分支和本地分支名字相同,便于区分。

git branch --set-upstream-to=origin/<branch> develop

6.2.2.          查看本地分支关联的远程分支

git branch -vv

6.3.      代码的拉取和推送

6.3.1.          拉取代码

         拉取代码到本地的远程跟踪分支origin/<branch>,然后在合并到本地分支<branch>,实际上这两步操作可以合并成一个操作,即 git pull = git fetch + git merge

git fetch

git merge

6.3.2.          推送代码

         推送代码到远程分支,使用如下命令,将本地develop推送至远程仓库,如果远程库没有这个分支,将自动新建。

git push origin develop

 

# 将本地develop分支推送至远程master分支

git push origin develop:master

 

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2024 Outsrkem
  • 访问人数: | 浏览次数:

      请我喝杯咖啡吧~

      支付宝
      微信