Git简介 --- 版本控制工具(命令)

工具介绍官方网站:http://git-scm.com
工具下载地址:http://git-scm.com/download/

git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。
git是个工具,在linux里面也就类似gcc这样的工具一样,是一个shell命令。

git的每一个节点(第一次从远程git仓库取得代码后,该git节点就是一个完整的代码仓库)相当于SVN的中心服务器,都包含完整的代码仓库。

git的工作原理

架构图

clipboard.png

git中的一些概念和原理 (工作区、暂存区、主分支)
clipboard.png

clipboard.png

clipboard.png

git 的优势

直接记录快照,而非差异比较

Git 和其它版本控制系统(包括 Subversion 和近似工具)的主要差别在于 Git 对待数据的方法

概念上来区分,其它大部分系统以文件变更列表的方式存储信息。这类系统(CVS、Subversion、Perforce、Bazaar 等等)将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。存储每个文件与初始版本的差异,如下图所示 -

clipboard.png

Git 不按照以上方式对待或保存数据。 反之,Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。如下图所示 -

clipboard.png

这是 Git 与几乎所有其它版本控制系统的重要区别。 因此 Git 重新考虑了以前每一代版本控制系统延续下来的诸多方面。 Git 更像是一个小型的文件系统,提供了许多以此为基础构建的超强工具,而不只是一个简单的 VCS。 稍后我们在 Git 分支讨论 Git 分支管理时,将探究这种方式对待数据所能获得的益处。

近乎所有操作都是本地执行

在 Git 中的绝大多数操作都只需要访问本地文件和资源,一般不需要来自网络上其它计算机的信息。 如果你习惯于所有操作都有网络延时开销的集中式版本控制系统,Git 在这方面会让你感到速度之神赐给了 Git 超凡的能量。 因为你在本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。

举个例子,要浏览项目的历史,Git 不需外连到服务器去获取历史,然后再显示出来——它只需直接从本地数据库中读取。 你能立即看到项目历史。 如果想查看当前版本与一个月前的版本之间引入的修改,Git 会查找到一个月前的文件做一次本地的差异计算,而不是由远程服务器处理或从远程服务器拉回旧版本文件再来本地处理。

这也意味着你离线或者没有 VPN 时,几乎可以进行任何操作。 如你在飞机或火车上想做些工作,你能愉快地提交,直到有网络连接时再上传。 如你回家后 VPN 客户端不正常,你仍能工作。 使用其它系统,做到如此是不可能或很费力的。 比如,用 Perforce,你没有连接服务器时几乎不能做什么事;用 Subversion 和 CVS,你能修改文件,但不能向数据库提交修改(因为你的本地数据库离线了)。 这看起来不是大问题,但是你可能会惊喜地发现它带来的巨大的不同。

Git 保证完整性

Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。

Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:

      24b9da6552252987aa493b52f8696cd6d3b0037
    

Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。

分支内部原理

1、如下图所示,版本的每一次提交(commit),git都将它们根据提交的时间点串联成一条线。刚开始是只有一条时间线,即master分支,HEAD指向的是当前分支的当前版本。

clipboard.png

2、当创建了新分支,比如dev分支(通过命令git branch dev完成),git新建一个指针dev,dev=master,dev指向master指向的版本,然后切换到dev分支(通过命令git checkout dev完成),把HEAD指针指向dev,如下图。

clipboard.png

3、在dev分支上编码开发时,都是在dev上进行指针移动,比如在dev分支上commit一次,dev指针往前移动一步,但是master指针没有变,如下:

clipboard.png

4、当我们完成了dev分支上的工作,要进行分支合并,把dev分支的内容合并到master分支上(通过首先切换到master分支,git branch master,然后合并git merge dev命令完成)。其内部的原理,其实就是先把HEAD指针指向master,再把master指针指向现在的dev指针指向的内容。如下图。

git co branchName

clipboard.png

例子:

clipboard.png

5、当合并分支的时候出现冲突(confict),比如在dev分支上commit了一个文件file1,同时在master分支上也提交了该文件file1,修改的地方不同(比如都修改了同一个语句),那么合并的时候就有可能出现冲突,如下图所示。

clipboard.png

这时候执行git merge dev命令,git会默认执行合并,但是要手动解决下冲突,然后在master上git add并且git commit,现在git分支的结构如下图。

clipboard.png

git log --graph --pretty=oneline --abbrev-commit

6、合并完成后,就可以删除掉dev分支(通过git branch -d dev命令完成)。

clipboard.png

部分命令

git status

git diff file :

git diff命令要在git add命令之前使用,否则一旦添加到commit缓存后,git diff命令就失效了。

git diff 版本1 版本2 [文件]  (HEAD)

查看commit历史

git log

查看命令历史

git reflog 

clipboard.png

版本回退
git reset --hard HEAD^  
git reset --hard HEAD@{4}// 恢复到某个提交点,不保留修改
git reset --soft HASH // 恢复到某特提交的,保留修改
git revert:还原一个版本的修改,必须提供一个具体的Git版本号,例如'git revert bbaf6fb5060b4875b18ff9ff637ce118256d6f20',Git的版本号都是生成的一个哈希值、

git是用HEAD来表示当前分支中的当前版本,HEAD^表示上一个版本,HEAD^^表示上上一个版本,以此类推,如果要回退很早的版本就用HEAD@{版本号},版本号用git reflog查看。

撤销修改

分3种情况:

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file 或者 手动修改。(该方法只能全部复原文件,因为git checkout -- file其实就是把版本库中的file替换现在工作区的file)

➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>git status
# 位于分支 Reg_20180628
# 尚未暂存以备提交的变更:
#   (使用 "git add <file>..." 更新要提交的内容)
#   (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
#    修改:      release/20180628.txt
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

场景2:当你不但改乱了工作区某个文件的内容,并且还添加到了暂存区(即已经git add了)时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。

➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>git add .
➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>git status
# 位于分支 Reg_20180628
# 要提交的变更:
#   (使用 "git reset HEAD <file>..." 撤出暂存区)
#
#    修改:      release/20180628.txt

➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗> git reset HEAD release/20180628.txt
重置后撤出暂存区的变更:
M    release/20180628.txt
➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>cat release/20180628.txt
[DEP]

[DB1]
   bettle=24974,25042
[DB2]
   bettle=25203
[NASFILE]

[NOTIFY]

[ADVICE]

[STATEMENT]
   

fdsfsdfsd%                          

git reset HEAD file命令是把缓存区中的file文件删去,对工作区后续做的修改并没有影响,比如上面的例子,git add后又修改了文件的内容everybody->chenj_freedom,git reset HEAD file后,file的内容还是chenj_freedom。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,可以用版本回退(参考版本回退一节),不过前提是没有推送到远程库。

git rm file 或者 git add file  
特别地:git rm --cache
git commit
➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>git add .
➜ /home/lufax/workspace/list-app git:(Reg_20180628) ✗>git commit -m "tmp"
[Reg_20180628 4873869] tmp
 1 个文件被修改,插入 1 行(+)
➜ /home/lufax/workspace/list-app git:(Reg_20180628)>git reflog
4873869 HEAD@{0}: commit: tmp
a470e0d HEAD@{1}: pull: Fast-forward
➜ /home/lufax/workspace/list-app git:(Reg_20180628)>git reset --hard HEAD^
HEAD 现在位于 a470e0d Merge branch 'fixBug0628' into 'Reg_20180628'
➜ /home/lufax/workspace/list-app git:(Reg_20180628)>cat release/20180628.txt 
[DEP]

[DB1]
   bettle=24974,25042
[DB2]
   bettle=25203
[NASFILE]

[NOTIFY]

[ADVICE]

[STATEMENT]
git stash用于保存和恢复工作进度
git stash

保存当前的工作进度。会分别对暂存区和工作区的状态进行保存

git stash save "message..."

这条命令实际上是第一条 git stash 命令的完整版

git stash list

显示进度列表。此命令显然暗示了git stash 可以多次保存工作进度,并用在恢复时候进行选择

git stash pop [--index] [<stash>]

如果不使用任何参数,会恢复最新保存的工作进度,并将恢复的工作进度从存储的工作进度列表中清除。
如果提供参数(来自 git stash list 显示的列表,则从该 <stash> 中恢复。恢复完毕也将从进度列表中删除<stash>。
项--index 除了恢复工作区的文件外,还尝试恢复暂存区。

git stash apply [--index] [<stash>]

除了不删除恢复的进度之外,其余和 git stash pop 命令一样

git stash clear

删除所存储的进度

合并
git merge --abort
远程仓库
关联远程仓库:
git remote add origin git@github.com:chenj-freedom/learngit.git 
 
查看远程仓库:
➜ /home/lufax/workspace/list-app git:(Reg_20180628)>git remote
origin
➜ /home/lufax/workspace/list-app git:(Reg_20180628)>git remote -v                             
origin    git@gitlab.lujs.cn:list/list-app.git (fetch)
origin    git@gitlab.lujs.cn:list/list-app.git (push)

git clone操作会自动为你将远程仓库命名为origin,并抓取远程仓库中的所有数据,建立一个指向它的master指针,在本地命名为orgin/master,然后,git自动建立一个属于你自己的本地master分支,始于origin上master分支相同的位置(master分支的关联,这个也叫做跟踪远程分支),你可以就此开始工作。

clipboard.png

举例:git push origin master

这里git自动把master扩展成了refs/heads/master:refs/heads/master,意为“取出我在本地的master分支,推送到远程仓库的master分支中去”。

若想把远程的master分支叫做other分支,可以使用git push origin master:other。

git fetch [remote-name] //抓取远程仓库的全部内容,但是不会自动合并  
git pull //抓取远程仓库跟踪分支的内容,并自动合并到本地相应的分支
git push [remote-name] :[remote-branch-name] 即删除远程仓库中的分支。






我是搬砖达人
20 声望3 粉丝