文章来源
Git入门
资料来源:https://www.runoob.com/git/git-tutorial.html、http://git-scm.com/docs
查看Git命令的帮助信息,git <command> --help
1.Git 工作区、暂存区和版本库(以本地举例)、远程仓库
- 工作区:就是你在电脑里能看到的目录。
- 暂存区:英文叫
stage
或index
。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。 - 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。
Git 工作区、暂存区和版本库
- 图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage/index),标记为 "master" 的是 master 分支所代表的目录树。
- 图中我们可以看出此时 "HEAD" 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
- 图中的 objects 标识的区域为 Git 的对象库,实际位于 ".git/objects" 目录下,里面包含了创建的各种对象及内容。
- 当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
- 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
- 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
- 当执行 git rm --cached 命令时,会直接从暂存区删除文件,工作区则不做出改变。
- 当执行 git checkout . 或者 git checkout -- 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。
- 当执行 git checkout HEAD . 或者 git checkout HEAD 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
2.Git文件状态
在Git中文件大概分为四种状态:已修改(modified)、已暂存(staged)、已提交(committed)、未追踪(Untrack)
- .gitignore内的文件,不会拥有任何一种状态,被git彻底无视。
- 处于ignore列表的文件,无法被add添加;但是可以强制添加
- 空目录、以及子目录全部是空目录的目录不会有Untrack状态,也无法通过add改变状态(无效)
- 工作目录新增文件时,只要不处于ignore目录,都会变成Untrack状态;
- 没有add过的文件或者被restore(不带--staged)的文件,处于Untrack状态;
- 初次add和被add后产生修改的文件,会处于modifed状态。
- 处于modified状态的文件,最开始可以进行add和restore两种操作,此时的add操作叫做
更新要提交的内容
,add后变为staged状态,restore(不加staged标记)后变为Untrack; - add后变为staged状态的文件,可用restore --staged 变回modified状态;这个staged状态的内容可以用来恢复内容。没有被add的modified状态文件内容没有被记录(虽然有撤回,但是本质不一样);
- 处于staged状态的文件,在没有commit之前再次产生修改时,会同时具有staged和modified两个状态(可以把statged状态的内容拉回来,覆盖。);但是commit时会使用内容最新的那个状态;
- commit会提交所有staged状态的文件,所以commit可以理解有一个modified到staged状态的过程(实际可能不存在,因为暂存区本来就有变动的记录);所以暂存状态不能理解为处于暂存区,应当指的是被纳入下一次提交的文件;任何被追踪的产生修改的文件都会在暂存区被记录;成为下一次提交的一部分;
- 未被追踪的文件被删除时,不会产生git状态。处于modofy未add时,会变成deleted状态;处于staged状态会保持暂存状态;
- 已经被删除的(deleted状态)被追踪的文件,恢复后会变成modified状态;
提示:add的作用是将文件添加到暂存区,只有被add的文件才会被追踪
- (1)所谓的暂存区只是一个简单的索引文件而已。
- (2)暂存区这个索引文件里面包含的是文件的目录树,像一个虚拟的工作区,在这个虚拟工作区的目录树中,记录了文件名、文件的时间戳、文件长度、文件类型以及最重要的SHA-1值,文件的内容并没有存储在其中,所以说 它像一个虚拟的工作区。
- (3)索引指向的是.Git/objects下的文件。
- (4)暂存区的作用:除非是绕过暂存区直接提交,否则Git想把修改提交上去,就必须将修改存入暂存区最后才能commit。每次提交的是暂存区所对应的文件快照。
拓展:status提示信息
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
- 既然是Changes not staged for commit,就说明出现这个提示下的所有文件改动,都是存在于工作区的。stage是暂存区的意思,not stage说明都不在暂存区,那么说明在工作区。
- (use “git add …” to update what will be committed)。执行这条命令就可以工作区里面的改变加入到暂存区。可以执行git add .把当前目录下所有改动加入暂存区。
- (use “git checkout – …” to discard changes in working directory)。执行这条命令将丢弃在工作区的改动。可以执行git checkout *把当前目录下所有工作区的改动丢弃掉
Untracked files:
(use "git add <file>..." to include in what will be committed)
- Untracked files,就说明出现这个提示下的所有文件都是当前HEAD没有被加入过的文件。这种改动也属于工作区。
- (use “git add …” to include in what will be committed)。把Untracked files加入暂存区。
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
- 当前分支比远程分支多了一次commit
Your branch and 'origin/master' have diverged, and have 1 and 1 different commits each, respectively
pull报错了,查看状态显示这个,先留着待解决吧
3.HEAD是什么
HEAD是Git中非常重要的一个概念,你可以称它为指针或者引用,它可以指向任意一个节点,并且指向的节点始终为当前工作目录,换句话说就是当前工作目录(也就是你所看到的代码)就是HEAD指向的节点。
4.git重命名检测
Git 采用了不同的方法:它没有选择去存储与文件移动操作相关的信息,而是采用了重命名检测算法。在该算法中,如果一个文件在某一次提交中消失了,它依然会存在于其前次提交,而如果某个拥有相同名字或相似内容的文件出现在了另一个位置,Git 就会自动检测到。如果是这种情况,Git 就会假定该文件被移动过了。
Git项目文件说明
Git init后主要有两个重要的文件和目录:.git目录和.gitignore
1. .gitignore
.gitignore文件存在于根目录(与.git同级的目录)用于在将文件提交到git暂存区时,指定将哪些文件排除;
有时候你想添加(git add)一个文件到Git,但发现添加不了,多半原因是这个文件被.gitignore
忽略了
git add .不会添加被.gitignore忽视的文件,而git add -f . 强制添加所有文件,即使是.gitignore忽视的文件也添加。
当.gitignore文件不是你编写的,但是它编写的不符合实际需求,你可以使用git check-ignore命令进行检查,看是哪一个规则有问题了
git check-ignore -v App.class
.gitignore:3:*.class App.class
.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。
git rm -r --cached .
git add .
git commit -m ‘update .gitignore’
也可以手动指定一个文件作为git忽略文件
git config core.excludesfile ***
对于全局Git配置,可以使用如下命令对全部仓库进行配置。
git config --global core.excludesfile **/.gitignore(文件相对或绝对位置)
忽略规则如下:
- 空格不匹配任意文件,可作为分隔符,可用反斜杠转义
- #开头的文件标识注释,可以使用反斜杠进行转义
- ! 开头的模式标识否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用 ! 也不会再次被包含。可以使用反斜杠进行转义
- / 结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件
- / 开始的模式匹配项目跟目录
- 如果一个模式不包含斜杠,则它匹配相对于当前 .gitignore 文件路径的内容,如果该模式不在 .gitignore 文件中,则相对于项目根目录
- ** 匹配多级目录,可在开始,中间,结束
- ? 通用匹配单个字符
- [] 通用匹配单个字符列表
各种项目的gitignore, 参考地址:https://github.com/github/gitignore
2. .git目录
任意文件夹中,用 git init 命令初始化仓库,即可在此文件夹下创建 .git 文件夹(.打头为隐藏文件夹,所以平时可能看不到)。这个文件夹之外的部分叫做工作区(Working Directory),.git 文件夹我们称做 Git仓库 (Git Repository)。 通常会有7个文件5个目录,常见目录如下:
COMMIT_EDITMSG
HEAD
ORIG_HEAD
FETCH_HEAD
config
description
index
hooks/
info/
logs/
objects/
refs/
1. 文件 COMMIT_EDITMSG
此文件是一个临时文件,存储最后一次提交的信息内容,git commit 命令之后打开的编辑器就是在编辑此文件,而你退出编辑器后,git 会把此文件内容写入 commit 记录。
实际应用: git pull 远程仓库后,新增了很多提交,淹没了本地提交记录,直接 cat .git/COMMIT_EDITMSG 就可以弄清楚最后工作的位置了。
2. HEAD
此文件永远存储当前位置指针,就像 linux 中的 $PWD 变量和命令提示符的箭头一样,永远指向当前位置,表明当前的工作位置。在 git 中 HEAD 永远指向当前正在工作的那个 commit。(孤立HEAD?????)
HEAD 存储一个分支的 ref,Linux中运行:cat .git/HEAD 通常会显示:
这说明你目前正在 master 分支工作。此时你的任何 commit,默认自动附加到 master 分支之上
git cat-file -p HEAD
, 显示详细的提交信息:
tree