分布式版本控制系统
版本控制系统(VCS)的核心:版本控制,主动提交,中央仓库
中央式版本控制系统的工作模型
分布式版本控制系统(DVCS)的工作模型
中央式VCS的中央仓库有两个功能:保存版本历史,同步团队代码
分布式VCS把保存版本历史交给了本地仓库,中央仓库只负责同步团队代码
优缺点:
避免了对网络的依赖
大型项目体积太大无法保存在本地
团队的基本工作模型
核心内容
- 写完所有的
commit后,不用考虑远程仓库是否有新的commit,直接push - 如果
push失败,就用pull把远程仓库上新的commit取回到本地和本地合并,然后再push
原理
当pull操作发现不仅远程仓库包含本地没有的commit,而且本地仓库也包含远程仓库没有的commit时,它就会把远端和本地的独有 commit进行合并,自动生成一个新的 commit ,和手动的 commit 不同,这种 commit 会自动填入一个默认的提交信息
git status本质上是将本地分支与它正在跟踪的远程分支进行比较
git status只能判断本地分支是否超前于远程分支,无法判断远程分支是否超前于本地分支通过git pull拉取远程代码时,如果远程仓库包含本地没有的commit,本地也包含远程没有的commit,那么除了把远程的commit拉取到了本地外,还会在本地新建一个commit表示自动合并。也就是说自动生成commit只是用来表示一次合并的过程,没有实际意义,commit会按照的时间线进行同步
最流行的工作流:Feature Branching
优势
- 代码分享
- 一人多任务
核心内容
- 任何新的功能或者bug修复全都新建一个
branch来写 branch写完后,合并到master,然后删掉这个branch
删除本地有但在远程库已经不存在的分支
git remote prune origin
Git引用
HEAD是一个永远自动指向当前commit的引用branch也是一种引用,HEAD除了可以指向commit,还可以指向一个branch,当它指向某个branch时,会通过这个branch来间接指向某个commit,当HEAD提交时自动向前移动的时候,会带着它所指向的branch一起移动

HEAD指向的branch不能删除,如果要删除HEAD指向的branch,需要先用checkout把HEAD指向其它地方- 删除
branch的操作只是删除引用,并不会删除任何commit,如果一个commit不在任何一个branch的路径上(野生commit),那么在一定时间后,它会被Git的回收机制删除
clone本质
git clone除了从远程仓库中把.git这个仓库目录下载到工作目录中,还会checkout master,checkout就是把某个commit作为当前commit,把HEAD移动过去,并把工作目录的文件内容替换成这个commit所对应的内容
push的本质
把当前branch 的位置(即它指向哪个 commit)上传到远端仓库,并把它的路径上的 commit一并上传
不加参数的 git push 只能上传那些之前从远端 clone 下来或者 pull 下来的分支,而如果需要 push 你本地的自己创建的分支,则需要手动指定目标仓库和目标分支(并且目标分支的名称必须和本地分支完全相同),
在 feature1 被 push 时,远程仓库的 HEAD 并没有和本地仓库的 HEAD 一样指向 feature1。这是因为,push 的时候只会上传当前的 branch 的指向,并不会把本地的 HEAD 的指向也一起上传到远程仓库。事实上,远程仓库的 HEAD 是永远指向它的默认分支(即 master,如果不修改它的名称的话),并会随着默认分支的移动而移动的。
merge的本质
从目标commit和当前commit分叉的位置起,把目标commit的路径上的所有commit的内容一并应用到当前 commit,然后自动生成一个新的commit
git merge branch1
merge原理.gif)
冲突:如果两个branch修改了同一部分内容,merge就无法自动合并,需要手动解决冲突
- 解决掉冲突
- 手动
commit
放弃解决冲突
git merge --abort
pull本质
git pull 这个指令的内部实现就是把远程仓库使用 git fetch 取下来以后再进行 merge 操作的
pull原理.gif)
origin/master 和 origin/HEAD 是什么鬼:它们是对远端仓库的 master 和 HEAD 的本地镜像,在 git pull 的「两步走」中的第一步——git fetch 下载远端仓库内容时,这两个镜像引用得到了更新,也就是上面这个动图中的第一步:origin/master 和 origin/HEAD 移动到了最新的 commit。
而 git pull 的第二步操作 merge 的目标 commit ,是远端仓库的 HEAD,也就是 origin/HEAD ,
checkout本质
git checkout branch 的本质,其实是把 HEAD 指向指定的 branch,然后签出这个 branch 所对应的 commit 的工作目录。所以同样的,checkout 的目标也可以不是 branch,而直接指定某个 commit
rebase本质
add理解
通过add添加进暂存区的不是文件名,而是具体的文件改动内容,在add时的改动都被添加进了暂存区,但在add之后同一文件的新改动并不会自动被添加进暂存区
改动对比
比对暂存区和上一条提交
这条指令可以让你看到「如果你立即输入 git commit,你将会提交什么」:
git diff --staged
比对工作目录和暂存区
这条指令可以让你看到「如果你现在把所有文件都 add,你会向暂存区中增加哪些内容」:
git diff
比对工作目录和上一条提交
这条指令可以让你看到「如果你现在把所有文件都 add 然后 git commit,你将会提交什么」
git diff HEAD
rebase
rebase 是站在需要被 rebase 的 commit 上进行操作,这点和 merge 是不同的。
为了避免和远端仓库发生冲突,一般不要从 master 向其他 branch 执行 rebase 操作。而如果是 master 以外的 branch 之间的 rebase(比如 branch1 和 branch2 之间),就不必这么多费一步,直接 rebase 就好。
交互式 rebase,它可以在 rebase 开始之前指定一些额外操作。交互式 rebase 最常用的场景是修改写错的 commit,但也可以用作其他用途。它的大致用法:
- 使用方式是
git rebase -i 目标commit; - 在编辑界面中指定需要操作的
commits 以及操作类型; - 操作完成之后用
git rebase --continue来继续rebase过程。
之前讲的修正 commit 的方法是把要修改的 commit 左边的 pick 改成 edit,而如果你要撤销某个 commit ,做法就更加简单粗暴一点:直接删掉这一行就好。
Git安装
apt-get install gitgit --version
Git基本命令
git init # 初始git仓库,出现.git目录git status # 查看项目文件状态git add xxx # 把工作区的文件提交到暂存区git commit -m "xxx" # 把暂存区的文件提交到版本库git log [--oneline] # 查看提交版本记录git commit -am "xxx" # 直接将工作区的文件提交到版本库
Git结构和状态
git的3层结构
working directory // 工作区staging index // 暂存区git directory(Repository) // 版本库
git文件的4种状态
untracked // 未跟踪changed/unstaged // 已修改/未暂存staged // 已暂存commited // 已提交
git配置
git config --global user.name xxxgit config --global user.email xxxgit config --list # 列出配置
Git撤销操作
git commit --amend # 撤销上一次提交,并将暂存区的文件重新提交git checkout -- xxx # 拉取暂存区的文件并将其替换工作区的文件, 注意与git checkout branchname区别git reset HEAD xxx # 拉取最近一次提交的版本库中的这个文件到暂存区,该操作不影响工作区
Git文件删除
git rm xxx # 删除工作区和暂存区中的文件,相当于删除文件后执行git addgit rm --cached xxx # 在不小心把不需要追踪的文件添加到暂存区,想删除暂存的文件但是不想删除工作区的文件时有用git rm -f xxx # 当工作区或者暂存区的文件修改了git mv oldname newname # 相当于mv oldname newname,git rm oldname,git add newname
Git分支
git log --oneline # 简洁查看分支git log --graph --all # 以图表形式查看所有分支git branch # 查看本地分支git branch -a # 查看本地和远程仓库所有分支git branch -r # 查看远程仓库git checkout -b xxx # 等价于git branch xxx,git checkout xxxgit checkout -b xxx 2b1c225dc # 从某个版本创建分支git checkout online # 切换到xxx分支git checkout -git branch -d online # 删除xxx分支git checkout master # 先切换到master分支git merge --no-ff xxx # 合并代码到master分支(禁止快进式合并)
Github远程仓库
git remote add xxx https://gitee.com/ouweibin/xxx.git # 添加别名git remote -v # 查看添加的远程地址git remote remove xxx # 删除指定的远程地址
补充
Git更新本地代码
git fetch xxx master:temp # 从远程的xxx仓库的master分支下载到本地并新建一个分支tempgit diff temp # 比较master分支和temp分支的不同git merge temp # 合并temp分支到master分支git branch -d temp # 删除temp
.gitignore文件
使用.gitignore忽略不想跟踪的文件或者文件夹
修改Git默认编辑器nano为vim
git config --global core.editor vim
Git修改最后一个版本
执行修改操作git commit --amend
Git修改非最后一个版本(危险)
rebase -i:交互式rebase
^ 的用法:在 commit 的后面加一个或多个 ^ 号,可以把 commit 往回偏移,偏移的数量是 ^ 的数量。例如:master^ 表示 master 指向的 commit 之前的那个 commit; HEAD^^ 表示 HEAD 所指向的 commit 往前数两个 commit
~ 的用法:在 commit 的后面加上 ~ 号和一个数,可以把 commit 往回偏移,偏移的数量是 ~ 号后面的数。例如:HEAD~5 表示 HEAD 指向的 commit往前数 5 个 commit
git loggit rebase -i HEAD^^把要修改版本的pick改成edit,保存退出执行修改操作git commit --amendgit rebase --continue # 重复直到Successfully
Git删除最后一个版本
git reset --hard HEAD^ # 之后的版本全部清空
Git修改非最后一个版本(危险)
Git删除远程仓库的某次错误提交
在本地把远程的master分支删除,再把reset后的分支内容给push上去(远程仓库默认分支不能为master,否则会删除失败)
git push origin :master # 删除远程的master分支(注意master前有个:)git push origin master # 重新创建远程master分支或者:git reset --hard <commit_id> # 回滚到你想回滚的commitgit push origin HEAD --force # 重新push到你的远程仓库
git push <远程主机名> <本地分支名>:<远程分支名>
如果远程分支名省略,则表示将本地分支推送到与之存在追踪关系的远程分支(通常两者同名),如果该远程分支不存在,则会被新建;如果本地分支名省略,则表示删除指定的远程分支,等同于推送一个空的本地分支到远程分支
