前言
本文是小编针对 David Mahler 在 Youtube 上对 Git 介绍进行的简单总结。Git是一种版本控制系统(version system control,简称VSC),它可以记录文件在一段时间内的变化。
Core Concepts
Commit Graph
commit graph(提交图)展示了我们的提交历史信息

Conceptual Area Diagram
Conceptual area diagram(概念区域图)为了便于理解Git在本地上的操作,我们需要了解下方的概念区域图

补充:
working tree 就是我们创建的netauto路径,还包含其中存在的任何子路径,但是不包含.git子路径
.git history 等价于提交图(commit graph), 它被放在隐藏文件.git中。
.git 路径包含构造repo需要的metadata和数据库对象,如果将 .git 发送给某个用户,那么该用户就有了整个 git 项目。
信息配置
git config --global user.name "huangning"
git config --global user.email "huangning@123.com"
git config --local user.name "huangninglocal"
git config --local user.email "huangninglocal@qq.com"
git config --list
|
基本操作

git add s1
git commit -m "add s1"
git commit
git log
git log -- s1:显示和s1相关的提交日志
|


git diff
git add s1 s2
git add s*
git add .
git diff --staged
|

删除文件
git log -p
git rm s2
git status
|

恢复文件

reset恢复
reset是用来修改提交历史的,它会丢弃掉一些版本历史,而revert是根据历史指定的commit生成一个新的commit,版本的历史不会被破坏。下图分别展示了revert和reset回到提交历史C状态的方法

git reset配合不同的参数,会对三个区域产生不同的影响,比如
- git reset —soft:改变HEAD所指向的commit
- git reset —mixed:改变HEAD所指向的commit并且将staging area区域更新为HEAD所指向的commit里包含的内容(默认参数)
- git reset —hard:改变HEAD所指向的commit并且将staging area以及working tree区域更新为HEAD所指向的commit里包含的内容
下图说明配合不同参数的reset所产生的不同效果

git reset --hard 38c5029b
git reflog
git reset --hard 98abc5a
git reset s1 git reset HEAD s1 git reset --mixed HEAD s1
reset xxxxx(哈希码) s1
|
checkout恢复
下部分描述的checkout切换分支会做3件事
- HEAD指向切换分支的最后一次commit
- 将HEAD指向commit里所有文件的sanpshot替换掉staging area区域里面的内容
- staging area区域里面的内容替换到working tree中的内容
注: staging area 里面一直不仅仅是git add之后才有东西,提交之后仍然有,所以staging area里面一直有东西!!!
从上述checkout的执行路径可以看到和reset —hard很像,但是有2个重要差别
- reset会把working directory里面的所有内容替换掉,而checkout不会修改之前在working tree里面修改过的文件
- reset会把branch移动到HEAD所指向的地方,checkout则把HEAD移动到另外的分支,比如有两个分支master和HN,这两个分支指向不同的commit,现在处于HN分支上(HEAD所指向的地方),如果通过git reset master,那么HN就会指向master所指向的commit,如果git checkout master, 那么develop不会动,只有HEAD会移动,HEAD指向master

git checkout 38c5029b -- s2
|
reset与checkout的比较

其中head列中的“REF”表示该命令移动了HEAD指向的分支引用,而“HEAD”则表示移动了HEAD自身,wd safe列中的YES表示不会动在work directory上的修改,而NO代表会动在work directory上的修改
补充
git rm --cached s1
alias graph="git log --all --decorate --oneline --graph"
|
Branch 和 Merge
Branch就是指向提交信息的指针,head 是告诉我们目前切换到哪里的指针,git 会自动创建第一个叫master的分支。
创建分支
git branch SDN git branch auth git branch
|

ps:图中绿色的分支表明HEAD指针正在指向master分支
切换分支


git add s1; git commit -m "SDN for s1"
git checkout auth
|

git commit -a -m "auth for s1"
|

补充
- 每次切换到一个分支,working area 和 staging area 中的文件都会更新成当前分支下的文件内容
合并分支
fast-forward merge
分支 B 包含分支 A 的所有历史提交信息,换句话说两个分支在一条路径上,对应的 merge 叫 fast-forward merge
git diff master..SDN
git merge SDN
|

3-way merge
分支 B 和分支 A 位于不同的路径上,换句话讲就是从一个分支出发,分成不同路径的分支,再合并到成分支的 merge 方式 叫 3-way merge


删除分支

git branch -d SDN
git branch -d SDN
|

ps: 如果非要删除没有合并的分支,就可以采用
Merge 冲突
Merge冲突一般发生在我们在合并分支的时候,不同的分支下同一个文件中同一行内容有着不同的修改
构造冲突
git checkout -b dev
git diff
|

git commit -a -m "update s1 VLANS"
git checkout master
graph
|

修改前的s1文件内容和两个修改后的s1文件内容比较

从比较图可以看出:
- 相比于base版本的mgmt_ip,master上进行了修改,但是dev上没有进行修改,那么合并的结果就是修改的结果
- 相比于base的vlans,dev上的是green,而master上的是pink,也就是在两个分支上修改了相同的行,这样就产生了第1个冲突
- 相比于base的第1个ports,dev和master进行了相同的修改,所以没有冲突
- 相比于base的第2个ports,dev进行了修改,但是master进行了删除,所以这就产生了第2个冲突


git merge --abort
git status
|

解决冲突

我们将其中的冲突修改掉,变成这样婶儿的👇



Detached HEAD
如果HEAD指针没有只想某个分支,而是志向某次commit,我们就是有一个detached HEAD state(分离的头指针状态)



从上图可以看到创建了一个新的分支,但是HEAD指针并没有指向该分支

从上图可以看到HEAD指针不再是detached状态
Git stash
每次前换分支或者merge分支的时候,我们的working tree 和 staging area 都是 clean 的状态,但是有时我们可能没有clean state,那么就可能会出错
# 首先切换回master分支 git checkout master
# 对master中的s1文件进行修改,并且要切换分支 git checkout stage
|

从上图结果可以看到系统针对没有clean state会提供两种方法,第二种方法就是stash(贮藏)

stash之后我们就可以随意checkout与merge分支了
git stash list
git stash list -p
|


git stash apply stash@{1}
git stash save "add yellow vlan"
|

git stash pop
git stash pop stash@{2}
|
Remotes
Remote 就是另外一个地方的repo, 这个地方可以是github上的repo,也可以是自己机器上的其他repo
GitHub连接
git clone git@github.com:HuangNing616/MLStockPrediction.git
git config --local user.name "huangStock" git config --local user.email "huangStock@stock.com"
|
Remote

从上图可以看到,origin是我们第一次远程连接repo地址的默认别名
alias graph="git log --all --decorate --oneline --graph"
graph
|

从上图可以出了本地的master以外,还多了origin/master,它是remote-tracking branch,这个分支表示origin上的master情况,换句话说github上的master分支和本地的master分支正在指向同一个commit
git checkout origin/master
|

Fetch 和 Merge
git fetch origin
git status
|

从上图可以看到本地branch落后于origin/master
git merge origin/master
git commit -a -m "modify s1"
graph
|


git push origin master
graph
|

Fork
假如另外一个同学A也想要加入该repo中,但是他没有向repo写/push的权利,其中一种解决办法就是使用fork,fork可以创造repo的copy版本到同学A的github中,之后同学A就可以通过gi t clone 在本地对该repo进行编辑
添加Remote
git remote add upstream git@github.com:HuangNing616/JavaNote.git
git remote -v
|

git remote remove upstream
git fetch upstream
git checkout -b "edit-s2"
git branch
git branch -r
git branch -a
|

补充
当从远端pull代码的时候用origin的前提是远端只有一个master分支,如果有多个分支的话需要指定pull具体的某个分支
git pull & git pull —rebase
假如我们fetch下来的commit graph是有两个分支情况,比如它这样婶儿的👇

将两个分支进行合并有两种方法
git merge:将两个分支合并并保留之前每个分支的提交信息

git rebase:将两个分支合并并删除之前mytask所在的分支记录

git pull origin
git pull --rebase origin master
git add .
git rebase --continue
|
- Introduction to Git - Core Concepts
- Introduction to Git - Branching and Merging
- Introduction to Git - Remotes