GIT

  2020-5-31 


系统性地整理一次GIT

Git结构

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,必须联网

Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库。只需把各自的修改推送给对方,就可以互相看到对方的修改了。

GIT架构:git

remote:远程仓库;repository:本地仓库;index:暂存区

当你在一个工程文件的目录下git init的时候,就会在该工程目录下创建.git文件夹,这个.git文件夹里包含暂存区、本地仓库,然后就可以在该工程目录下使用addpushpull等指令对该工程目录进行git操作。(可以写个gitignore来指定哪些不git)

所以每个需要git(分布式版本控制)的项目都可以在其工程目录下新建git仓库

Git 身份认证

本地仓库连接远程仓库进行PUSH等操作之前,需要认证身份,有两种方式:SSH协议HTTPS协议

SSH协议认机器(通过ssh key公私秘钥认证),HTTPS协议认账号(通过账号密码登陆远程仓库来认证)

SSH KEY方式

  1. 使用ssh方式添加远程仓库:

    # 第一次新建项目后指定本地代码关联的远程仓库地址
    git remote add origin git@github.com/aisakaki/aisakaki.github.io.git

    所有的git仓库都默认使用global的ssh key,存放于home目录下的.ssh文件夹

    ssh key配置一对秘钥(本地私钥,远程仓库如github放私钥),这样就本地和远程就能验证身份,通过身份认证就可以进行push pull等各种远程操作

  2. 生成ssh key(默认生成ssh-key到home/.ssh目录下):

    #用ssh-keygen来生成公私钥,后面指点非对称加密算法和署名
    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    #可以在后面添加参数如-f C:\Users\htt20\.ssh\test\new-rsa来指定生成秘钥储存在哪个文件
    #不指定就默认用户目录下的.ssh文件夹下,如果自命名又不指定路径就储存在用户根目录下
    
    #若未用-f指定enter后,可以自己命名储存秘钥文件的名字
    Generating public/private rsa key pair.   #<-到这里稍等一下,别急着回车
    Enter file in which to save the key (C:\Users\htt20/.ssh/id_rsa): newName-rsa  #<-这就指定新公私钥储存的名字

    会生成公钥id-rsa.pub私钥id-rsa,然后将公钥存放在github远程仓库配置中即可

    【多ssh key怎么配置】:即“同一台主机多个git账户”,就需要

    ①生成多个ssh key ,②然后配置 ~/.ssh/config~/.gitconfig来管理③使用局部邮箱用户名配置

    依然是用上面ssh key生成方法,不过注意新生成ssh key不能重名(要么-f指定新生成在哪,要么自己改名

    修改~/.ssh/config~/.gitconfig文件

    #~.gitconfig文件内容、
    #-----------------------------------------------------------------------#
    #git account1
    Host   github.com
           HostName github.com
           IdentityFile ~/.ssh/home_rsa
    
    #git account2
    Host    github.com
            HostName github.com
            IdentityFile ~/.ssh/lab_rsa

    私钥位置记录在config中,公钥都记录在远程仓库配置中。写了配置,多ssh key就可以生效了。

    具体不同的git使用哪个ssh,是在添加远程仓库语句:git remote add origin git@github.com/aisakaki/aisakaki.github.io.git中绑定的。

    如果配置过global邮箱和用户名,就必须先取消

    # 取消全局邮箱和账户名配置
    git config --global --unset user.name
    git config --global --unset user.email
    
    # 在每个项目目录,新建仓库的时候,单独使用局部配置,不指定global参数
    git init
    git config user.name "aisaka_home" 
    git config user.email aisaka_home@gmail.com
  3. ssh key和depoly key的区别ssh keys拥有最高权限,可以管理所有仓库(项目);depoly key是这个仓库的专有key,只能操作这个项目

    一样在本地创建公私钥,然后ssh key的话是将公钥添加在github账号设置里,而depoly key是添加在项目仓库的设置里

HTTPS方式

使用https方式添加远程仓库:

#和ssh方式区别在于后面url不同
git remote add origin  https://github.com/aisakaki/aisakaki.github.io.git

连接远程仓库的时候,输入账号和密码登陆远程仓库(就是github的账号密码),省去了本地配置的麻烦,只要有URL和相应的权限便能进行相应的操作。但每次连接都要输入账号密码

可以参考git http/https方式储存密码来记住账户密码

windows有GUI的git,如果使用HTTP方式会记住并自动输入github的账号密码进行认证

HTTPS方式只能public

GIT配置&操作流程步骤(SSH方式)

HTTPS方式就不需要配置SSH KEY,并且制定远程仓库的url的协议标识修改一下

  1. 配置ssh key

    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

    单ssh key情况,多情况需要建立多个并写config

  2. 新建远程仓库配置ssh公钥

    github网页上进行

  3. 设置全局邮箱和用户名(如果需要)

    git config --global user.name "Your Name"
    git config --global user.email "email@example.com"
  4. 新建本地仓库

    ======从这里开始的操作就是在项目文件夹目录下进行操作了======

    #进入目标项目的文件夹
    git init
  5. 设置局部邮箱和用户名(如果需要,多ssh key情况)

    git config user.name "Your Name"
    git config user.email "email@example.com"
  6. clone项目到本地(如果需要。注意这里要先init,再clone)

    git clone https://github.com/aisakaki/aisakaki.github.io.git
  7. 添加远程仓库

    # 添加远程仓库
    git remote add origin git@github.com/aisakaki/aisakaki.github.io.git

    【origin】origin是一个名字,它是在你clone一个托管在Github上代码库时,git为你默认创建的指向这个远程代码库的标签。你也可以改名叫其它名字,比如aisakagit,都OK的,下面你用这个仓库的时候就用aisakagit你取的别名

    【这个origin就是远程仓库git@github.com/aisakaki/aisakaki.github.io.git的别名】

  8. 开始各种GIT操作

P.S. 邮箱和用户名

为什么git需要配置邮箱和用户名呢?因为远程仓库里需要记录提交记录是由来完成的,只是个署名,这里的邮箱和用户名并没有身份验证作用!。

git config --global user.name "Your Name"
git config --global user.email "email@example.com"

# (多ssh key情况不能带上global参数)

origin&master

远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义,原因仅仅是它的广泛使用。

origin 是当你运行 git clone 时默认的【远程仓库】名字。 如果你运行 git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master

master 是当你运行 git init 时默认的【起始分支】名字

所以master就是local branch(本地仓库默认分支),origin/master是remote branch(远程仓库默认分支)

默认分支即主分支

#eg,这里就用了默认仓库别名origin和默认主分支名master
git remote add origin 远程仓库url  #origin你改成其它的名字也是OK的,下面push的origin跟着改
git push -u origin master

P.S.后面<远程仓库别名(默认origin)>写得太累赘了,可以直接看作origin,因为一般都是取origin的

分支

分支是什么?分支就相当于是一个原来完整代码的一个副本,完全由你自己独占,修改当前分支不会影响另一个分支,就像一个平行宇宙一样(但git的分支实现方式并不是直接复制一份,而是版本组成一颗多叉树,见下)

默认分支是主分支master,主分支是init git 的时候就默认创建的。

分支有什么用?当你修改完后,可以选择将此分支再合并到原分支(这样一来就方便管理和修改,也避免了如果在原分支上修改,修改了一半push之后别人没法使用,因为代码没写完)

GIT分支实现原理git分支的理解

实际上,git的操作会构成一个版本链(每commit提交一次,就生成一个版本,会记录修改),分支实现的实质是指向版本链上的指针,默认分支master即是指向版本链上的master指针(见上文理解)那么在进行git操作的时候,版本链新增一个版本,然后当前分支下的分支指针后移,如果多个分支都被修改,那就会出现分叉了

【不同分支的版本链组成了一个多叉树,分支指针指向当前分支的最新版本】。分叉口即为分支修改出现不同的地方,如果仅仅是修改了一个分支,那是不会分叉出去的,原未被修改的分支还是指向原来新分支之前那个版本链位置,这时候的分支合并即为快速合并:直接将master指针指向当前分支指针位置如果两个分支都修改了,那么git就会尝试将各自的修改合并起来(合并两个版本),如果出现冲突,那就需要手动解决冲突

HEAD指针指向当前版本

GIT操作详解

重点记忆加粗命令

本地基本操作

  1. 暂存(add)

    git add file
    git add .
  2. 提交(commit)

    git commit
    
    # 注释换行,单引号开始结束
    git commit -m '
    > line1
    > line2
    > line3
    '

    可以多次向暂存区add,commit则是一次将暂存区所有内容提交到仓库

  3. 查看操作记录

    # 查看所有已提交的版本信息
    git log
    # commit后跟的就是commit-id
    # 还有其它相关信息比如日期、提交注释等
    
    # 可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作,结合下面reset指令可以撤销回退)
    git reflog
  4. 回退到某个版本

    可以回退到老版本(查log),也可以回退到新版本(查reflog)

    git reset --hard <commit-id>
  5. 查看文件状态(是否跟踪)

    跟踪指的是commit提交的时候会提交这些add的文件,实际上就是查看暂存区哪些文件被add了。和本地分支跟踪远程分支的跟踪不是一个意思

    git status
    
    # 被跟踪:tracked
    # 未被跟踪:untracked
    # 忽略:ignored,即.gitignore下的
  6. 撤销add

    git reset HEAD 撤销上一次add的所有文件 
    git reset HEAD file 撤销file
  7. 放弃修改

    放弃未暂存(add),未提交(commit)的修改

    # 放弃单个文件的修改
    git checkout filename
    
    # 放弃当前目录下的修改
    git checkout . 

分支操作

  1. 创建分支

    git branch newBranch
  2. 切换分支

    # 切换本地分支
    git checkout newBranch
  3. 查看分支

    # 本地
    git branch
    
    # 本地分支及追踪的远程分支
    # 所谓本地追踪的远程分支,就是push -u指定的本地分支对应远程分支的关系,或者创建并切换远程分支指定的
    git branch -vv
    
    # 远程
    git branch -r
    
    # 本地+远程
    git branch -a

    带星号的是当前所处分支

  4. 合并分支

    git merge newBranch

    git merge合并当前分支到master分支上

    如果master分支未修改,那么执行的是快速合并,见上分支一节

    如果两个分支都修改了,那么git将试图合并两个版本

    如果合并两个版本的时候发生冲突,就需要手动处理冲突

  5. 删除分支

    git branch -d newBranch
  6. 创建并切换分支(12合并写法)

    # 本地
    git checkout -b newBranch
    
    # 远程:将远程分支拉到本地的一个新分支
    git checkout -b newBranch 仓库别名(一般origin)/远程分支名
    # 经过这个命令之后,会形成本地分支-远程分支的追踪关系
  7. 重命名分支

    git branch -m oldName newName
  8. 查看本地分支与远程分支差异

    git diff --stat <localBranch> <远程仓库别名(默认origin)>/<remoteBranch>

远程操作

  1. 推送(push)

    # 将本地分支推送到远程 【-u表示默认,下一次推送就会默认使用后面的参数】
    git push -u <远程仓库别名(默认origin)> <本地分支名>:<远程分支名>
    # 经过这个命令之后,会形成本地分支-远程分支的追踪关系
    
    eg: git push -u origin master:master #这里本地和远程分支都是默认的master
    
    #【第一次push使用-u之后就建立了跟踪关系,以后再推送就只需要如下简写,就会默认采用之前的设置】
    git push
  2. 拉取并合并(pull)

    pull=fetch+merge

    git pull <远程仓库别名(默认origin)> <远程分支名>
  3. 拉取(fetch)(不合并)

    git fetch <远程仓库别名(默认origin)> <远程分支名>
  4. 重新设定远程仓库(仓库级别):

    # 当代码库远程迁移后,重新设定本地代码关联的远程地址
    git remote set-url origin git@github.com/aisakaki/aisakaki.github.io.git
  5. 添加远程地址(仓库级别)

    git remote add <远程仓库别名(默认origin)> <url(https方式 or ssh方式)>
  6. 删除本地指定的远程地址(仓库级别)

    git remote remove <远程仓库别名(默认origin)>
  7. 查看远程仓库信息

    # 列出远程分支
    git remote
    
    # 列出远程分支详细信息,在每一个名字后面列出其远程url
    git remote -v  
    
    # 更详细了。。
    git remote -vv
  8. GITHUB设置分支PUSH权限

    ① 管理员身份登录GitHub,找到项目
    ②Settings—>Branches—>Protected branches—->Choose a branch… ,选择需要保护的分支,然后点击edit按钮,
    ③Branch protection for 所选的分支名 —> 勾选Restrict who can push to this branch People and teams with push access
    若不选择任何人,则任何人都没有push代码到该分支的权限。

  9. 测试链接(git方式)

    测试本地的私钥能否与我账户中的公钥认证

    ssh -T git@github.com

常见GIT指令的选项参数

-d
--delete:删除
 
-D
--delete --force的快捷键
 
-f
--force:强制
 
-m
--move:移动或重命名
 
-M
--move --force的快捷键
 
-r
--remote:远程
 
-a
--all:所有

操作习惯

一般我们Git提交都不会直接提交主分支master,先提交到dev分支,没问题,再会合并到master分支。

可以写.gitignore来让git忽略某些文件

常见分支设定:

Production分支(主线分支用于发版,不会直接改)
Develop分支(开发分支)
Feature分支(新功能分支)
Release分支(偏向测试)
Hotfix分支(紧急bug发布)

底层原理【待更新】

暂存区实际上是索引,所以才说是跟踪

P.S. 有些打了<>有些忘打了不要在意细节


且听风吟