天天看点

新手入门系列-git实例引导

1. 说明

  • 从原理到实际
  • 从场景出发
  • 先本地
  • 在远程

1.1 概念/原理

  1. git 关心的是“文件快照”,而非“差异比较”。SVN等关心的是“差异”。简单理解就是,git每次提交都是完整文件的保存。不会比较同一文件在这次提交有什么变化。
  2. git 大多数的操作都在“本地”
  3. git 每次commit都是在移动

    HEAD

    HEAD

    相当于指针,指向某次提交
  4. 每个文件都会有三种状态:

    未追踪

    暂存

    已入库

  5. git 所有命令都是围绕文件的状态,与仓库的状态来工作
  6. git 三个地方,对应文件三种状态。
    1. Workspace:

      工作区

      ,代码目录。包含了所有状态的文件
    2. Index / Stage:

      暂存区

      ,git add了但没有提交的文件
    3. Repository:

      本地仓库

      ,git commit入库后的存储
    4. Remote:

      远程仓库

新手入门系列-git实例引导

2. 本地代码一般操作

2.1 本地代码库初始化

  • 进入本地代码根目录执行,系统会默认创建"master"分支
    //假设代码目录有文件不需要这一步
    $touch 1.txt
    //初始化git环境
    $git init
               
  • 添加本地文件到仓库并提交(两个命令)。两个&的含义是,前面一个命令执行出错,后面的就不会执行。注意: -m 表示本次提交的说明。一定要有
  • 查看分支,master已经出现并作为默认分支
    $git branch
    * master
               

2.2 创建与查看本地分支,*号代表当前代码所在分支

  • 从master作为“父分支”创建本地分支dev。注意继承关系。从哪个分支创建子分支,代码就从哪个分支继承
    $git branch dev
               
  • 切换到本地分支dev
    $git checkout dev
               
  • 查看本地分支(因为checkout到dev了,所以*号在dev分支上
    $git branch
    * dev
    master
               

2.3 修改代码并提交到本地分支“dev”

  • 写入"123"到a.txt,如果a.txt不存在系统会创建
    $echo "123" > a.txt
               
  • 执行status命令,查看代码状态。可以看到提示“要把文件加入仓库追踪”
    $git status
    On branch dev
    Untracked files:
    (use "git add <file>..." to include in what will be committed)
      a.txt
    nothing added to commit but untracked files present (use "git add" to track)
               
  • 根据提示把文件加入追踪并提交到本地
  • 再次执行status,提示工作区是干净的
    $git status
    On branch dev
    nothing to commit, working directory clean
               

2.4 代码修改完毕后,合并到master分支

通过2.3我们改变了dev,改动完毕,这时候要合并代码到master。但在合并到master之前需要先更新master代码到dev。

目前通行且最佳的方案是采用rebase方案。rebase方案与merge的优劣我们不在这里讨论,请自行搜索。

简单理解就是:rebase使得提交路线更加清晰,而merge会因为“分支”过多,合并过多导致提交路线杂乱追踪起来比较难。但rebase会丢失很多提交细节,也不是完美合并。
  1. 总之:非常难单一的使用哪个就能解决所有问题!
  2. 先统一名称:上游、下游
  3. 如果

    dev

    是从

    master

    创建出来的分支。那么,master就是dev的

    上游

    ,dev就是master的

    下游

  4. 下游合并上游,要尽可能的保持提交路径简洁,那么采用"Rebase"
  5. 上游合并下游代码,要尽可能的保持提交细节,那么采用"merge"

想了解更多帮助理解,参考两篇文章

  • 动画图解 Git 命令
  • GIT使用rebase和merge的正确姿势

2.4.1 实际例子

  1. dev是从master创建的分支
    $git branch dev
    $git checkout dev
               
  2. dev开发一段时间后,master已经被其它同事修改了一些内容。dev本身也做了一些提交。这时,需要更新master代码才能做dev的测试。这时候就是:“下游合并上游”。那么采用

    rebase

    $git rebase master
               
  3. dev开发完毕了,这时候需要合并到master。这时候就是:“上游合并下游”。那么采用

    merge

    $git checkout master
    $git merge dev
               

3. 将现有代码纳入管理

3.1 本地代码从未纳入过仓库,仓库也是空的

这种最简单,按照如下执行即可

  1. 设置邮箱,用户名
    $git config --global user.name "smokelee"
    $git config --global user.email "[email protected]"
               
  2. 进入代码的根目录
    //初始化本地代码仓库
    $git init 
    //将远程仓库主机命名为"origin",并与本地的master建立追踪关系
    //origin 是远程主机`本地别名`,名字可以自定义的,不会影响到远端
    $git remote add origin ssh://gi[email protected]:10022/lihao/gitlearn.git  
    //把本地代码加入到代码追踪
    $git add .
    //把本地代码提交到本地仓库
    $git commit -m "Initial commit"
    //推送本地代码到远端主机“origin”的"master"
    //git push <远程主机名> <本地分支名>:<远程分支名>
    //远程分支被省略,如上则表示将本地分支推送到与之存在追踪关系的远程分支。一般本地与
    //远程分支会同名
    $git push -u origin master
               

    git push -u

    这个要注意,第一次提交时采用了

    -u

    ,含义是同时设置本地分支“master”与远端的"origin/master",建立追踪关系。那么以后再

    push

    代码时,直接使用

    git push

    就可以了。

3.2 本地代码,某个提交错了,向撤回提交

用git reset 命令实现回退,但怎么回退是个学问。
  1. 直接扔掉回退间的代码是一种(Hard)
  2. 回退但保留指定回退间产生代码是一种(Soft)
  3. 本质是移动git的HEAD指向

3.2.1 先来硬的

何为硬?不管

暂存区

有没有追踪但未提交的文件,不管上次提交改了什么,通通丢弃。对!就是你理解的丢掉。
  1. 想撤回

    本次提交的上1个提交
    $git reset --hard HEAD^
               
  2. 想撤回

    本次提交的上N个提交
    $git reset --hard HEAD~N
               
  3. 撤回

    某个提交
    $git reset --hard 98abc5a
               
  4. 误操作怎么办?reflog(30天内)
    $git reflog
    b7057a9 HEAD@{0}: reset: moving to b7057a9
    98abc5a HEAD@{1}: commit: more stuff added to foo
               

    98abc5a

    就是被

    掉的提交。
    git reset --hard 98abc5a
               
    再次git log查看。丢掉的内容回来了!
    $git log 
    98abc5a (HEAD, master) more stuff added to foo
               

3.2.2 再来软的

何为软?与硬不同的是,软只回退提交,但中间产生的文件不丢弃!

操作与hard一致,不做更多说明

4. 连接远程

4.1 从远程下载代码,注意:只会下载

master

代码

git clone ssh://xxxxxx/xxxx/prj.git
           

4.2 下载后切换到分支

  1. 查看所有分支
    $git branch -a 
    master
    remotes/origin/HEAD -> origin/master
    remotes/origin/dev
    remotes/origin/master
               
  2. 切换到

    dev

    分支,并建立

    远程分支

    本地分支

    关联
    $git checkout -b dev origin/dev
               
  3. 更新远程分支到本地
    $git pull --rebase
               
    如果没有走1、2两步,不要用3。其它后面会讲

4.3 本地建立分支,修改,并提交"远程分支"

前提条件

dev

已经与远程

origin/dev

建立关联。请看4.2

  1. dev

    上建立feature分支并修改
    $git branch feature<jira编号>-smokelee-20200423
    $git checkout feature<jira编号>-smokelee-20200423
    $touch newfeature.java 
    $git add . && git commit -m "add feature"
               
  2. 该下班了,还没改完,提交到远程服务器(小变化无需上传)
    $git push origin feature<jira编号>-smokelee-20200423
               
  3. 第二天修改完了,合并到

    dev

    。先更新

    dev

    $git checkout dev
    $git pull --rebase
               
  4. 合并feature到dev
    $git merge f1
    $git push
               
  5. 合并成功,没有问题。删除远程分支
    $git checkout feature<jira编号>-smokelee-20200423
    $git push origin :feature<jira编号>-smokelee-20200423
               

注意5中的第二条命令冒号前是空的,复习:git push <远程主机名> <本地分支名>:<远程分支名> 本地分支名不设置,就表示删除远程分支

4.4 干拉一个分支到本地

不从任何

本地分支

建立

feature

分支。并且不建立

本地

远程

分支关联。

要建立关联也简单,git pull后设置

git branch --set-upstream-to=origin/dev feaure-xxx-xxxx

这里纯粹在演示完整用法,就是字打的多点

  1. git pull origin <远程分支名>:<本地分支名>
    $git pull origin master:feaure-xxx-xxxx
    //关联远程与本地分支
    $git branch --set-upstream-to=origin/dev feaure-xxx-xxxx
    $git checkout feaure-xxx-xxxx
               
  2. 修改

    feaure-xxx-xxxx

    并提交
    $touch f1.java
    $git add . && git commit -m "dev1"
               
  3. 修改代码测试完毕准备提交到

    远程分支

    $git pull origin dev:feaure-xxx-xxxx --rebase
    $git push origin feaure-xxx-xxxx.local:dev
               
    在关联了

    远程

    本地

    分支情况下语句简单多了。
    $git pull --reabase
    $git push