git学习笔记

1. git是什么


       一种分布式版本控制工具。

2. 为什么选择使用git


2.1 git的特点

        git和其他版本控制工具的主要差别:git 只关心文件数据的整体是否发生变化,而大多数其他版本控制工具则只关心文件内容的具体差异。

          

       git并不保存version变化前后的差异数据。git作为一个小型的文件系统,每次提交更新(commit)时,它会纵览一遍所有的文件指纹信息并对文件做一次快照,然后保存一个指向这次快照的索引。为了提高性能,若文件没有变化,git只对上次保存的快照索引做一次链接。

2.2 git的优点

     (1)几乎所有操作都可以本地执行;

     (2)可以时刻保证数据的完整性:SHA-1算法计算数据的校验和;

     (3)多数的操作仅是添加数据。

3. git的基础


3.1  git的三种状态

        对于任何一个文件,在 git 内都只有三 种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。

 

             

       所谓的暂存区域只不过是个简单的文件,一般都放在 git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

       基本的 Git 工作流程如下所示:

       (1) 在工作目录中修改某些文件。

       (2)对这些修改了的文件作快照,并保存到暂存区域。

       (3)提交更新,将保存在暂存区域的文件快照转储到 git 目录中。

      git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。这些变量可以存放在以下三个不同的地方:系统级别的/etc/gitconfig文件 ;用户级别的 ~/.gitconfig ;项目级别的 在工作目录中的.git/config 。使用git  config --list 命令可以查看配置信息。

        其中有些在目录中但是不需要被git管理的文件可以在.gitignore文件中进行设置,具体设置方法请参考。 

3.2  git的基本命令

设置用户名和邮箱
git config --global user.name "**"  # "**"换成自己名字的拼音,注意中间不要有空格
git config --global user.email  *@****.com
创建git
1. git init   # cd到工作目录中 
2. git clone ssh://git@git.**.com/web/www.git  # 其中www是要克隆的版本库
更新代码库到最新版本
git pull
查看工作区状态
git status
提交代码到本地仓库
git add **.java   # 提交**.java文件到暂存区
git commit -m [-a] “更新描述” # 使用-a可以跳过使用暂存区域,即跳过git add
推送到远程仓库
git pull  # 更新代码库到最新版本
git push  # 开始推送
git push origin master # 对新建远程仓库的第一次推送,需要指定主分支名master
暂存区操作
git add **.java   # 提交**.java文件到暂存区
git reset HEAD **.java # 删除暂存区中的**.java文件
查看代码改动
git diff # 查看工作区与暂存区的文件差异
git diff --cached # 查看暂存区与最后一次本地提交的文件差异
git diff HEAD # 工作区与最后一次本地提交之间的差异
git diff origin # 工作区与本地仓库原始版本比较
查看提交记录
git log # 后面加上参数可以查看加上限制条件的记录
远程仓库操作
git remote # 列出每个远程库的简短名字
git remote add [remote-name] [url] # 添加远程库
git fetch  [remote-name]  # 把远程仓库remote-name更新至本地仓库
git push [remote-name] [branch-name] # 将本地仓库中的数据推送到远程仓库
git remote show [remote-name] # 查看远程仓库remote-name的信息
移动文件
git mv file_from file_to  等价于 
    git rm file_from
    git add file_to
查看命令帮助
git help command # command是对应的git命令

3.3  git的分支与合并

       (1)分支的概念

       当使用 git commit 新建一个提交对象前,git 会先计算每一个子目录的校验和,然后在 git 仓库中将这些目录保存为树(tree)对象。之后 git 创建的提交对象,除了包含相关提交信息以外,还包含着指向这个树对象的指 针,如此它就可以在将来需要的时候,重现此次快照的内容了。如下左图所示,git仓库中有五个对象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象的索引和其他提交信息元数据的 commit 对象作些修改后再次提交,提交对象会包含一个指向上次提交对象的指针,如下右图所示。 

        

    git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。git 会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次 提交对象的 master 分支,它在每次提交的时候都会自动向前移动。 

创建并切换分支
git branch [branch-name]  # 建立新的分支
git checkout [branch-name] # 切换分支
git branch -b [branch-name] # 新建并切换到新的分支
git checkout -b [branch-name] master # 从master分支创建新分支,并切换到新分支

       (2)分支的合并

合并分支
git merge master  # 把master分支合并到当前分支
git merge [branch-name] --squash # 合并[branch-name]分支到当前分支,但将分支上的提交压缩,然后手工提交变成一次提交。
git merge origin/master  # 合并远程的master分支到当前分支

       在合并时,如果你修改了两个待合并分支里同一个文件的同一部 分,git 就无法干净地把两者合到一起,出现冲突(conflit)。任何包含未解决冲突的文件都会以未合并(unmerged)状态列出。git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。 

查看和删除分支
git branch # 查看所有的分支,带*号的是当前所在分支
git branch -v  # 查看各个分支最后一次commit信息
git branch --merged # 查看与当前分支合并过的分支,只要合并过的分支即使删掉也不用担心
git branch --no-merged # 查看与当前分支没有合并过的分支
git branch -d [branch-name]  # 删除分支
git branch -D [branch-name] # 强制删除分支     

      许多使用 git的开发者都喜欢以如下方式来开展工作,比如仅在 master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。与此同时,他们还有一个名为 develop 或 next 的平行分支,专门用于后续的开发,或仅用于稳定性测试 —— 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到master 里。这样,在确保这些已完成的特性分支(短期分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布。稳定分支的指针总是在提交历 史中落后一大截,而前沿分支总是比较靠前。

             

       (3)远程分支

       如果我们克隆一个项目(git clone ssh://git@git.sankuai.com/web/www.git),git服务器 会自动将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针,在本地命名为 origin/master,但我们无法在本地更改其数据。接着,git 建立一个属于自己的本地 master 分支,始于 origin上 master分支相同的位置,我们可以就此开始工作。

       可以运行 git fetch origin 来进行同步,该命令首先找到 origin 是哪个服务器,从上面获取本地尚未拥有的数据,更新本地的数据库,然后把 origin/master 的指针移到它最新的位置 。要想和其他人分享某个分支,你需要把它推送到一个你拥有写权限的远程仓库 ,可以运行 git push (远程仓库名) (分支名) 。  

远程分支操作
git push origin [branch-name]  # 将本地分支[branch-name]保存到远程
git push origin :[branch-name] # 将远程分支[branch-name]删除
git branch -a #查看目录下的所有分支

3.4  rebase与merge

       把一个分支整合到另一个分支的办法有两种:merge(合并) 和 rebase(衍合)。

       (1)rebase与merge的区别

       最容易的整合分支的方法是 merge 命令,如下图所示,它会把两个分支最新的快照(C4和 C6)以及二者最新的共同祖先(C2)进行三方合并。同时,也可以把在 C36里产生的变化补丁重新在 C4 的基础上打一 遍。在 Git 里,这种操作叫做衍合。有了 rebase 命令,就可以把在一个分支 里提交的改变在另一个分支里重放一遍。它的工作原理是回到两个分支(你所在的分支和你想要衍合进去的分支)的共同祖先,提取你所在分支每次提交时产生的差异(diff),把这些差异分别保存到临时文件里,然后从当前分支转换到你需要衍合入的分支,依序施用每一个差异补丁文件。

             

        当合并时发生conflict的时候,merge只需要解决一次冲突即可,而rebase则可能需要多次解决。在解决完冲突后,用"git-add"命令去更新这些内容的索引(index), 使用rebase你无需执行 git-commit,只要执行:

       $ git rebase --continue
       这样git会继续应用(apply)余下的补丁。
       在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。
       $ git rebase --abort
       可以看一下用合并(merge)和用rebase所产生的历史的区别:
         
      无论是通过一次衍合还是一次三方合 并,都是同样的快照内容,只是提交的历史不同罢了。衍合按照每行改变发生的次序重演发生的改变,而合并是把最终结果合在一起。使用 rebase 的话git树看起来更干净。

      (2)rebase使用时可能存在的问题

        永远不要衍合那些已经推送到公共仓库的更新

        一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。

        举一个例子说明

      (3)使用时rebase与merge的选择

       如果你修改比较多,预期会有较多的 conflict,建议用 merge。如果修改范围较小,不太预期有 conflict,則建议可以加上 rebase 参数。

      “同分支总是 git pull --rebase origin xxx, 合并分支总是 git merge  xxx 禁止 rebase”

4. git 工具


4.1 版本回滚

HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。

穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

      

4.2 撤销修改

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。

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

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,使用版本回滚,不过前提是没有推送到远程库。

4.3 git reset –soft与git reset –hard区别

git reset –soft之后,git diff返回空,而git diff –cached和git diff HEAD会返回有效信息。这说明使用–soft选项后,只回退了commit的信息,而不会回复到index file一级。你如果想撤销commit,并且只回退commit的信息,那么就用–soft吧!git reset –hard会完全撤销一个commit,彻底的回复到上一次commit的状态。连working tree的源代码也会完全倒退到上次commit之时的状态。所以使用–hard后,git diff,git diff –cached和git diff HEAD都会返回空。

有了这个–hard好工具,你可以这样做:在当前的current working tree中修改了代码,你可以选择git add或者不add,然后使用git reset –hard HEAD命令就可以恢复到修改之前的最初状态了。你修改的代码和git add的信息都会被丢弃。这个用法记住它,早晚你会用到它。但往往你会武断的认为git reset只能恢复到之前的commit状态,但你往往想不到git reset还可以恢复到当前的HEAD所指定的commit状态。

5. gitWorkflow


        工作流程如下图所示:

        

       假如已经有一份Git代码仓库,代码仓库里面默认会有一个master分支。

(1)从master分支建立develop分支,然后在develop分支上进行开发
git checkout master # 切换到master分支
git checkout -b develop # 从master创建develop分支,并切换到该分支
(2)在develop开发已经完毕(修复bug或者添加新特性),这时从develop创建mirror分支
git commit -m -a "fix bug 1" # 修复了bug1
git commit -m -a "add file 2" # 新增文件2  
git checkout -b mirror # 从develop创建mirror分支,并切换到该分支     
(3)更新master到最新,把master的代码更新合并到mirror。如果有冲突,请解决冲突后提交;
git checkout master
git pull # 更新master到最新
git checkout mirror
git merge master # 合并master到mirror    
(4)把mirror分支的代码更新合并到master,然后推送到远程。
git checkout master
git merge mirror --squash # 压缩合并mirror分支上的代码更新
git commit -a -m 'xxxx' #注意需要进行一次提交
git push # 推送到远程
         开发时注意: 不要在master上进行开发,master分支是连接远程代码库和本地分支的桥梁,桥梁的功能只有一个就是连接。 mirror分支的作用是,如果合并发生冲突,可以保留一份干净的副本,如果改动很小,这个分支也可以不要。
         在我们平时开发过程中,有一种情况经常出现,就是在第二步的develop开发中,如果需要两个人(主A,副B)合作开发,就需要B从A提交的远程分支上创建自己的分支develop2,开发完成后commit and push提交到远程develop分支,然后A开发完成后从本地pull下远程develop分支,然后继续第二步的创建mirror操作。
        此外,在开发大型项目时,也可以采用一套更加规范的git flow,参考这两个wiki:git flowgit flow实践

 主要参考:

      Pro Git

      GitQuickStart

      GitWorkflow

      

转载于:https://my.oschina.net/zouqun/blog/405892

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值