路漫漫其修远兮
吾将上下而求索

git学习:基础原理和配置

简介

版本控制工具,分类:

  本地版本控制系统,分布式:可以不需要互联网在本地工作,只有需要提交或者拉取的时候才需要网络

  集中式版本控制系统:就像在线编辑博客一样,必须要联网才能进行,最后都会保存在服务器上面

  常用工具:git(分布式),cvs-svn(集中式)

版本记录中,当前的版本和第一版之间只是某个文件多了几行数据,svn记录的是两个版本之间的差异,将差异记录下来,将来像打补丁一样保存到新的版本上面。git工作方式类似于快照,每次记录的都是文件的完整内容,文件1发生变化,则在第二版中文件1单独保存,其他的文件还是第一版的文件的映射。两个版本中相同的文件只保存一份。当第二版是在第一版的基础上增加了一个文件,则第二版保存的是第一版的未变化文件的快照+第二版增加的或者修改的文件,而不是其变化的部分

下面是cvs的每个版本数据保存方式:

deltas.png

下面是git的每个版本数据保存方式

deltas.png

Git 有三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。 已提交表示数据已经安全的保存在本地数据库中。 已修改表示修改了文件,但还没保存到数据库中。 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。

git分为几个区域

工作区:working directory:工作的区域,可以在这个目录中进行编辑等基本的操作。默认情况下,呈现的一直是最新的状态,看到的一直是当下的某一个版本的文件,目录下面有一个隐藏目录记录着所有的版本信息和更改信息。

暂存区:staging area

版本仓库:repository

所有的版本记录和版本变化状态都记录在工作目录当下的一个隐藏目录中:.git目录中

image.png

当编辑好后需要进行备份以便以后某个时期可以回溯到当前的状态,可以将当前的工作目录中所有的内容进行快照,类似于文件系统的快照类似,保存在当前的版本库中,也可以将当前的版本文件推送到远程的版本库中。

通过快照的方式进行存储,不管是图片,文本还是其他格式的文件,(文件由元数据和数据组成)文件的元数据和文件数据都在git的数据区域保存,git文件名,即git的元数据保存的是这个文件的hash值,由此,只要文件的内容发生变化,文件的hash值就会发生变化,继而git保存的文件名发生变化。文件名发生变化,保存的就是单独的另外一个对象文件。

git有自己的压缩算法,假如一个单独的文件有1GB大小,增加一行保存为一个版本,则10个版本后就有10个G,但是增加的内容其实不多,git可以将其压缩打包,极大减少空间使用,将相似的文件公共部分共用存储,最后只有一个多GB大小

68747470733a2f2f7777772e73696c766572706561732e6f72672f696d616765732f6769745f657665727468696e675f69735f6c6f63616c2e706e67.png

git基本设置

git官网:https://git-scm.com

centos安装git:yum install git  

centos源码安装:从 https://github.com/git/git/releases 下载最新版的 zip 包或者 tar.gz 并解压

git的配置有三个等级

/etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 --system 选项的 git config 时,它会从此文件读写配置变量。

~/.gitconfig 或 ~/.config/git/config 文件:只针对当前用户。 可以传递 --global 选项让 Git 读写此文件。

当前使用仓库的 Git 目录中的 config 文件(就是 .git/config):针对该仓库

每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量	

设置默认文本编辑器

$ git config --global core.editor vim

设置提交的时候所用的用户名和邮箱

$ git config --global user.name 'Administrator'
$ git config --global user.email 'contact@andblog.cn'

linux和window下换行符同一位lf

git config --global core.autocrlf false
设置core.autocrlf=false,windows也用LF换行
除了记事本,其他编辑器都可以正常编辑

查看单个属性设置

$ git config user.email
contact@andblog.cn

查看刚才设置的属性

$ git config --list  #或者git config -l
user.name=Administrator
user.email=contact@andblog.cn
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.editor=vim

查看帮助文档,这里所有的子命令中间都要有-,才可以查看帮助文档

$ git help <verb> 
$ git <verb> --help 
$ man git-<verb>
#例如
$ man git-add
$ man git-commit

git基本操作

git中文件分类:

已追踪的(tracked):已经在版本库中,已经使用git add命令添加到索引中的文件
已忽略的(ignored):在版本库中通过“忽略文件列表”明确忽略的文件
未追踪的(untracked):没添加的其他文件

git add/rm/mv命令:

add:暂存一个文件;将文件复制到对象库中,在索引中添加文件映射路径,
    可以用#git ls-files显示索引中文件原始名,
        -s:显示文件信息:权限,对象名,暂存号和原始文件名
    git ls-files -o 显示没有被追踪的文件
    在目录下创建:.gitignore,里面列出的文件会被忽略,不被记录到版本库
rm:
    git rm:删除工作目录中的文件,及索引中的映射
    当工作目录中删除一个文件(/bin/rm),索引目录中还会存在这个文件
    git rm --cached:只删除索引中的映射
mv:
    git mv:改变工作目录中的文件名,及索引中的映射
    当在工作目录中直接mv文件为另外的文件,git add的时候会报错

初始化一个空仓库

[root@master ~]#mkdir git_test
[root@master ~]#cd git_test
[root@master ~/git_test]#git init
[root@master ~/git_test]#ls -a
.  ..  .git

下面的方法更简单,自动创建foo目录
$ git init foo

将文件由未被追踪变为追踪状态:git add *或者git add .  都表示将所有文件添加

[root@master ~/git_test]#echo "first line" > file1
[root@master ~/git_test]#ll
total 4
-rw-r--r-- 1 root root 11 Sep 18 11:51 file1
[root@master ~/git_test]#git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	file1
nothing added to commit but untracked files present (use "git add" to track)

[root@master ~/git_test]#git add *

[root@master ~/git_test]#git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#	new file:   file1
#

[root@master ~/git_test]#git ls-files -s
100644 08fe2720d8e3fe3a5f81fbb289bc4c7a522f13da 0	file1

image.png


查看当前状态:git status,可以查看哪些文件没有被追踪,或者哪些文件没有被提交。或者被追踪了,但是又修改了,git status 命令的输出十分详细,但其用语有些繁琐。 如果你使用 git status -s 命令或 git status –short 命令,你将得到一种更为紧凑的格式输出。 运行 git status -s ,状态报告输出如下:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。 你可能注意到了 M 有两个可以出现的位置,出现在右边的 M 表示该文件被修改了但是还没放入暂存区,出现在靠左边的 M 表示该文件被修改了并放入了暂存区。 例如,上面的状态报告显示: README 文件在工作区被修改了但是还没有将修改后的文件放入暂存区,lib/simplegit.rb 文件被修改了并将修改后的文件放入了暂存区。 而 Rakefile 在工作区被修改并提交到暂存区后又在工作区中被修改了,所以在暂存区和工作区都有该文件被修改了的记录。


忽略文件,一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。 来看一个实际的例子:

$ cat .gitignore
*.[oa]
*~

第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。

文件 .gitignore 的格式规范如下:

所有空行或者以 # 开头的行都会被 Git 忽略。
可以使用标准的 glob 模式匹配。
匹配模式可以以(/)开头防止递归。
匹配模式可以以(/)结尾指定目录。
要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;\
[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个\
 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字\
 符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(*) 表示匹配任\
 意中间目录,比如`a/**/z` 可以匹配 a/z, a/b/z 或 `a/b/c/z`等。

我们再看一个 .gitignore 文件的例子:

# no .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO  子目录不忽略
/TODO

# ignore all files in the build/ directory
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory
doc/**/*.pdf

提交

#将当前所有文件暂存,为什么要暂存?今天更改了一个文件,添加了好多行代码,但是还没有到重新创建一个版本的时候,下一次来可以接着工作,为此,使用暂存。当多天修改后想重新命名为一个版本文件,可以使用#git commit命令,暂存可以理解为是购物车,等添加的物品比较多的时候,统一再结算。

在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行

$ git commit -m "Story 182: Fix benchmarks for speed"

尽管使用暂存区域的方式可以精心准备要提交的细节,但有时候这么做略显繁琐。 Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交


移除文件

要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目的,使用 –cached 选项:

$ git rm --cached README

移动文件

Git 并不显式跟踪文件移动操作。 如果在 Git 中重命名了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作

$ git mv README.md README

其实,运行 git mv 就相当于运行了下面三条命令:

$ mv README.md README
$ git rm README.md
$ git add README

查看提交历史

git log 会按提交时间列出所有的更新,最近的更新排在最上面。 正如你所看到的,这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

git log 附带一系列的总结性选项。 你可以使用 –stat 选项,看到每次提交的简略的统计信息

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 Rakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

 lib/simplegit.rb | 5 -----
 1 file changed, 5 deletions(-)

另外一个常用的选项是 –pretty

$ git log –pretty=oneline  将每个提交放在一行显示,查看的提交数很大时非常有用

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

format,可以定制要显示的记录格式

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

还有按照时间作限制的选项,比如 –since 和 –until 也很有用。 例如,下面的命令列出所有最近两周内的提交:

$ git log --since=2.weeks

撤销操作

将暂存区文件覆盖到工作区,如果指定单个文件,则只有这个单个文件从暂存区恢复覆盖到工作区,其他文件不变。此为工作区修改了以后,不想要了,想把暂存区的文件还原到工作区,从暂存区的文件重新工作

$ git checkout -- file

撤销提交

有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 –amend 选项的提交命令尝试重新提交:

$ git commit --amend

这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令),那么快照会保持不变,而你所修改的只是提交信息。

文本编辑器启动后,可以看到之前的提交信息。 编辑后保存会覆盖原来的提交信息。

例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

最终你只会有一个提交 – 第二次提交将代替第一次提交的结果。


打标签

Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等)

列出标签

在 Git 中列出已有的标签是非常简单直观的。 只需要输入 git tag:

$ git tag
v0.1
v1.3

支持通配符

$ git tag -l 'v1.8.5*'

附注标签

在 Git 中创建一个附注标签是很简单的。 最简单的方式是当你在运行 tag 命令时指定 -a 选项,-m 选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会运行编辑器要求你输入信息。

$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4

通过使用 git show 命令可以看到标签信息与对应的提交信息

后期打标签,你也可以对过去的提交打标签,要在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和):

$ git tag -a v1.2 9fceb02

默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样 – 你可以运行 git push origin [tagname]

如果想要一次性推送很多标签,也可以使用带有 –tags 选项的 git push 命令。 这将会把所有不在远程仓库服务器上的标签全部传送到那里。

git标签打错了,可以删除

 $ git tag -d v0.1

================================================================

下面是补充

提交标示:

引用:ID:reference,SHA1,绝对提交名

符号引用:symbolic reference,=> symref

    本地特性分支名称,远程跟踪分支名称,标签名

        名称:refs/heads/REF:本地特性分支

              refs/remotes/REF:远程跟踪分支名称

              refs/tags/REF:标签名

git自动维护几个特定目的的特殊符号引用

    HEAD:始终指向当前分支的最近提交,或检出到其他分支时,目标分支的最近的提交,

        如图git_9:

        最近提交v0.5,则当前head指向v0.5,如果切换到v0.2则head指向v0.2

        [root@localhost ~/test_git/.git]#cat HEAD 

        ref: refs/heads/master

    ORIG_HEAD:指向先前版本的head,合并操作时,新生成的提交之前的提交保存在此引用中

    如图:

相对提交名:没有分支的情况下,只有一个branch

    ^:同一代父提交中的不同的父提交:v0.5^1(1可以省略)指的是v0.4,v0.5^2指的是版本y,两个都是父提交,

        如图git_10:

    ~:返回父提交之前的多个父提交, v0.5~1指的是v0.4,v0.5~2指的是v0.3, v0.5^2~1指的是版本x

image.png

git-reset – Reset current HEAD to the specified state,如果当前head在v0.4

git reset –soft:如图红线,将HEAD引用指向给定的提交v0.3,v0.4就被废掉了,但不影响索引和工作目录

git reset –mixed:如图蓝线,将HEAD引用指向给定的提交v0.3,并将索引内容改变为指定提交的快照,但不改变工作目录,v0.4被废掉

git reset –hard:如图绿线,将HEAD引用指向给定的提交v0.3,并将索引内容改变为指定提交的快照,并改变工作目录中的内容反映指定提交的内容,v0.4被废掉

将被追踪的文件撤回:git reset HEAD first.txt

git ls-files -s 查看索引中的文件    

image.png

从历史版本中检出某个版本

创建新的分支

git checkout -b name-of-new-branch current-branch

从历史版本中某个版本创建新分支,即将历史中的某个版本内容恢复到工作区目录中

Git 的活动分支会切换到 name-of-new-branch 这个分支上,而它的内容与 169d2dc 这个分支一致

git checkout -b name-of-new-branch 169d2dc

下面是隐藏文件.git的结构

.git
├── branches #分支文件
├── config  #配置文件
├── description  #描述文件
├── HEAD    #头,指向哪个版本
├── hooks
│   └── update.sample
├── index
├── info
│   └── exclude
├── objects #对象库
│   ├── fe
│   │   └── 8b80b89922b3afebce3c4ee64252893e600890
│   ├── info
│   └── pack
└── refs    #引用
    ├── heads
    └── tags

git diff命令

image.png

参考文档:

http://marklodato.github.io/visual-git-guide/index-en.html#commit

https://git-scm.com/book/zh/v2

文件

git.zip

未经允许不得转载:江哥架构师笔记 » git学习:基础原理和配置

分享到:更多 ()

评论 抢沙发

评论前必须登录!