在windows7上安装GIT(msysgit)的过程
-在Select Components选项中将“Git Bash here”和“Git GUI here”打对勾。
-在“Adjusting your PATH environment”选项中,选中"Use Git Bash only"。
-在“Configuring the line ending conversions”选项中,
第一个选项:如果是跨平台项目,在windows系统安装,选择;
第二个选项:如果是跨平台项目,在Unix系统安装,选择;
第三个选项:非跨平台项目,选择。
选中第三个
-在Configuring the terminal emulator to use with Git Bash选项中选择"Use MinTTY"
-在Configuring extra options选项中选择"Enable file system caching"
-安装完成后,在目录下的鼠标右键菜单选择"Git Bash here"
在linux上安装GIT
yum -y install git
配置GIT
命令方式:
全局配置:
git config --global core.editer vim
#设置提交时注释所需编辑注释的文本编辑器
git config --global user.name author #将用户名设为author
git config --global user.email author@corpmail.com #将用户邮箱设为author@corpmail.com
项目级配置:
git config user.name tangshiwei#将用户名设为nickname
git config user.email tangshiwei@qq.com #将用户邮箱设为nickname@gmail.com
配置文件方式:
全局配置文件:"~/.gitconfig"(用户目录下的.gitconfig)文件
项目级配置文件:Git项目所在目录的".git/config"文件
文件内容:
[user]
name = nickname
email = nickname@gmail.com
Git使用举例
创建一个testGit仓库
mkdir testGit #建立仓库目录
cd testGit #进入仓库目录
git init #这会在当前的目录下建一个仓库
配置GIT用户名和邮箱,见前面介绍
介绍几个查看命令
git status #查看当前仓库的状态
git log #查看当前仓库的历史日志
git diff #查看仓库里未暂存内容和仓库已提交内容的差异
提交文件
echo “hello Git” > readme.txt #建立一个含有 hello Git 的文本文件
git add readme.txt #将readme.txt添加到暂存区中。如果git add后不加参数表示将当前目录下所有文件添加到暂存区
git commit -m "project init" #将刚才的修改提交到本地仓库中
重命名文件、删除文件
git mv oldfile newfile
git rm -f file/dir #删除文件或目录
git commit -m "rename file1,del file2"
修改提交后的文件,或解决冲突文件
echo "Git is Cool" >> readme.txt
git diff #查看仓库里未暂存内容和仓库已提交内容的差异
git add readme.txt
git commit -m "Git is Cool"
远程库操作
git clone git_repository [directory] #克隆一个库,directory表示要克隆库的某个目录
git push remote_repository #向远程库提交修改
git format-patch remote_repository #生成基于仓库的版本补丁
git fetch remote_repository
git merge remote_repository 合并前,先fetch一下来获取远程的最新版本
Git的目录结构
git init命令在项目的顶层目录中建了一个名为:“.git”的目录;一个Git项目一般只在项目的根目录下建一个“.git”目录,不像SVN在每级目录下皆有”.svn”目录。
git项目的历史提交信息会存放在.git目录中,修改后提交的文件也会临时存放在此目录,然后再提交到远程服务器。把git项目和对应.git目录一起拷贝到其他主机能马上使用。
Git为了 调试的方便,它可以指定项目的Git目录的位置。有两种办法:一是设置“GIT_DIR”环境变量,二是在命令行里设定“--git-dir--git-dir”参数指定它的位置
.
git目录结构
COMMIT_EDITMSG # 保存着上一次提交时的注释信息
config # 项目的配置信息
description # 项目的描述信息
HEAD # 项目当前在哪个分支的信息
hooks/ # 默认的“hooks” 脚本文件
index # 索引文件,git add 后把要添加的项暂存到这里
info/ # 里面有一个exclude文件,指定本项目要忽略的文件 #,看一下这里
logs/ # 各个refs的历史信息
objects/ # 这个目录非常重要,里面存储都是Git的数据对象
# 包括:提交(commits), 树对象(trees),二进制对象 #(blobs),标签对象(tags)。
#不明白没有关系,后面会讲的。
refs/ # 标识着你的每个分支指向哪个提交(commit)。
查看文件版本和对应文件内容
git log #查看SHA签名前5个字符
git cat-file -p xxxxx #SHA签名前5个字符,执行三次分别查看commit、tree、blob等对象内容
find .git/objects #查看commit、tree、blob等对象文件的位置
clone一个远程项目
git clone https://github.com/netkiller/netkiller.github.io.git #Git仓库除了可以通过git、http、https协议传输外还可以通过ssh、ftp(s)、rsync等协议来传输。git clone的本质就是把“Git目录”里面的内容拷贝过来,一般的“Git目录”里有成千上万的各种对象(提交对象,树对象,二进制对象......),如果逐一复制的话,其效率就可想而知。如果通过git、ssh协议传输,服务器端会在传输前把需要传输的各种对象先打好包再进行传输;而http(s)协议则会反复请求要传输的不同对象。
索引与提交的原理
git add,git commit它们一个是把文件暂存到索引中为下一次提交做准备,一个创建新的提交(commit)。
Git 索引是一个在你的工作目录(working tree)和项目仓库间的暂存区域(staging area)。如果你创建了一个提交(commit),那么提交的一般是暂存区里的内容, 而不是工作目录中的内容。
一个Git项目中文件的状态大概分成下面的两大类,而第二大类又分为三小类:
未被跟踪的文件(untracked file)
已被跟踪的文件(tracked file)
被修改但未被暂存的文件(changed but not updated或modified)
已暂存可以被提交的文件(changes to be committed 或staged)
自上次提交以来,未修改的文件(clean 或 unmodified)
过程讲解
mkdir stage_proj
cd stage_proj
git init
echo "hello,world" > readme.txt #创建一个文件
git status
git add readme.txt #把“readme.txt"加到暂存区
//暂存区(staging area)一般存放在“git目录“下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。索引是一个二进制格式的文件,里面存放了与当前暂存内容相关的信息,包括暂存的文件名、文件内容的SHA1哈希串值和文件访问权限,整个索引文件的内容以暂存的文件名进行排 序保存的。
git status
git ls-files --stage #看一下暂存区(staging area)里的内容
git cat-file -p 2d832d #查看此文件的内容
//Git在把一个文件添加暂存区时,不但把它在索引文件(.git/index)里挂了号,而且把它的内容先保存到了“.git/objects“(git目录)里面去了。
//git rm --cached filename 把误添加的文件从暂存区中移除
echo "hello,world2" >> readme.txt #再次修改文件
git status
//每次执行“git add”添加文件到暂存区时,它都会把文件内容进行SHA1哈希运算,在索引文件中新加一项,再把文件内容存放到本地的“git目录“里。如果在上次执行 “git add”之后再对文件的内容进行了修改,那么在执行“git status”命令时,Git会对文件内容进行SHA1哈希运算就会发现文件又被修改了,这时“readme.txt“就同时呈现了两个状态:被修改但未被暂存的文件(changed but not updated),已暂存可以被提交的文件(changes to be committed)。如果我们这时提交的话,就是只会提交第一次“git add"所以暂存的文件内容。
git checkout -- readme.txt #对于“hello,world2"的这个修改不是很满意,想要撤消这个修改
git status
git commit -m "project init"
//可以看到“nothing to commit (working directory clean)”;如果一个工作树(working tree)中所有的修改都已提交到了当前分支里(current head),那么就说它是干净的(clean),反之它就是脏的(dirty)。
SHA1值内容寻址
Git是一种全新的使用数据的方式(Git is a totally new way to operate on data)。Git把它所管理的所有对象(blob,tree,commit,tag……),全部根据它们的内容生成SHA1哈希串值作为对象名;根据目前的数学知识,如果两块数据的SHA1哈希串值相等,那么我们就可以认为这两块数据是相同 的。
实验步骤:
echo "hello,world" > readme2.txt #创建一个和“readme.txt“内容完全相同的文件”readme2.txt“
git add readme2.txt
git commit -m "add new file: readme2.txt"
git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p #查看当前的提交(HEAD)所包含的blob对象
//100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt
//100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt
git cat-file -p HEAD^ | head -n 1 | cut -b6-15 | xargs git cat-file -p #查看上一次提交(HEAD^)所包含的blob对象
//100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt
//尽管当前的提交比前一次多了一个文件,但是它们之间却是在共用同一个blob对象:“2d832d9”
快照存储(snapshot)
GIT在提交前根据要提交 的内容求SHA1哈希串值作为对象名,看仓库内是否有相同的对象,如果没有就将在“.git/objects"目录创建对应的对象,如果有就会重用已有的 对象,以节约空间。
实验步骤:
echo "hello,world2" >> readme.txt
git add readme.txt
git commit -m "add new content for readme.txt"
git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
//100644 blob 2e4e85a61968db0c9ac294f76de70575a62822e1 readme.txt
//100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt
//可以看到"readme.txt"已经对应了一个新的blob对象:“2e4e85a”,而之前版本的"readme.txt“对应的blob对象是:“2d832d9”。
git cat-file -p 2e4e8
//hello,world
//hello,world2
git cat-file -p 2d832
//hello,world
总结:“git add“不但能把未跟踪的文件(untracked file)添加到版本控制之下,也可以把修改了的文章暂存到索引中。同时,由于采用“SHA1哈希串值内容寻值“和”快照存储(snapshot)“,让Git成为一个速度非常非常快的版本控制系统(VCS)。
合并分支
新建仓库并添加一个文件到主干上
mkdir test_branch_proj
cd test_branch_proj/
git init
echo "hello,world" > readme.txt
git add readme.txt
git commit -m "project init"
git status
//On branch master
//nothing to commit, working tree clean
cd .git
cat HEAD #HEAD文件告诉我们在哪个分支上工作
//ref: refs/heads/master
cat refs/heads/master #这是一个“SHA1哈希串值”的对象名
//b4d0629bd5d62998dde197d2a47808a019efc3cd
cat refs/heads/master | xargs git cat-file -t #这个对象是提交(commit)对象
//commit
cat refs/heads/master | xargs git cat-file -p
//tree 2bb9f0c9dc5caa1fb10f9e0ccbb3a7003c8a0e13
//author tangshiwei <tangshiwei@qq.com> 1476437628 +0800
//committer tangshiwei <tangshiwei@qq.com> 1476437628 +0800
//project init
//这是一个提交(commit),“master”文件里面存有主分支(master)最新提交的“对象名”;我们根据这个“对象名”就可以可找到对应的树对象(tree)和二进制对象(blob),简而言之就是我能够按“名”索引找到这个分支里所有的对象。
//Git根据内容来生成名字的,而且同名(SHA1哈希串值)肯定会有 相同内容,但是提交对象(commit)和其它对象有点不一样,它里面会多一个时间戳(timestamp),这里是1476437628 +0800,所以在不同的时间生成的提交对象,即使内容 完全一样其名字也不会相同。
cat refs/heads/master | xargs git cat-file -p | head -n 1 | cut -b6-15 | xargs git cat-file -p
//100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt
git cat-file -p 2d832
//hello,world
新建test分支,提交修改的文件并验证
cd ..
git branch test #创建一个叫“test”的分支
git checkout test #签出“test”分支到工作目录里
git branch
// master
//* test
echo "In test branch" >> readme.txt
git add readme.txt
git commit -m "test branch modified"
git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
//100644 blob 77d8b9830d90e9bdbf9077c4ed594a7ddc1c6046 readme.txt
cd .git
cat HEAD
//ref: refs/heads/test
cat refs/heads/test | xargs git cat-file -p | head -n 1 | cut -b6-15 | xargs git cat-file -p
//100644 blob 77d8b9830d90e9bdbf9077c4ed594a7ddc1c6046 readme.txt
git cat-file -p 77d8b9
//hello,world
//In test branch
合并分支后删除分支
cd ..
git checkout master
//Switched to branch 'master'
git checkout master
//Already on 'master'
cat readme.txt
//hello,world
git diff test #查看此文件在主干和分支它们之间的不同
//diff --git a/readme.txt b/readme.txt
//index 77d8b98..2d832d9 100644
//--- a/readme.txt
//+++ b/readme.txt
//@@ -1,2 +1 @@
// hello,world
//-In test branch #相比test分支,主干少了一行
git merge test #合并分支,用分支的覆盖主干
Updating b4d0629..67f3895
//Fast-forward 在这里可以理解为顺利合并,没有冲突。
cat readme.txt
//hello,world
//In test branch
git status
//On branch master
//nothing to commit, working tree clean
git branch -d test #删除合并后的分支,如果分支没有合并,需要改用“git branch -D”来强制删除
解决合并分支冲突
创建仓库并在主分支上提交文件
mkdir test_merge_proj
cd test_merge_proj/
git init
echo "hello,world" > readme.txt
git add readme.txt
git commit -m "master commit 1"
创建从分支并提交修改后的文件
git branch test
git checkout test
cho "hello, the world" > readme.txt
git add readme.txt
git commit -m "slave commit 1"
在主分支上提交修改后的文件,并合并从分支
git checkout master
echo "hello,tangshiwei" > readme.txt
git add readme.txt
git commit -m "master commit 2"
git merge test
//Automatic merge failed; fix conflicts and then commit the result.
//合并出现冲突,需要手动解决,让后提交到主分支上
git add readme.txt
git commit -m "master commit 3"
如果合并冲突后想回退,请使用下面的命令
git reset --hard HEAD^
HEAD is now at 51ba09c master commit 2
参考资料:
书:
Git Community Book 中文版:http://gitbook.liuhui998.com/book.pdf
安装包:
mSysGit:https://git-for-windows.github.io/