前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Git基本概念及操作(3)

Git基本概念及操作(3)

作者头像
py3study
发布2020-01-09 12:34:14
8360
发布2020-01-09 12:34:14
举报
文章被收录于专栏:python3

如果使用传统的如CC开发的话,刚开始进行GIT开发可能不是太适应。这个主要是有些概念不一样。比喻在CC中,我们一般是围绕一个主分支进行开发,对一个文件来说,在主分支上会生成不同的版本。同样,我们在每一个版本下面创立新的次分支,在次分支上也会生出很多版本。最后合到主分支,产生下一个版本。那么在GIT中是如何实现这些关联呢?GIT中同样有分支、版本概念。但是没有Configspec概念。tag概念同LABEL概念类似。当然这些概念都同GIT中是如何管理文件版本相关的。首先我们来看GIT是如何将文件对象化管理的,前面我们说GIT同其它版本管理系统不一样是GIT每个版本都不是保存变更,而是全保存。那么如果全保存的话,显然会带来相当大的硬盘开销,其弊端非常明显,那么GIT是怎么消除这个弊端的呢?GIT利用了HASH算法,我们知道在目前已知道的算法中,HASH(SHA-1)算法产生的唯一性还是非常强的。也就是说虽然在工作区域是一个普通文件,但是在仓库中保存的是一个HASH值,由这个HASH值来表示文件,自然空间节省很多。GIT中将这个HASH值称之为对象。这些对象通常是由提交版本、子目录、文件的HASH值组成。对每一个对象通常按类型、大小和内容进行管理。其中最主要的是类型分为三种:

1)blob 这种类型对象是用来存储文件数据,GIT中表现为一个HASH值,如下图所示:

image
image

在以前GIT版本中会有一个单独的目录保存这些文件生成的HASH值通常是.git/objects/fc现在不在有这个fc目录,直接取生成的HASH的前两个值作目录。如下所示,注意在未提交之前,目录是不诞生对象。

[root@wrlinux3 mygit]# git add . [root@wrlinux3 mygit]# ls -latr .git/objects/ total 28 drwxr-xr-x. 2 root root 4096 Apr 28 13:34 pack drwxr-xr-x. 2 root root 4096 Apr 28 13:34 info drwxr-xr-x. 2 root root 4096 Apr 28 13:35 f8 drwxr-xr-x. 2 root root 4096 Apr 28 13:35 d2 drwxr-xr-x. 2 root root 4096 Apr 28 13:35 52 drwxr-xr-x. 7 root root 4096 Apr 28 13:35 .. drwxr-xr-x. 7 root root 4096 Apr 28 13:35 . [root@wrlinux3 mygit]# git hash-object README 52c897fedf9f8728e953a149b7be3b5829a07b1c [root@wrlinux3 mygit]# git hash-object main.c f8b643afbf2c84dc03b777743d3e53a22045cf49 [root@wrlinux3 mygit]# git hash-object testdir/test.c d22409509cd2f0a420e0cb6355008a9676656961

[root@wrlinux3 mygit]# git show d224 int test() { return 0; } [root@wrlinux3 mygit]# git show f8b6 int main() {   return 0; } [root@wrlinux3 mygit]# git show 52c8 new readme

[root@wrlinux3 mygit]# git cat-file -t 52c8 blob [root@wrlinux3 mygit]# git cat-file -t f8b6 blob [root@wrlinux3 mygit]# git cat-file -t d224 blob

2)tree 是一个simple 对象,它的内容就是一个指针表,指针指向的就是这个目录下的所有文件及子目录对象。也就是说这个对象记录了当前目录的元信息。如下图所示:

image
image

正如前面所说,tree也是一串HASH值,这串HASH存储的是元信息。用来表示目录层次关系的。这和一般的SCM系统中是不一样,一般的SCM中目录同文件是一样的保存为版本对象的。

[root@wrlinux3 mygit]# git commit -a -m "init commit" [master (root-commit) 4cfc524] init commit Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

3 files changed, 9 insertions(+) create mode 100644 README create mode 100644 main.c create mode 100644 testdir/test.c [root@wrlinux3 mygit]# ls -latr .git/objects/ total 40 drwxr-xr-x.  2 root root 4096 Apr 28 13:34 pack drwxr-xr-x.  2 root root 4096 Apr 28 13:34 info drwxr-xr-x.  2 root root 4096 Apr 28 13:35 f8 drwxr-xr-x.  2 root root 4096 Apr 28 13:35 d2 drwxr-xr-x.  2 root root 4096 Apr 28 13:35 52 drwxr-xr-x.  2 root root 4096 Apr 28 14:12 bc drwxr-xr-x.  2 root root 4096 Apr 28 14:12 a8 drwxr-xr-x.  2 root root 4096 Apr 28 14:12 4c drwxr-xr-x. 10 root root 4096 Apr 28 14:12 . drwxr-xr-x.  8 root root 4096 Apr 28 14:12 .. [root@wrlinux3 mygit]# ls -latr .git/objects/4c/fc5245433ac0b9277892ccb6e7bd4347aa01ec -r--r--r--. 1 root root 133 Apr 28 14:12 .git/objects/4c/fc5245433ac0b9277892ccb6e7bd4347aa01ec [root@wrlinux3 mygit]# ls -latr .git/objects/a8/8383ae64b09e71666adc12f4bf4760857f8c55 -r--r--r--. 1 root root 115 Apr 28 14:12 .git/objects/a8/8383ae64b09e71666adc12f4bf4760857f8c55 [root@wrlinux3 mygit]# ls -latr .git/objects/bc/a9ca7434467d22451fc370375dbab1a8930433 -r--r--r--. 1 root root 51 Apr 28 14:12 .git/objects/bc/a9ca7434467d22451fc370375dbab1a8930433 [root@wrlinux3 mygit]# git cat-file -t bca9 tree [root@wrlinux3 mygit]# git cat-file -t a883 tree [root@wrlinux3 mygit]# git cat-file -t 4cfc commit [root@wrlinux3 mygit]# git ls-tree bcag fatal: Not a valid object name bcag [root@wrlinux3 mygit]# git ls-tree bca9 100644 blob d22409509cd2f0a420e0cb6355008a9676656961    test.c [root@wrlinux3 mygit]# git ls-tree a883 100644 blob 52c897fedf9f8728e953a149b7be3b5829a07b1c    README 100644 blob f8b643afbf2c84dc03b777743d3e53a22045cf49    main.c 040000 tree bca9ca7434467d22451fc370375dbab1a8930433    testdir [root@wrlinux3 mygit]#

3)commit 也是一种对象,但是这种对象存储是在提交这个点上的元信息,包括提交人、上次提交的版本对象指针及本次提交包含的树节点指针。如下图所示:

image
image

看到这里可能还不是很明白。那我们将面连接起来如下所示:

image
image

从这个图我们应该能够简单的明白了,在GIT中版本这种对象是在最高层,不像一般SCM中,对一个文件来说会记录不同的版本。而在GIT中不是这样的,它是对当下这个项目提交一个版本就进行一次快照。通俗的说就是一个版本包含当前快照下所有对象指针。这样从版本管理的角度来说,要管理的对象的是版本。不再是文件或者目录。这些东西统统可以缩成一个快照。如下图所示:

image
image

在实际上可以使用如下命令查看:

[root@wrlinux3 mygit]# git show -s --pretty=raw 4cfc commit 4cfc5245433ac0b9277892ccb6e7bd4347aa01ec tree a88383ae64b09e71666adc12f4bf4760857f8c55 author ROOT root <root@wrlinux3.nsn-nsn.net> 1335593557 +0800 committer ROOT root <root@wrlinux3.nsn-nsn.net> 1335593557 +0800

    init commit [root@wrlinux3 mygit]#

通过上面的讲述我相信在Commit、Tree和Blob对象之三者的关系有了一个简单的认识,有人总结成了如下一张图,可以说是GIT实现的核心。

image
image

从这张图我们也就明白了前面所说了Commit对象作为GIT管理的核心。GIT的Commit对象它不是说针对单个文件,它是针对的整个项目的。另外还有一种对象,TAG对象。TAG对象是用来标记特定的Commit的,如下图所示,这里可能还不能够清楚解析,后面学习了分支之后会比较清楚的了解。

image
image

前面讲述了四种GIT对象,GIT对象是不可改变的(除了一些撤消操作之外),当然这里面的TAG对象有时候也可以称之为References引用,引用是可以移动,引用都是基本版本Commit对象的。因此从另外一个角度来说TAG也可以称之为引用。但实际上我们打了一个TAG之后是不能移动,他的特性与对象又一样。常用的引用主要分为分支、头、及远程分支。如下图所示:

image
image

从上图可以看出,HEAD,BRACH,REMOTE,TAG最下层都是Commit对象,也就是GIT管理的粒度是以Commit来决定。Commit相当于一个快照。我们可以从git目录查看到这种组织方式。

[root@wrlinux3 mygit]# cat .git/HEAD ref: refs/heads/master [root@wrlinux3 mygit]# ls -l .git/refs/ total 8 drwxr-xr-x. 2 root root 4096 Apr 28 14:12 heads drwxr-xr-x. 2 root root 4096 Apr 28 13:34 tags [root@wrlinux3 mygit]# ls -l .git/refs/tags/ total 0 [root@wrlinux3 mygit]# ls -l .git/refs/heads/ total 4 -rw-r--r--. 1 root root 41 Apr 28 14:12 master [root@wrlinux3 mygit]# cat .git/refs/heads/master 4cfc5245433ac0b9277892ccb6e7bd4347aa01ec [root@wrlinux3 mygit]# git cat-file -t 4cfc commit [root@wrlinux3 mygit]#

另外GIT也使用了优化算法,就是前面两个版本之间如果相同的对象没有发生改变的话,会直接采用链接的方式。如下图所示:

image
image

这样就可以省去很多对象的产生。前面我们对Reference对象没有特别强调,只是强调他们是可以随着分支移动。这一点与很多SCM系统不同,比喻说CC,分支拉出来就固定,分支上生长出版本。而GIT不同,GIT上的分支它是随着版本移动的。我们来研究如下:

1)分支 GIT中分支本质上是个指向Commit 对象的可变分支。默认情况下Git使用master作为分支的默认名字,每次一提交,master指针都会自动向前移动到下一个版本的commit对象上。当然你也可创建一个分支,使用命令git branch testing.如下图所示:

image
image

可以通过仓库显示如下:

[root@wrlinux3 mygit]# git branch testing [root@wrlinux3 mygit]# git branch * master   testing

[root@wrlinux3 mygit]# cat .git/HEAD ref: refs/heads/master

[root@wrlinux3 mygit]# cat .git/refs/heads/master 4cfc5245433ac0b9277892ccb6e7bd4347aa01ec [root@wrlinux3 mygit]# cat .git/refs/heads/testing 4cfc5245433ac0b9277892ccb6e7bd4347aa01ec [root@wrlinux3 mygit]#

这时我们可以看master和testing都指向4cfc Commit对象,同时master前面带有*号,HEAD中指向master,表示当前工作分支还在master上,如果想要在testing上工作,就必须修改HEAD指针。使用git checkout testing就可以切换了。

[root@wrlinux3 mygit]# git checkout testing Switched to branch 'testing' [root@wrlinux3 mygit]# cat .git/HEAD ref: refs/heads/testing [root@wrlinux3 mygit]#

这时HEAD指针指向Testing分支了。

image
image

因为在GIT中创建和删除分支基本上不需要耗费计算机资源,因为分支在GIT表示的就是一个指向版本的指针(这个文件中保存的是版本对像的SHA值)。所以GIT是非常鼓励多建分支。那么很明显分支太多,也会带来版本合并的麻烦,所以一般来说建议尝试一个新功能在一个分支上开发完毕后,进行测试完成后就合并到主分支上再删除原来分支。下面我们围绕一个开发过程来进行分支的创建和合并。

image
image

对应的版本图如下:

image
image

对应的操作记录如下:

[root@wrlinux3 mygit]# git checkout -b iss53 Switched to a new branch 'iss53' [root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git commit -a -m 'add new variable to calculate the value on branch [iss53]' [iss53 2f1f64e] add new variable to calculate the value on branch [iss53] Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 5 insertions(+), 1 deletion(-) [root@wrlinux3 mygit]# git checkout master Switched to branch 'master' [root@wrlinux3 mygit]# git checkout -b 'hotfix' Switched to a new branch 'hotfix' [root@wrlinux3 mygit]# git branch * hotfix   iss53   master   testing [root@wrlinux3 mygit]# cd testdir/ [root@wrlinux3 testdir]# vi test.c [root@wrlinux3 testdir]# git commit -a -m 'fixed the issue" [root@wrlinux3 testdir]# cd .. > ls > ^C [root@wrlinux3 testdir]# cd .. [root@wrlinux3 mygit]# ls main.c  README  testdir [root@wrlinux3 mygit]# git commit -a -m 'fixed the issue" > ^C [root@wrlinux3 mygit]# git commit -a -m 'fixed the issue' [hotfix 85412f9] fixed the issue Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 4 insertions(+), 1 deletion(-) [root@wrlinux3 mygit]# git checkout master Switched to branch 'master' [root@wrlinux3 mygit]# git merge hotfix Updating 4cfc524..85412f9 Fast-forward testdir/test.c |    5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) [root@wrlinux3 mygit]# git branch -d hotfix Deleted branch hotfix (was 85412f9). [root@wrlinux3 mygit]# git branch   iss53 * master   testing [root@wrlinux3 mygit]# vi testdir/test.c [root@wrlinux3 mygit]# git checkout master Already on 'master' [root@wrlinux3 mygit]# git merge iss53 Merge made by the 'recursive' strategy. main.c |    6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) [root@wrlinux3 mygit]# git merge iss53 Already up-to-date. [root@wrlinux3 mygit]#

通过GIT进行合并,因为是基本文本方式合并,可能不与CC中图形化直观,但是一定要注意两点,一点是DIFF工具可改,二点是MERGE前的工作区应该是干净的。当提示一些CONFLIC时需要手工打这些文件进行修改。

[root@wrlinux3 mygit]# git mergetool No files need merging [root@wrlinux3 mygit]# git checkout testing Switched to branch 'testing' [root@wrlinux3 mygit]# ls main.c  README  testdir [root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git commit -a -m "test comments" [testing d2569cb] test comments Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 1 insertion(+) [root@wrlinux3 mygit]# git checkout master Switched to branch 'master' [root@wrlinux3 mygit]# git mergetool No files need merging [root@wrlinux3 mygit]# git merge testing Auto-merging main.c CONFLICT (content): Merge conflict in main.c Automatic merge failed; fix conflicts and then commit the result. [root@wrlinux3 mygit]# git status # On branch master # Unmerged paths: #   (use "git add/rm <file>..." as appropriate to mark resolution) # #    both modified:      main.c # no changes added to commit (use "git add" and/or "git commit -a") [root@wrlinux3 mygit]# git merge testing error: 'merge' is not possible because you have unmerged files. hint: Fix them up in the work tree, hint: and then use 'git add/rm <file>' as hint: appropriate to mark resolution and make a commit, hint: or use 'git commit -a'. fatal: Exiting because of an unresolved conflict. [root@wrlinux3 mygit]# git status # On branch master # Unmerged paths: #   (use "git add/rm <file>..." as appropriate to mark resolution) # #    both modified:      main.c # no changes added to commit (use "git add" and/or "git commit -a") [root@wrlinux3 mygit]# git commit -a -m "commit stat" [master 5e453fa] commit stat Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

[root@wrlinux3 mygit]# git st # On branch master nothing to commit (working directory clean)

前面讲了一些通用的分支操作,通过创建分支、合并分支并最终形成一个稳定的版本的过程,这个过程也是我们常见的SCM的管理职责,目前SCM人员需要制定主分支、开发分支、特性分支,通过管控这些分支来保证整个产品的质量的稳定。如下图所示:

image
image

上图中不同的开发分支,代表了产品成熟的不同的周期。通过维护这些分支的生命周期来维护产品的生命周期。这里还需要强调的我们前面所进行的操作都是向有操作,也就是MERGE操作,实际上还有一种操作叫REBASE操作,rebase比较复杂,轻易不要使用,因为rebase会将当前已提交的版本历史给删除掉了,这样的话,一旦别人根据这些开发的话会产生丢失版本情况。如下图所示:

image
image

对应的操作记录如下:

[root@wrlinux3 mygit]# git branch experiment [root@wrlinux3 mygit]# git branch   experiment * master [root@wrlinux3 mygit]# git checkout -b experiment fatal: A branch named 'experiment' already exists. [root@wrlinux3 mygit]# git checkout -B experiment Switched to and reset branch 'experiment' [root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git commit -a -m 'commit on experiment' [experiment 774b7ee] commit on experiment Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 2 insertions(+), 3 deletions(-) [root@wrlinux3 mygit]# git checkout master Switched to branch 'master' [root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git commit -a -m 'commit on master' [master cbe0f99] commit on master Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 1 insertion(+), 2 deletions(-) [root@wrlinux3 mygit]# gitk [root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git commit -a -m 'commit on master more' [master 8f20d8c] commit on master more Committer: ROOT root <root@wrlinux3.nsn-nsn.net> Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"     git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

1 file changed, 1 insertion(+) [root@wrlinux3 mygit]# git checkout experiment Switched to branch 'experiment' [root@wrlinux3 mygit]# git rebase master

It seems that there is already a rebase-apply directory, and I wonder if you are in the middle of another rebase.  If that is the case, please try     git rebase (--continue | --abort | --skip) If that is not the case, please     rm -fr /work/bongos/mygit/.git/rebase-apply and run me again.  I am stopping in case you still have something valuable there. [root@wrlinux3 mygit]# rm -fr /work/bongos/mygit/.git/rebase-apply [root@wrlinux3 mygit]# git rebase master First, rewinding head to replay your work on top of it... Applying: commit on experiment Using index info to reconstruct a base tree... Falling back to patching base and 3-way merge... Auto-merging main.c CONFLICT (content): Merge conflict in main.c Failed to merge in the changes. Patch failed at 0001 commit on experiment

When you have resolved this problem run "git rebase --continue". If you would prefer to skip this patch, instead run "git rebase --skip". To check out the original branch and stop rebasing run "git rebase --abort".

[root@wrlinux3 mygit]# vi main.c [root@wrlinux3 mygit]# git rebase --continue main.c: needs merge You must edit all merge conflicts and then mark them as resolved using git add [root@wrlinux3 mygit]# git add . [root@wrlinux3 mygit]# git rebase --continue Applying: commit on experiment [root@wrlinux3 mygit]# git st # On branch experiment nothing to commit (working directory clean) [root@wrlinux3 mygit]# gitk [root@wrlinux3 mygit]# git branch * experiment   master [root@wrlinux3 mygit]#

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/09/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档