美文网首页
版本控制

版本控制

作者: android小菜鸡一枚 | 来源:发表于2018-09-30 15:17 被阅读0次

    Git

    Git是一个分布式版本控制系统(Distributed Version Control System - DVCS)

    版本控制系统(Version Control System - VCS)

    核心:版本控制,主动提交,中央仓库三个要素

    中央式版本控制系统(Centralized VCS)

    中央仓库的作用:保存版本历史,同步团队代码

    分布式版本控制系统(Distributed VCS/DVCS)

    分布式VCS除了中央仓库之外,还有本地仓库。
    一.工作模型:
    1.首先代码提交到本地仓库;
    2.在服务器创建一个中央仓库,把代码从本地仓库推送到服务器的中央仓库;
    3.其他同事把中央仓库的内容克隆到本地,拥有了各自的本地仓库;
    4.在功能开发中,一个人会把它的每一步改动提交到本地仓库,再从本地仓库推送到中央仓库;
    5.另外两个人就可以选择把这些提交同步到自己的机器上,并把它们和自己的本地代码合并。
    二.优点:
    大多数的操作可以在本地进行,所以速度更快,而且由于无需联网;由于可以提交到本地,所以你可以分步提交代码,把代码提交做得更细,而不是一个提交包含很多代码,难以 review 也难以回溯;
    三.缺点:
    由于每一个机器都有完整的本地仓库,所以初次获取项目(Git 术语:clone)的时候会比较耗时;本地占用的存储比中央式 VCS 要高。

    Git基本使用

    下载地址:Git下载

    1. 在GitHub通过New Repository来新建远程仓库,在Create a new
      repository的时候,填写Repository name,Add.gitignore:Android,最后点击Create repository完成创建;创建完成后,点击右边Clone or download,把仓库的clone地址复制到剪贴板;
    2. 从GitHub把中央仓库clone到本地(使用命令:git clone)
      git clone 复制的地址
      注:.git 目录就是你的本地仓库(Local Repository),所有的版本信息都会存在这里,而.git所在的根目录,称为Git的工作目录(Working Directory),它保存了你当前从仓库中checkout的内容。
      在项目的目录下输入:git log 查看提交历史
    3. 代码提交(先用git add 文件名把文件添加到暂存区,再用git commit提交)
      在这个过程中,可以使用git status来随时查看工作目录的状态
      image.png
      注:每个文件有"changed/unstaged"(已修改),"staged"(已修改并暂存),"commited"(已提交)三种状态,以及一种特殊状态"untracked"(未跟踪)

    用add指令来让Git开始跟踪:git add eZhouXingV5-Android
    再次输入git status

    image.png
    提交的方式是用commit指令:git commit
    在初始状态下,你是在命令模式,不能编辑这个文件,你需要按一下 "i"(小写)来切换到插入模式,然后就可以输入你的提交信息了;
    在输入完成后别按回车,而是要按 ESC 键返回到命令模式,然后连续输入两个大写的 "Z"(用 Shift 键或 Capslock 键都可以),就保存并退出了;
    1. 提交一次或多次之后,把本地提交push到中央仓库(git push)
      可以使用git push来把你的本地提交发布(即上传到中央仓库)

    团队工作的基本工作模型

    模拟同事的本地仓库:
    git clone 地址 文件名
    从远程仓库更新内容使用: git pull
    流程:同事commit代码到他的本地,并push到GitHub中央仓库;你把GitHub的新提交通过pull指令来取到你的本地;

    push冲突:由于 GitHub 的远端仓库上含有本地仓库没有的内容,所以这次 push 被拒绝了;
    解决方式:先用 pull 把远端仓库上的新内容取回到本地和本地合并,然后再把合并后的本地仓库向远端仓库推送;
    多人合作的基本工作模型:

    1. 写完所有的 commit 后,不用考虑中央仓库是否有新的提交,直接 push 就好;
    2. 如果 push 失败,就用 pull 把本地仓库的提交和中央仓库的提交进行合并,然后再 push 一次;

    进阶 1:HEAD、master 与 branch

    HEAD

    当前commit的引用,它指的就是当前工作目录所对应的commit;它具有唯一性,每个仓库中只有一个 HEAD。在每次提交时它都会自动向前移动到最新的 commit 。

    branch分支

    HEAD 除了直接指向 commit,也可以通过指向某个 branch 来间接指向 commit。当 HEAD 指向一个 branch 时,commit 发生时,HEAD 会带着它所指向的 branch 一起移动。

    master 默认branch

    主branch/主分支

    1. 新建的仓库中的第一个 commit 会被 master 自动指向;
    2. 在 git clone 时,会自动 checkout 出 master。
    branch的创建,切换和删除
    1. 创建branch:git branch 名称
    2. 切换branch: git checkout 名称
      可以用git checkout -b 名称创建后自动切换,用指定的名称创建 branch 后,再直接切换过去;
    3. 删除branch: git branch -d 名称
      HEAD 指向的 branch 不能删除。如果要删除 HEAD 指向的 branch,需要先用 checkout 把 HEAD 指向其他地方。

    进阶 2:push 的本质

    1. push 是把当前的分支上传到远程仓库,并把这个 branch 的路径上的所有 commits 也一并上传;
    2. push 的时候,如果当前分支是一个本地创建的分支,需要指定远程仓库名和分支名,用git push origin branch_name 的格式,而不能只用 git push;或者可以通过 git config 修改 push.default 来改变 push 时的行为逻辑。
    3. push 的时候之后上传当前分支,并不会上传 HEAD;远程仓库的 HEAD 是永远指向默认分支(即 master)的;

    进阶 3:merge:合并 commits

    1. merge含义:从两个 commit「分叉」的位置起,把目标 commit 的内容应用到当前 commit(HEAD 所指向的 commit),并生成一个新的 commit;执行git merge branch1
    2. merge的使用场景:
      单独开发的branch用完了以后,合并回原先的branch;
      git pull的内部自动操作

    pull的内部操作:pull的实际操作其实是把远端仓库的内容用fetch取下来之后,用merge来合并;
    merge在合并的时候,是有一定的自动合并能力的,如果一个分支改了A文件,另一个分支改了B文件,那么合并后就是既改A也改B;如果两个分支都改了同一个文件,但一个改的是第 1 行,另一个改的是第 2 行,那么合并后就是第 1 行和第 2 行都改,也是自动完成。

    1. merge的三种特殊情况
      3.1 原因:当前分支和目标分支修改了同一部分内容,Git无法确定应该怎样合并;
      应对方法:解决冲突后手动commit;


      image.png

      Git 添加了三行符号 <<< === >>>
      3.2 HEAD领先于目标commit: Git什么也不做,空操作;
      3.3 HEAD落后于目标commit:fast-forward;

    进阶 4:Feature Branching:最流行的工作流

    简介:

    1. 任何新的功能(feature)或 bug 修复全都新建一个 branch 来写;
    2. branch 写完后,合并到 master,然后删掉这个 branch;
    git checkout -b books;//创建一个新的branch叫做books
    git push origin books;//把代码push到中央仓库
    git pull;//同事从中央仓库拉下代码
    git checkout books;//切换到分支books
    // 合并到master
    git checkout master;
    git pull;//merge之前pull一下,让master更新到和远程仓库同步
    git merge books;//合并books分支
    // 合并后的结果push到了中央仓库,并删掉了books这个branch
    git push;
    git branch -d books;
    git push origin -d books// 用-d参数把远程仓库的branch也删了
    

    进阶 5:关于 add

    add把改动的内容放进暂存区

    1. add后面加个点'.':全部暂存

    git add .直接把工作目录下的所有改动全部放进暂存区;

    2. add添加的是文件改动,而不是文件名

    进阶 6:看看我都改了什么

    git log可以查看历史记录

    1. 查看历史中的多个commit: log

    查看详细改动:git log -p;
    查看大致改动: git log --stat

    2. 查看具体某个commit: show

    要看最新 commit ,直接输入 git show;要看指定 commit ,输入 git show commit的引用或SHA-1;
    如果还要指定文件,在 git show 的最后加上文件名

    3. 查看未提交的内容:diff

    查看暂存区和上一条 commit 的区别:git diff --staged(或 --cached)
    查看工作目录和暂存区的区别:git diff 不加选项参数
    查看工作目录和上一条 commit 的区别:git diff HEAD

    高级 1:不喜欢 merge 的分叉?用 rebase 吧

    rebase——在新位置重新提交,重写设置基础点,改变commit序列的基础点
    使用方式:git rebase 目标基础点

    git checkout branch1
    git rebase master
    // 在rebase之后,记得切回master再merge一下,把master移动最新的commit:
    git checkout master
    git merge branch1
    

    高级 2:刚刚提交的代码,发现写错了怎么办?

    用 commit --amend 可以修复当前提交的错误: git commit --amend,commit --amend 并不是直接修改原 commit 的内容,而是生成一条新的 commit。

    git add 笑声.txt
    git commit --amend
    

    高级 3:写错的不是最新的提交,而是倒数第二个?

    commit --amend 可以修复最新 commit 的错误,但如果是倒数第二个 commit 写错了,怎么办?

    rebase -i:交互式 rebase

    开启交互式 rebase 过程: git rebase -i HEAD^^
    把当前 commit ( HEAD 所指向的 commit) rebase 到 HEAD 之前 2 个的 commit 上;
    交互式 rebase 最常用的场景是修改写错的 commit

    1. 使用方式是 git rebase -i 目标commit;
    2. 在编辑界面中指定需要操作的 commits 以及操作类型;
    3. 操作完成之后用git rebase --continue 来继续 rebase 过程。

    高级 4:比错还错,想直接丢弃刚写的提交?

    reset --hard 丢弃最新的提交

    git reset --hard HEAD^:HEAD^ 表示你要恢复到哪个 commit。因为你要撤销最新的一个 commit,所以你需要恢复到它的父 commit ,也就是 HEAD^。那么在这行之后,你的最新一条就被撤销了

    高级 5:想丢弃的也不是最新的提交?

    用交互式 rebase 撤销提交

    交互式 rebase 可以用来修改某些旧的 commits。其实除了修改提交,它还可以用于撤销提交;
    你想撤销倒数第二条 commit,那么可以使用 rebase -i:git rebase -i HEAD^^

    用 rebase --onto 撤销提交

    在 rebase 命令中直接剔除想撤销的 commits

    高级 6:代码已经 push 上去了才发现写错?

    1. 出错的内容在你自己的 branch

    如果你在本地对已有的commit做了修改,这时你再push就会失败,因为中央仓库包含本地没有的commits,这时选择强行push:
    git push origin branch1 -f:忽略冲突,强制push

    2. 出错的内容已经合并到 master

    增加一个新的提交,把之前的提交的内容抹掉;
    不要强制 push,而要用 revert 把写错的 commit 撤销;git revert HEAD^

    高级 7:reset 的本质——不止可以撤销提交

    reset 的本质:移动 HEAD 以及它所指向的 branch

    reset --hard HEAD^它把 HEAD 和它所指向的 branch 一起移动到了当前 commit 的父 commit 上,从而起到了「撤销」的效果;
    把 HEAD 和 branch 移动到其他的任何地方:git reset --hard branch2

    reset --hard:重置工作目录

    重置位置的同时,清空工作目录的所有改动;

    reset --soft:保留工作目录

    r重置位置的同时,保留工作目录和暂存区的内容,并把重置 HEAD 的位置所导致的新的文件差异放进暂存区;

    reset 不加参数:保留工作目录,并清空暂存区

    --mixed(默认):重置位置的同时,保留工作目录的内容,并清空暂存区。

    高级 8:checkout 的本质

    git checkout branch名: checkout 的本质是签出指定的 commit,所以你不止可以切换 branch,也可以直接指定 commit 作为参数,来把 HEAD 移动到指定的 commit。

    checkout 和 reset 的不同

    reset 在移动 HEAD 时会带着它所指向的 branch 一起移动,而 checkout 不会。当你用 checkout 指向其他地方的时候,HEAD 和 它所指向的 branch 就自动脱离了。

    高级 9:紧急情况:「立即给我打个包,现在马上!」

    stash:临时存放工作目录的改动

    在 Git 中,stash 指令可以帮你把工作目录的内容全部放在你本地的一个独立的地方,它不会被提交,也不会被删除,你把东西放起来之后就可以去做你的临时工作了,做完以后再来取走,就可以继续之前手头的事了。git stash
    打完包切回你的分支: git stash pop

    高级 10:branch 删过了才想起来有用?

    branch 用完就删是好习惯

    reflog :引用的 log

    查看一下 HEAD 的移动历史:git reflog

    查看其他引用的 reflog

    reflog 默认查看 HEAD 的移动历史,除此之外,也可以手动加上名称来查看其他引用的移动历史:git reflog master

    额外说点:.gitignore——排除不想被管理的文件和目录

    .gitignore记录了所有你希望被 Git 忽略的目录和文件。


    image.png

    Git原理详解及实用指南

    相关文章

      网友评论

          本文标题:版本控制

          本文链接:https://www.haomeiwen.com/subject/tzxyoftx.html