git实操和理论知识

一、git工作流程

1、工作区、暂存区、版本库

1)有红色信息(工作区有内容),就执行 add 
2)全绿信息(内容全部在暂存区),才执行 commit
3)只有被版本库控制的代码,才能被监听,所以可以回滚到任何一个版本

2、设置用户

一个仓库有局部用户,优先使用局部用户,没有配置再找全局用户

# 全局用户
>: git config --global user.name '用户名'
>: git config --global user.email '用户邮箱'

注:在全局文件 C:\Users\用户文件夹\.gitconfig新建用户信息,在所有仓库下都可以使用

# 局部用户
>: git config user.name '用户名'
	-- 用户名
>: git config user.email '用户邮箱'
	-- 用户邮箱

补充:

1 在当前仓库下的config新建用户信息,只能在当前仓库下使用

2 当使用ssh 的公钥进行登录时,不需要输入用户名和密码,默认使用mac的用户名,可以进行指定gitee或gitlab的账号和邮箱

 cat ~/.gitconfig
...
[user]
        name = jingzhiz
        email = Z57s40@@

3 windos制作ssh公钥

安装git之后,点开 Git Bash Here ,自带了ssh-keygen命令

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

生成的SSH私钥路径 C盘/Users/chenjs/.ssh/id_rsa

3、常用操作

初始化一个仓库

git init 或者 git init name

查看当前仓库状态(注意颜色)

git status 

- 红色:仓库中新增了,或修改、删除某些文件,还没有提交到暂存区

- 绿色:在暂存区有变化,还没有提交到版本库

 

把当前所有变更都提交到暂存区

git add .

把暂存区所有内容,提交到版本库,被版本管理起来,以后可以回退,查看

git commit -m '注释' 

查看版本记录

git log  显示当前分支的提交历史,以 commit 为单位。 

git reflog  显示引用(包括分支、HEAD 等)的变化历史,以引用的操作为单位。

git reflog 是一个非常有用的命令,特别是当你需要回滚到之前的某个状态或者找回误删除的分支时,它可以帮助你追踪引用的变化。

git checkout .  # 把工作区变更删除

git reset HEAD   # 把暂存区,拉回到工作区

git reset --soft 23e9e095 # 版本号是上一个版本,把版本库内容拉回到暂存区

git reset --mix b23875 # 把版本库内容拉回到工作区,变红

远程仓库回滚(慎重)

git reset --hard e5fff5fe48

只要被版本管理了(一定能要提交到版本库),以后无论如何操作,都能再退回到某个位置

强制推送到远端

git push origin master # 本地与远端存在较大的差异,推送失败
    
git push origin master -f 

git submodule用法

项目很大很复杂的时候,需要将各个模块文件进行抽离,以此来降低项目文件之间的耦合程度

# 克隆 find-system
git clone git@git.mi.ai:fingeem/fingeem.git

# 初始化子模块
git submodule update --init fingeeration

远程仓库操作(复制要上传的代码库地址)

"""
1)查看仓库已配置的远程源
>: git remote
>: git remote -v

2)查看remote命令帮助文档
>: git remote -h

3)删除远程源
>: git remote remove 源名
eg: git remote remove origin

4)添加远程源
>: git remote add 源名 源地址
>: git remote add orgin git@gitee.com:doctor_owen/luffyapi.git

5)提交代码到远程源
>: git push 源码 分支名

6)克隆远程源
>: git clone 远程源地址
"""

"""
1)通过克隆方式连接远程源,默认远程源名就叫origin;所以主动添加远程源来连接远程仓库,源码也用origin
2)本地一个仓库只需要和远程一个源进行同步,所以只需要连接一个远程源,如果还想把本地代码同步给第三个平台,那么可以通过主动添加远程源来连接第三个平台的远程仓库,此时的源码就不能再叫origin了,比如online都可以
3)pull和push都可以提供选择不同的源码,和不同的远程仓库交互
"""

更新仓库代码到本地git pull、git pull --rebase

git pull = git fetch + git merge FETCH_HEAD
git pull --rebase = git fetch + git rebase FETCH_HEAD 

git pull --rebase
git pull --rebase --autostash
git pull --rebase  --autostash -v
git pull --rebase -v

以下命令会强制覆盖本地的代码

git fetch --all && git reset --hard origin/master && git pull

拉取远程仓库所有的最新分支(gitlab页面创建分支,本地看不到)

git fetch --all 
Fetching origin
Username for 'http://192.168.40.132:9980': root
Password for 'http://root@192.168.40.132:9980': 
From http://192.168.40.132:9980/root/k8s-ansible1
 * [new branch]      openstack  -> origin/openstack

git branch -a
* master
  ops
  remotes/origin/master
  remotes/origin/openstack
  remotes/origin/ops

查看分支提交树

git log --graph --pretty=oneline --abbrev-commit  

分支操作

"""
1.创建分支
>: git branch 分支名

2.查看分支
>: git branch

3.切换分支
>: git checkout 分支名

4.创建并切换到分支
>: git checkout -b 分支名

5.删除分支
>: git branch -d 分支名

6.查看远程分支
>: git branch -a

7.合并分支
>: git merge 分支名
把dev分支合并到master分支:切换到master分支,执行合并dev分支的命令
"""

4、忽略文件.gitignore

# 如果一个文件夹被git管理了,所有文件都会被管理,所有文件发生变化,都会变红
# 在一个文件夹中,可能有些文件,或文件不想被git管理,这时候需要设置过滤文件

# 使用方式
	-1 在仓库目录下(其它目录下不要有),新建一个文件:.gitignore
    -2 在里面写忽略文件或文件夹
    	""" 过滤文件内容
        文件或文件夹名:代表所有目录下的同名文件或文件夹都被过滤
        /文件或文件夹名:代表仓库根目录下的文件或文件夹被过滤

        eg:
        a.txt:项目中所有a.txt文件和文件夹都会被过滤
        /a.txt:项目中只有根目录下a.txt文件和文件夹会被过滤
        /b/a.txt:项目中只有根目录下的b文件夹下的a.txt文件和文件夹会被过滤
        *x*:名字中有一个x的都会被过滤(*代表0~n个任意字符)
        空文件夹不会被提交,空包会被提交,包可以被提交(包中有一个init空文件)
        """
        
# 忽略文件,在一开始就要忽略,如果已经被版本管理了,再忽略就没用了

# 如果之前没管,已经提交了 删除---》提交到版本库---》再在忽略文件中加入 # 咱们项目的忽略文件 .idea logs/*.log scripts __pycache__ *.pyc # 记住:迁移记录文件是否提交---》建议不提交 **/migrations/*.py # 忽略迁移记录 !**/migrations/__init__.py #不不忽略 __init__.py  

二、两种本地与远程仓库同步

1、两种情况

"""
1)你作为项目仓库初始化人员:
线上要创建空仓库 => 本地初始化好仓库 => 建立remote链接(remote add) => 提交本地仓库到远程(push)

2)你作为项目后期开发人员:
远程项目仓库已经创建成功 => 复制远程仓库到本地(clone) => 进入仓库就可以进行接下来的开发
"""

2、更新代码本地到仓库两种方式

方法一

$ git fetch origin master //从远程的origin仓库的master分支下载代码到本地的origin master
 
$ git  log -p master   origin/master//比较本地的仓库和远程参考的区别
 
$ git merge origin/master//把远程下载下来的代码合并到本地仓库,远程的和本地的合并

方法二

$ git fetch origin master:temp //从远程的origin仓库的master分支下载到本地并新建一个分支temp
 
$ git diff temp//比较master分支和temp分支的不同
 
$ git merge temp//合并temp分支到master分支
 
$ git branch -d temp//删除temp

三、理论

Git的相关理论基础

  • Git的四大工作区域
  • Git的工作流程
  • Git文件的四种状态
  • 一张图解释Git的工作原理

Git的四大工作区域

  • Workspace工作区:你电脑本地看到的文件和目录,在Git的版本控制下,构成了工作区。
  • Index/Stage暂存区:一般存放在 .git目录下,即.git/index,它又叫待提交更新区,用于临时存放你未提交的改动。比如,你执行git add,这些改动就添加到这个区域啦。
  • Repository本地仓库:你执行git clone 地址,就是把远程仓库克隆到本地仓库。它是一个存放在本地的版本库,其中HEAD指向最新放入仓库的版本。当你执行git commit,文件改动就到本地仓库来了~
  • Remote远程仓库:就是类似github,码云等网站所提供的仓库,可以理解为远程数据交换的仓库~

Git的工作流程

 git 的正向工作流程一般就这样:

  • 从远程仓库拉取文件代码回来;
  • 在工作目录,增删改查文件;
  • 把改动的文件放入暂存区;
  • 将暂存区的文件提交本地仓库;
  • 将本地仓库的文件推送到远程仓库;

Git文件的四种状态

根据一个文件是否已加入版本控制,可以把文件状态分为:Tracked(已跟踪)和Untracked(未跟踪),而tracked(已跟踪)又包括三种工作状态:Unmodified,Modified,Staged

  • Untracked: 文件还没有加入到git库,还没参与版本控制,即未跟踪状态。这时候的文件,通过git add 状态,可以变为Staged状态
  • Unmodified:文件已经加入git库, 但是呢,还没修改, 就是说版本库中的文件快照内容与文件夹中还完全一致。Unmodified的文件如果被修改, 就会变为Modified. 如果使用git remove移出版本库, 则成为Untracked文件。
  • Modified:文件被修改了,就进入modified状态啦,文件这个状态通过stage命令可以进入staged状态
  • staged:暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodified状态.

一张图解释Git的工作原理

日常开发中,Git的基本常用命令

这个图只是模拟一下git基本命令使用的大概流程

git clone 是克隆远程版本库到本地呢

 git checkout -b dev

克隆完之后呢,开发新需求的话,我们需要新建一个开发分支,比如新建开发分支dev。创建分支:

git checkout -b dev   创建开发分支dev,并切换到该分支下

 git add

git add .	添加当前目录的所有文件到暂存区
git add [dir]	添加指定目录到暂存区,包括子目录
git add [file1]	添加指定文件到暂存区

 有了开发分支dev之后,我们就可以开始开发啦,假设我们开发完HelloWorld.java,可以把它加到暂存区,命令如下

git add Hello.java  把HelloWorld.java文件添加到暂存区去

 git commit

git commit -m [message] 提交暂存区到仓库区,message为说明信息
git commit [file1] -m [message] 提交暂存区的指定文件到本地仓库
git commit --amend -m [message] 使用一次新的commit,替代上一次提交

把HelloWorld.java文件加到暂存区后,我们接着可以提交到本地仓库啦~

git commit -m 'helloworld开发'

git status

git status,表示查看工作区状态,使用命令格式:

git status  查看当前工作区暂存区变动
git status -s  查看当前工作区暂存区变动,概要信息
git status  --show-stash 查询工作区中是否有stash(暂存的文件)

 当你忘记是否已把代码文件添加到暂存区或者是否提交到本地仓库,都可以用git status看看哦~

git log

git log,这个命令用得应该比较多,表示查看提交历史/提交日志~

git  log  查看提交历史
git  log --oneline 以精简模式显示查看提交历史
git  log -p <file> 查看指定文件的提交历史
git  blame <file> 一列表方式查看指定文件的提交历史

看看dev分支上的提交历史吧~要回滚代码就经常用它喵喵提交历史~

git diff

git diff 显示暂存区和工作区的差异
git diff filepath   filepath路径文件中,工作区与暂存区的比较差异
git diff HEAD filepath 工作区与HEAD ( 当前工作分支)的比较差异
git diff branchName filepath 当前分支的文件与branchName分支的文件的比较差异
git diff commitId filepath 与某一次提交的比较差异

git pull/git fetch

git pull  拉取远程仓库所有分支更新并合并到本地分支。
git pull origin master 将远程master分支合并到当前本地分支
git pull origin master:master 将远程master分支合并到当前本地master分支,冒号后面表示本地分支

git fetch --all  拉取所有远端的最新代码
git fetch origin master 拉取远程最新master分支代码

 我们一般都会用git pull拉取最新代码看看的,解决一下冲突,再推送代码到远程仓库的。

 git pull = git fetch+ git merge。pull的话,拉取远程分支并与本地分支合并,fetch只是拉远程分支,怎么合并,可以自己再做选择。

git push

git push 可以推送本地分支、标签到远程仓库,也可以删除远程分支哦。

git push origin master 将本地分支的更新全部推送到远程仓库master分支。
git push origin -d <branchname>   删除远程branchname分支
git push --tags 推送所有标签

 如果我们在dev开发完,或者就想把文件推送到远程仓库,给别的伙伴看看,就可以使用git push origin dev~

Git进阶之分支处理

Git一般都是存在多个分支的,开发分支,回归测试分支以及主干分支等,所以Git分支处理的命令也需要很熟悉的呀~

  • git branch
  • git checkout
  • git merge

git branch

git branch用处多多呢,比如新建分支、查看分支、删除分支等等

新建分支:

git checkout -b dev2  新建一个分支,并且切换到新的分支dev2
git branch dev2 新建一个分支,但是仍停留在原来分支

 查看分支:

git branch    查看本地所有的分支
git branch -r  查看所有远程的分支
git branch -a  查看所有远程分支和本地分支

 删除分支:

git branch -D <branchname>  删除本地branchname分支

git branch -d -r branchname   删除远程branchname分支

git checkout

切换分支:

git checkout master 切换到master分支

git branch -m  old new / git branch -M old new

重命名分支,如果newbranch名字分支已经存在,则需要使用-M强制重命名,否则,使用-m进行重命名。

git merge

我们在开发分支dev开发、测试完成在发布之前,我们一般需要把开发分支dev代码合并到master,所以git merge也是程序员必备的一个命令。

git merge master  在当前分支上合并master分支过来
git merge --no-ff origin/dev  在当前分支上合并远程分支dev
git merge --abort 终止本次merge,并回到merge前的状态

 比如,你开发完需求后,发版需要把代码合到主干master分支,如下:

Git进阶之处理冲突

Git版本控制,是多个人一起搞的,多个分支并存的,这就难免会有冲突出现~

Git合并分支,冲突出现

同一个文件,在合并分支的时候,如果同一行被多个分支或者不同人都修改了,合并的时候就会出现冲突。

举个粟子吧,我们现在在dev分支,修改HelloWorld.java文件,假设修改了第三行,并且commit提交到本地仓库,修改内容如下:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello,捡田螺的小男孩!");
    }
}

 我们切回到master分支,也修改HelloWorld.java同一位置内容,如下:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello,jay!!");
    }
}

 再然后呢,我们提交一下master分支的这个改动,并把dev分支合并过下,就出现冲突啦,如图所示:

Git解决冲突

Git 解决冲突步骤如下:

  • 查看冲突文件内容
  • 确定冲突内容保留哪些部分,修改文件
  • 重新提交,done

1.查看冲突文件内容

git merge提示冲突后,我们切换到对应文件,看看冲突内容哈,,如下:

2.确定冲突内容保留哪些部分,修改文件

  • Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,
  • <<<<<<<HEAD是指主分支修改的内容,>>>>>>> dev是指dev分支上修改的内容

所以呢,我们确定到底保留哪个分支内容,还是两个分支内容都保留呢,然后再去修改文件冲突内容~

3.修改完冲突文件内容,我们重新提交,冲突done

Git进阶之撤销与回退

Git的撤销与回退,在日常工作中使用的比较频繁。比如我们想将某个修改后的文件撤销到上一个版本,或者想撤销某次多余的提交,都要用到git的撤销和回退操作。

代码在Git的每个工作区域都是用哪些命令撤销或者回退的呢,如下图所示:

有关于Git的撤销与回退,一般就以下几个核心命令

  • git checkout
  • git reset
  • git revert

git checkout

如果文件还在工作区,还没添加到暂存区,可以使用git checkout撤销

git checkout [file]  丢弃某个文件file
git checkout .  丢弃所有文件

 以下demo,使用git checkout -- test.txt 撤销了test.txt的修改

git reset

git reset的理解

git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本.

为了更好地理解git reset,我们来回顾一下,Git的版本管理及HEAD的理解

Git的所有提交,会连成一条时间轴线,这就是分支。如果当前分支是master,HEAD指针一般指向当前分支,如下:

 假设执行git reset,回退到版本二之后,版本三不见了哦,如下:

git reset的使用

Git Reset的几种使用模式

git reset HEAD --file
回退暂存区里的某个文件,回退到当前版本工作区状态
git reset –-soft 目标版本号 可以把版本库上的提交回退到暂存区,修改记录保留
git reset –-mixed 目标版本号 可以把版本库上的提交回退到工作区,修改记录保留
git reset –-hard  可以把版本库上的提交彻底回退,修改的记录全部revert。

 先看一个粟子demo吧,代码git add到暂存区,并未commit提交,可以酱紫回退,如下:

git reset HEAD file 取消暂存
git checkout file 撤销修改

 

再看另外一个粟子吧,代码已经git commit了,但是还没有push:

git log  获取到想要回退的commit_id
git reset --hard commit_id  想回到过去,回到过去的commit_id

 

 如果代码已经push到远程仓库了呢,也可以使用reset回滚哦(这里大家可以自己操作实践一下哦)~

git log
git reset --hard commit_id
git push origin HEAD --force

git revert

与git reset不同的是,revert复制了那个想要回退到的历史版本,将它加在当前分支的最前端。

revert之前:

revert 之后:

当然,如果代码已经推送到远程的话,还可以考虑revert回滚呢

git log  得到你需要回退一次提交的commit id
git revert -n <commit_id>  撤销指定的版本,撤销也会作为一次提交进行保存

 

Git进阶之标签tag

打tag就是对发布的版本标注一个版本号,如果版本发布有问题,就把该版本拉取出来,修复bug,再合回去。

git tag  列出所有tag
git tag [tag] 新建一个tag在当前commit
git tag [tag] [commit] 新建一个tag在指定commit
git tag -d [tag] 删除本地tag
git push origin [tag] 推送tag到远程
git show [tag] 查看tag
git checkout -b [branch] [tag] 新建一个分支,指向某个tag

 

Git其他一些经典命令

git rebase(变基)

rebase又称为衍合,是合并的另外一种选择。

构造两个分支master和feature,其中feature是在提交点B处从master上拉出的分支

master上有一个新提交M,feature上有两个新提交C和D

此时切换到feature分支上,执行rebase命令,相当于是想要把master分支合并到feature分支(这一步的场景就可以类比为我们在自己的分支feature上开发了一段时间了,准备从主干master上拉一下最新改动。模拟了git pull --rebase的情形)

下图为变基后的提交节点图

结合例子解释:

  当在feature分支上执行git rebase master时,git会从master和featuer的共同祖先B开始提取feature分支上的修改,也就是C和D两个提交,先提取到。然后将feature分支指向master分支的最新提交上,也就是M。

最后把提取的C和D接到M后面,注意这里的接法,官方没说清楚,实际是会依次拿M和C、D内容分别比较,处理冲突后生成新的C’和D’。一定注意,这里新C’、D’和之前的C、D已经不一样了,是我们处理冲突后的新内容,feature指针自然最后也是指向D’

通俗解释(重要!!):rebase,变基,可以直接理解为改变基底。feature分支是基于master分支的B拉出来的分支,feature的基底是B。而master在B之后有新的提交,就相当于此时要用master上新的提交来作为feature分支的新基底。

实际操作为把B之后feature的提交先暂存下来,然后删掉原来这些提交,再找到master的最新提交位置,把存下来的提交再接上去(接上去是逐个和新基底处理冲突的过程),如此feature分支的基底就相当于变成了M而不是原来的B了。

(注意,如果master上在B以后没有新提交,那么就还是用原来的B作为基,rebase操作相当于无效,此时和git merge就基本没区别了,差异只在于git merge会多一条记录Merge操作的提交记录)

上面的例子可抽象为如下实际工作场景:

  远程库上有一个master分支目前开发到B了,张三从B拉了代码到本地的feature分支进行开发,目前提交了两次,开发到D了;李四也从B拉到本地的master分支,他提交到了M,然后合到远程库的master上了。此时张三想从远程库master拉下最新代码,于是他在feature分支上执行了git pull origin master:feature --rebase(注意要加–rebase参数),即把远程库master分支给rebase下来,由于李四更早开发完,此时远程master上是李四的最新内容,rebase后再看张三的历史提交记录,就相当于是张三是基于李四的最新提交M进行的开发了。(但实际上张三更早拉代码下来,李四拉的晚但提交早)

搞来搞去那么多,这其实是最重要的。不同公司,不同情况有不同使用场景,不过大部分情况推荐如下:
  1. 拉公共分支最新代码——rebase,也就是git pull -r或git pull --rebase。这样的好处很明显,提交记录会比较简洁。但有个缺点就是rebase以后我就不知道我的当前分支最早是从哪个分支拉出来的了,因为基底变了嘛,所以看个人需求了。总体来说,即使是单机也不建议使用。
  2. 往公共分支上合代码——merge。如果使用rebase,那么其他开发人员想看主分支的历史,就不是原来的历史了,历史已经被你篡改了。举个例子解释下,比如张三和李四从共同的节点拉出来开发,张三先开发完提交了两次然后merge上去了,李四后来开发完如果rebase上去(注意,李四需要切换到自己本地的主分支,假设先pull了张三的最新改动下来,然后执行<git rebase 李四的开发分支>,然后再git push到远端),则李四的新提交变成了张三的新提交的新基底,本来李四的提交是最新的,结果最新的提交显示反而是张三的,就乱套了,以后有问题就不好追溯了。
  3. 正因如此,大部分公司其实会禁用rebase,不管是拉代码还是push代码统一都使用merge,虽然会多出无意义的一条提交记录“Merge … to …”,但至少能清楚地知道主线上谁合了的代码以及他们合代码的时间先后顺序

git stash

stash命令可用于临时保存和恢复修改

git stash  把当前的工作隐藏起来 等以后恢复现场后继续工作
git stash list 显示保存的工作进度列表
git stash pop stash@{num} 恢复工作进度到工作区
git stash show :显示做了哪些改动
git stash drop stash@{num} :删除一条保存的工作进度
git stash clear 删除所有缓存的stash。

 

git reflog

显示当前分支的最近几次提交

git blame filepath

git blame 记录了某个文件的更改历史和更改人,可以查看背锅人

 

 

 

Git Merge和Rebase的区别。包括作用,效果和使用场景。全b站最清楚的讲解!不是的话当我没说。_哔哩哔哩_bilibili

SourceTree 提交代码以及合并 (py3study.com) git图形化操作工具

Git for Windows   gitbash工具可以用unix的操作方式来操作windos,工具不错

https://www.cnblogs.com/fisherbook/p/11397168.html  

SourceTree安装与使用(https://www.sourcetreeapp.com/  中文版下载地址)

https://mp.weixin.qq.com/s/giciJzRMmyzOCvJcrOWCnQ

https://www.liuname.xyz/archives/915/

https://www.cnblogs.com/iruxu/p/gitgui.html   git的windos ui工具

https://gitee.com/all-about-git  git大全,内容涵盖齐全

posted @ 2020-06-30 16:29  凡人半睁眼  阅读(438)  评论(0编辑  收藏  举报