每个项目都有一个 Git 目录(译注:如果 git clone 出来的话,就是其中 .git 的目录;如果 git clone --bare 的话,新建的目录本身就是 Git 目录。),它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。
1、基本的 Git 工作流程如下:
在工作目录中修改某些文件。
对修改后的文件进行快照,然后保存到暂存区域。
提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。
2、 Git 配置
在使用 Git 前需要配置一些信息,方便之后变更提交的管理。
配置 user 信息:
git config --global user.name 'name'
git config --global user.email 'emailname@domain.com'
git config --local ##只对某个仓库有效,切换到另外一个仓库失效
git config --global ##当前用户的所有仓库有效,工作当中最常用
git config --system ##系统的所有用户,几乎不用
查看配置:
git config --list --local ##只能在仓库里面起作用, 普通路径git不管理
git config --list --global
git config --list --system
local的在.git/config里面;global的在个人home目录下的.gitconfig里面;system 在git安装目录的下;
3、 建 Git 仓库
A、把已有的项目代码加入 Git 管理
$ cd path
$ git init
git init 初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。不过目前,仅仅是按照既有的结构框架初始化好了里边所有的文件和目录,但我们还没有开始跟踪管理项目中的任何一个文件。
B、新建的项目直接使用 Git 管理
$ cd path
$ git init project_name #会在当前路径下创建和项目同名的文件夹
C、 从现有仓库克隆
git clone 会在当前目录下创建目录,其中包含一个 .git 的目录,用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝。希望在克隆的时候,自己定义要新建的项目目录名称,可以在命令末尾指定新的名字:git clone [url] name .
4、 .git 目录
创建完 Git 仓库后,文件夹中包含一个 .git 的目录,其中包含了以下文件:
HEAD: 指向当前的工作的分支 refs/heads/master
config: 存放本地仓库(local)相关的配置信息。
refs: heads 存放分支 tags:存放tag,又叫里程牌 (当这次commit是具有里程碑意义的 比如项目1.0的时候 就可以打tag)
objects: 存放对象 .git/objects/ 文件夹中的子文件夹都是以哈希值的前两位字符命名 每个object由40位字符组成,前两位字符用来当文件夹,后38位做文件。
cat 命令主要用来查看文件内容,创建文件,文件合并,追加文件内容等功能。
cat HEAD 查看HEAD文件的内容
git cat-file 命令 显示版本库对象的内容、类型及大小信息。
git cat-file -t 4aXX 显示 git 文件对象的类型
git cat-file -s 显示大小
git cat-file -p 显示内容
git 核心的几个对象,commit tree blob
当你向仓库中添加了一个新文件后 add 添加到暂存区后,git 会根据文件内容创建对应的 blob,然后你在执行 commit 命令后,git 再根据文件所在的文件夹创建对应的 tree,然后把对应的 blob 添加到 tree,然后再封装到一个 commit 对象中完成本次提交。
如果你只是在仓库中新建了文件夹,新建的文件夹下没有文件的话,是不会被 git 管理的,没有文件就没有,对应的 tree 也不会生成对应的 commit。
5、 Git 命令
git help xxx 可查看命令的文档
A、 检查当前文件状态
git status 命令:哪些文件当前处于什么状
B、 跟踪文件
未跟踪的文件意味着Git在之前的快照(提交)中没有这些文件;Git 不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”,因而不用担心把临时文件什么的也归入版本管理。
使用命令 git add 开始跟踪一个新文件,运行:git add filename
git add 这是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。
git add -u:将文件的修改、删除,添加到暂存区。不会添加新增的文件。
git add .:将文件的修改、新建、删除,添加到暂存区。对当前路径及其子路径下的变更有效。
git add -A:将文件的修改、新建、删除,添加到暂存区。对整个仓库仓库的变更有效。等同于git add -all。
工作中一般是用到 git add . 或者 git add -A
git add -A相对于git add -u命令的优点 : 可以提交所有被删除、被替换、被修改和新增的文件到数据暂存区。
git add -u 只能操作跟踪过的文件,避免把工作区没准备好的新文件直接加到暂存区了
git commit --amend 修改未 push 的最近一次 commit 的内容。如果已经 push 到远端的话,得用 push -f
git rebase -i 父节点 可用来变更,未push的某一个xxx commit的子commit的message。
也可用来合并多个 commit
rebase会基于新base的commit来变更部分commits,
分离头指针,生成新的commit,rebase创建完最后一个commit后,
结束分离头状态。
C、 变更文件
git mv a.txt b.c 变更文件
git rm test/a.txt 删除文件
git log -n2 --oneline 查看日志,最近的两次,简洁的信息显示一行
--all 所有分支的日志。--graph 图像化的显示
git checkout -b temp 新建分支并切换到新建的分支上
git diff HEAD HEAD~1 查看当前节点指向,和它上一个节点的区别 用 ~2 ^^ 表示上一个父节点
git diff --cached 修改了文件add之后,用这个命令来查看修改的内容,暂存区和HEAD的比较
git diff -- 文件名 工作区和缓存区的比较
git diff HEAD -- 文件名 工作区和HEAD的比较
git diff temp master -- 文件名 比较在不同的分支上文件的差别。
也可以比较commit_id1 commit_id2上的不同
git checkout -- 文件名 工作区恢复为暂存区。文件修改后没有进行add操作,这个命令会恢复文件
git reset --hard 清除暂存。add后未commit,这个命令会撤销add操作。
git reset HEAD -- 文件名 暂存区恢复为HEAD。就是撤销add的操作
git reset --hard xxx commit之后未push。这个命令会撤销commit回退到xxx节点。
git stash 在工作区修改了文件,还没add,然后有其他紧急的事要处理,用这个命令可保存修改
git stash list 显示保存的列表
git stash apply 把保存的恢复到工作区,而且这条保存的信息会保留
git stash pop 把保存的恢复到工作区,这条保存的信息会删除
D、 分支
git branch -av 查看分支
git checkout xxx 切换分支到xxx
git checkout -b xxx 新建分支 xxx 并切换到分支上去
git checkout -b 本地分支名 origin/远程分支名 (从远程仓库里拉取一条本地不存在的分支,会自动创建一个新的本地分支,并与指定的远程分支关联起来。)
git branch -d xxx 删除分支,如果分支没有 merge 会有提示
git merge,rebase 的区别
它们都被设计来将一个分支的更改并入另一个分支,只不过方式有些不同。
merge:不会改变两个分支已有的版本历史,只会把两个分支合并后创建出一个新的 commit 出来。
merge是一个安全的操作。现有的分支不会被更改
rebase:假设当前在 A 分支,要基于 B 分支做 rebase,那么会先找到A和B的最近的公共祖先C,
从C到A之间所有 commit,都基于 B 重新生成新的 commit。
rebase 通常会修改某个分支的历史。
rebase最大的好处是你的项目历史会非常整洁,项目历史是线性的。
不像 merge 那样引入不必要的合并提交。
这种简单的提交历史会带来两个后果:安全性和可跟踪性。
如果你违反了 rebase 黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。
此外,rebase 不会有合并提交中附带的信息——你看不到分支中并入了上游的哪些更改。
rebase 的黄金法则便是,绝不要在公共的分支上使用它。
E、pull push
git pull 命令等同于先做了git fetch ,再做 git merge。即:
git fetch origin 分支
git checkout 分支
git merge origin/分支
git pull origin <远程分支名>:<本地分支名> 将远程指定分支,拉取到本地指定分支上
git pull origin <远程分支名> 将远程指定分支,拉取到本地当前分支上
git pull origin 将本地当前分支同名的远程分支,拉取到本地当前分支上(需先关联远程分支)
git push origin <本地分支名>:<远程分支名> 将本地当前分支,推送到远程指定分支上(注意:pull是远程在前本地在后,push相反)
git push origin <本地分支名> 将本地当前分支,推送到与本地当前分支同名的远程分支上
git push origin 将本地当前分支,推送到与本地当前分支同名的远程分支上(需先关联远程分支)
git push --set-upstream origin <本地分支名> 将本地分支与远程同名分支相关联。如果远程仓库不存在该分支,推送到远程仓库。
6、忽略某些文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。
.gitignore 文件的例子:
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
如果提交commit后,想再忽略一些已经提交的文件:
把想忽略的文件添加到 .gitignore,然后通过 git rm --cached name_of_file 的方式删除掉git仓库里面无需跟踪的文件。
删除暂存区或分支上的文件, 但本地又需要使用, 只是不希望这个文件被版本控制, 可以使用 git rm --cached name_of_file 命令
Reference
https://git-scm.com/book/zh/v2
https://github.com/geeeeeeeeek/git-recipes/wiki