git笔记百宝箱

466 阅读20分钟

初始化仓库

// 进入到learngit目录并执行git init将learngit初始化为本地仓库
cd learngit
git init

远程仓库remote

1. 本地仓库关联远程仓库

如果是从远程仓库clone到本地的仓库,则不需要关联本地仓库和远程仓库

// 在本地仓库learngit目录下,执行git remote add origin git@github.com:/git.git;表示将远程仓库地址git@github.com:/git.git,关联到本地仓库。origin是给远程仓库地址取的别名,以后origin就代表远程仓库地址git@github.com:/git.git

git remote add origin git@github.com:/git.git

// 在learngit本地仓库中执行git remote -v,查看本地仓库关联的远程仓库
git remote -v

2. 克隆仓库


// 当你从远程仓库克隆时,实际上Git自动在本地分支和远程分支之间建立一种追踪关系,比如:在git clone的时候,所有本地分支默认与远程主机的同名分支之间建立追踪关系,也就是说,本地的master分支自动"追踪"origin/master分支。并且远程仓库的默认名称是origin
git clone git@github.com:/git.git

3. 修改远程仓库

// 方法1:重置远程仓库的地址
git remote set-url origin https://github.com/xx/git.git

// 方法2:先删除再重新添加再push
git remote remove origin
git remote add origin yourRemoteUrl
git push -u origin master

分支代码推送

推送本地分支到远程分支:git push系列

  • 方式1是git push <远程主机名也就是远程仓库地址> <本地分支名>:<远程分支名>

// 推送本地dev分支到远程的master分支 
git push origin dev:master

// 如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会被新建
// `git push origin master`	省略了远程分支名表示将本地的master分支推送到origin主机的master分支。如果远程master分支不存在,则会被新建
git push origin master


// 如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支
// `git push origin :master` 等同于 `git push origin --delete master`
// `git push origin :master` 表示删除远程origin地址下的master分支
git push origin :master


// 如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略
// 将当前分支推送到`origin`指定的远程仓库对应的分支
git push origin

// 如果当前分支只有一个追踪分支,那么主机名都可以省略。也就是当前的本地仓库下的本地分支只关联了一个远程仓库下的一个具有追踪关系的远程分支
git push


// 如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
// `git push -u origin master`: 表示将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
git push -u origin master

  • 方式2git push --set-upstream [远程主机名] [远程分支名] (前提是远程没有本地的分支)
// 新建并切换到本地dev
git checkout -b dev
// 推送dev分支此时出错
git push dev

// 出现错误提示:
fatal: The current branch zheer has no upstream branch.
To push the current branch and set the remote as upstream, use
 	git push --set-upstream zheer zheer

// git push --set-upstream  [远程主机名] [远程分支名]
// 在本地dev分支上执行下面命令表示推送本地dev到远程的dev分支
git push --set-upstream origin dev
  • 方式3
// 创建dev分支
git checkout -b dev

// 刚创建dev分支,还没写代码之前,可以直接执行下面的命令给远端也新建了dev分支并且和本地的dev分支是关联的.
git push -u origin dev

分支代码拉取之git pull

分支代码拉取使用:git pull 系列

  • git pull:取回远程主机某个分支的更新,再与本地的指定分支合并。
git pull
等价于
git fetch && git merge

/////////////
在master上执行git pull -r ,拉完master代码,并且变基到master上,这时候再 checkout -b到新分支,新分支就直接是以master为基点的
  • 语法git pull <远程主机名> <远程分支名>:<本地分支名>
// 表示取回`origin`远程地址下的`next`分支,与本地的`master`分支合并
git pull origin next:master

// 如果远程分支是与当前分支合并,则冒号后面的部分可以省略
// `git pull origin next`表示取回`origin/next分支`,再与当前分支合并
// git pull origin next 等价于 git fetch origin && git merge origin/next
git pull origin next


// 手动建立追踪关系
// `git branch --set-upstream master origin/next`表示:指定本地`master`分支追踪`origin/next`分支
git branch --set-upstream master origin/next

// 当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名
// `git pull origin` 表示:本地的当前分支自动与对应的origin主机"追踪分支"(remote-tracking branch)进行合并
git pull origin


// 如果当前分支只有一个追踪分支,连远程主机名都可以省略
// `git pull`: 表示拉取当前分支对应的远程分支,并和当前分支合并
git pull

分支代码拉取之git fetch

git fetch:一旦远程主机的版本库有了更新(Git术语叫做commit),需要将所有的远程分支最新的commit更新取回本地。会将远程最新的commit拿到本地在缓冲区放着,维护在.git/FETCH_HEAD文件中

缓冲区:本地有个缓冲区,里面放着跟远程仓库关联的分支,记录着分支的最新状态,git fetch会将远程分支的最新commit更新到这里;并不会影响本地仓库的commit。缓冲文件:.git/FETCH_HEAD

语法git fetch <远程主机名> <远程分支名>:<本地分支名>

// 将所有关联的远程仓库上的所有远程分支的最新commit更新到本地的`.git/FETCH_HEAD`文件中
git fetch 

// 将origin远程仓库的所有分支的最新commit更新到本地的`.git/FETCH_HEAD`文件中
git fetch origin

// 将origin远程仓库下的远程分支revision2的最新commit记录到本地的`.git/FETCH_HEAD`文件中
// 所取回的更新,在本地主机上要用"远程主机名/分支名"的形式读取。比如origin主机的revision2,就要用origin/revision2读取
git fetch origin revision2

// 在本地创建dev分支,并且将最新的远端分支revision2上所有数据放在本地dev分支上;
git fetch origin oringin/revision2:dev

分支代码拉取场景

1. 基于远程分支拉去新分支开发

// 方式1:
git checkout -b 本地分支名x origin/远程分支名x

git pull

// 方式2:
git checkout -b 本地分支名x
git branch --set-upstream-to=origin/远程分支名x 本地分支名x

git pull

// 执行完方式1或者2的其中一种之后,此时在本地分支x上,并且本地分支x已经关联远程分支x;再从本地分支x上拉新分支y
git checkout -b 本地分支y

rebase

1. rebase简介

2. rebase开发流程应用

git pull --rebase origin development //等价于下面两行
git fetch origin development
git rebase origin/development

一般我们在dev分支开发,开发完需要merge到master,大致流程如下:

1. 在dev分支写了代码,然后在从本地dev提交并push到远程dev上
2. 然后在本地dev分支上执行`git pull --rebase origin master`(这句表示拉取远程master的代码,并将dev分支的commit嫁接到master分支上)
3. 如果第2步rebase过程有冲突,解决冲突,解决完冲突使用`git add .`
4.3步add之后继续执行rebse操作 `git rebase --continue`(冲突不好解决可以使用`git rebase —abort`放弃这次rebase)
5. rebase完成后,还在dev分支上强制更新dev分支变基后的节点结构到远端的dev分支`git push -f`
6. 接着执行`git checkout master`切到本地master分支,执行`git merge dev`使得master和dev执行本地最新的变基后的统一节点
7. 在本地master上执行git push

// 如果没有冲突直接 12567

// 一般公司开发时,有的是不能直接操作master分支,需要提merge请求;这里备注当dev分支变基到master分支上时,dev分支是领先master分支的,这时候直接提merge请求(相当于把远端的dev分支merge到远端master分支;这时候是快速合并的形式,master和dev会指向同一节点。)
每次开发时,从master分支拉了新分支dev后,在本地dev开发,然后在本地commit之后,再在本地dev分支上执行`git pull --rebase origin master`,这样将本地dev分支的commit变基到最新的本地master上,最后dev分支的功能开发完成要推到远程dev分支时,可以将本地dev分支的多次commit合并成一次commit,然后再使用`git push -f`强制推送到远程dev分支,再在可视化界面提远程dev分支merge到远程master的merge请求

3. 变基冲突合并

当多人在同一个分支dev开发时,这时候如果有人,amend或者rebase,那么我们本地代码push的时候就会有大量的冲突;更好的解决办法如下:

1. 将自己工作区的代码存储到stash,然后在dev分支上执行`git pull`如果有冲突问题,则直接切换到master分支,删除dev分支,再新建切换到新的dev分支,再git pull,然后再将stash暂存区的代码pop到当前的dev分支,然后提交 push到远程dev分支。

4. rebase合并commit

目标:将本地3次commit合并成1次,也就是这里将C2、C3都合并到C1



// 备注4612a67这个版本不参与合并
git rebase -i 4612a67
// git rebase -i HEAD~3  这个效果和上面一样

上图:wq退出之后,下面这个图删除1-12行 就可以填新合并生成commit的commit message

注意发现这里合并后的commit不是之前C1的commit,而是新生成的合并后的commit

5. 修改已经提交的commit内容

可以直接git rebase -i xxx进入shell后将pick修改为r,然后:wq退出,就会再进入shell,这时候修改commit msg即可

eg:将 '修改UI样式' 文案 改成 'fix: 修改UI样式'

image.png

执行:git rebase -i 3ff896c4

merge

merge场景:将dev分支merge到master分支,解决冲突

步骤:

  1. 先切换到master分支git checkout master
  2. 在master分支上执行git merge dev将devmerge到master
  3. 如果出现冲突,则手动解决冲突,然后add,然后commit,然后push,如果过程中出现问题可以使用git merge --abort终止merge
  4. 没有出现冲突直接add接着commit接着push

stash

  • 场景:当你在某一个分支上工作时,突然因为某个原因想要切换到其他分支上看看或者操作,但是你又不想提交当前分支只改了部分代码的半成品,因此,你就可以使用git stash来缓存当前分支的操作工作,然后再切换到其他分支操作,等操作完了,你就可以切回来将缓存的操作弹出来继续操作。当然这个缓存的操作内容不仅仅可以弹出到原来的操作分支,还可以弹出到你想要的任意分支。

  • 暂存到stash的内容,本地仓库的所有分支是共享的,也就是说,在dev分支存放到stash的代码,切换到master分支,在master分支上也可以获取到stash内的内容

// 将本地已追踪的文件的代码改动存放到暂存区
git stash
// 将本地已追踪的文件的代码改动存放到暂存区, 并且增加记录信息
git stash save '暂存的stash记录信息'
// 存储没有追踪的文件到stash暂存区
git stash save -u

// 查看stash暂存区的存储记录
git stash list
// 查看某一条存储记录的内容
git stash show -p stash@{x}

// 从stash恢复最近的一条记录到本地仓库工作区;并且删除stash中的这条记录
git stash pop
// 从stash恢复指定的一条记录到本地仓库工作区;并且删除stash中的这条记录
git stash pop stash@{x}

// 从stash恢复指定的一条记录到本地仓库工作区;并且不删除stash中的这条记录
git stash apply stash@{x}
// 手动删除指定记录
git stash drop stash@{x}


// 清空stash记录
git stash clear

分支

1. 创建分支

// 新建本地分支dev
git branch dev

// 在本地创建和远程分支对应的分支;本地和远程分支的名称最好一致
git checkout -b branch-name origin/branch-name

2. 查看分支

// 查看分支
git branch

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

// 查看远程分支
git branch -r

// 查看本地分支关联的远程分支
git branch -vv

3. 切换分支

// 切换到dev分支
git checkout dev

4. 创建并切换分支

// 创建dev分支并切换到dev分支上
git checkout -b dev

// 如果远程有dev分支,本地没有dev分支,下面这句的作用是在本地创建dev分支并且自动关联到远程的dev分支,并且切换到本地的dev分支
git checkout dev

5. 删除分支

  • 备注:不能在dev分支上执行删除dev分支的命令;只能切换到其他分支上执行删除dev分支的命令

  • 删除本地分支

// 删除本地dev分支
git branch -d dev

// 如果dev分支还没有被合并,直接`git branch -d dev`删除分支,则会销毁失败。如果要强行删除,需要使用大写的-D参数
git branch -d dev

// 采用 -D 强行删除
git branch -D dev
  • 删除远端分支
// dev为远端分支名
git push origin --delete dev

分支合并

// 比如当前在master分支;将dev分支合并到当前master分支
git branch			// 输出当前分支是master分支
git merge dev		// 在当前的master分支上,执行git merge dev;表示将dev分支合并到当前的master分支

1. 合并方式1之快速合并(Fast-forward)

快速合并的前提条件是:比如两个分支中的其中一个分支master没有动,另一分支dev有新的提交,此时是快速合并,只需要将master分支的指针移动到dev分支指针指的节点上就可以。此时并没有产生新的提交点。只是移动master分支的指针

这种情况停在master分支上,然后把dev分支的更改合并到master分支上,这样dev和master都指向同一个节点上。并且此时不产生新节点,只是移动master指针到dev最新提交点上

2. 合并方式2之三方合并(recursive strategy)

三方合并前提条件是:两个分支都有提交记录,此时不能通过移动指针来完成合并。需要通过两个分支各自的最新提交记录和公共的第一个祖先提交记录共同决定出一个新的提交节点

  • 三方合并解析

分支合并冲突

两个分支对同一个文件的同一行都进行了修改,并且都commit提交了;然后执行git merge合并这两个分支时,此时会引发冲突,人为修复冲突决定最终提交内容

修改完冲突之后,重新提交下.

一般代码流程:从master拉了分支dev,在本地dev上开发,本地也有master,提交的时候,先切换到本地master分支,在本地master分支上拉下远程master的代码,然后切换到本地的dev分支,将刚拉下来的本地master分支合并到dev分支,合并过程有冲突,就在dev分支上解决冲突,解决完了之后再dev分支上再提交代码到远程dev分支,然后再切换到本地master分支,合并本地dev分支的解决冲突之后的新代码代码到本地的master分支,然后再将本地的master分支push到远程master分支

状态查询status

// 查看分支上的工作区和暂存区的文件状态
git status

diff查看

1. 查看两个commit的diff

当rebase合并了commit之后,使用settinglist分支合并后的b48a043master分支最新的fab100e之间的diff,这样能确保在推送代码到远端settinglist之前,查看代码是否在合并的过程中丢失代码

// a表示 fab100e 的改动
// b表示  b48a043 的改动
// 注意这里+-并不代表删除,而是增加改动
// git diff a 	  b
git diff fab100e b48a043

2 查看

日志

1. git log: 显示从最近到最远的提交日志记录历史

2. git log --pretty=oneline : 
		- 显示从最近到最远的提交日志记录历史,只显示commit信息不显示其他,比较简洁
		- 也可以直接使用 `git log --oneline`
		- `git log --oneline --graph`: 可以帮我们展示出简略的提交记录图形化
3. git reflog: 是记录每一次命令,查看命令历史

撤销操作

1. 撤销工作区的修改

// 撤销工作区中当前目录中的所有更改
git checkout .

// 撤销工作区中指定文件的修改
git checkout -- filename

2. 版本回退

  • 版本回退:是指将版本库从当前版本回退到其他的版本
  • 语法git reset --hard 版本号
    • HEAD:指向当前分支记录的最新版本节点
    • HEAD^:表示当前分支记录的上一个版本节点
    • HEAD~50:表示当前分支记录的上50个版本节点
// 将当前分支的版本回退到上一个commit版本节点
git reset --hard HEAD^

// 回退到指定版本
git reset --hard 4b2a0c8
  • 帮助git reset -h 帮助查看选项
1. --mixed: 
	- 为默认参数,表示不删除工作空间的改动代码,撤销commit,并且撤销git add操作;
  - git reset --mixed HEAD^ 和 git reset HEAD^ 效果是一样的。

2. --soft: 
	- 表示仅仅重置 HEAD 指针,即只改变 HEAD 的指向
  - 不删除工作空间改动代码,也保留暂存区。撤销commit,不撤销add操作

3. --hard: 
	- 删除工作空间改动代码,撤销commit,撤销git add 
  - 注意完成这个操作后,就恢复到了上一次的commit状态
  • 具体操作:见场景分析

场景分析

1. 场景1

  • 假如你只是修改了工作区,还没有 git add 到暂存区。可以使用下面的命令撤销工作区中的修改
// 还没有git add之前,撤销工作区所有更改
git checkout .

// 撤销工作区中指定文件的修改
git checkout -- filename

2. 场景2

  • 假如你修改了工作区,并把工作区中的修改 git add 到了暂存区。如果你想撤销git add操作并且不保留工作区的代码改动。
git reset --hard head

3. 场景3

  • 假如你修改了工作区,并把工作区中的修改 git add 到了暂存区。如果你只想撤销git add操作并且保留工作区的代码改动。
git reset --mixed
// 或者简写
git reset

4. 场景4

  • 假如修改了工作区,并且已经git add到暂存区,也已经git commit到版本库,此时只想撤销commit操作,不撤销git add操作,保留暂存区代码,也保留工作区代码
git reset --soft HEAD^

5. 场景5

  • 假如修改了工作区,并且已经git add到暂存区,也已经git commit到版本库,此时只想撤销commit操作,撤销git add操作,保留工作区代码
// 撤销commit和add,保留工作区改动的代码
git reset --mixed HEAD^

6. 场景6

  • 假如修改了工作区,并且已经git add到暂存区,也已经git commit到版本库,此时只想撤销commit操作,撤销git add操作,不保留工作区代码
// 相当于回到了上一个版本,也就是上一个commit之后
git reset --hard head^

回滚操作

1. 撤销git命令

比如执行了某个操作命令 git add .想回滚到这个命令之前的状态,就像没执行这个命令一样

先使用git reflog 查看所有的命令日志,再使用git reset --hard cd63939 cd63939是git add这行命令之前的最新的commmit

git的config配置

// 在当前的本地仓库内配置局部git用户名信息
git config user.name xxx

// 在当前的本地仓库内配置局部git用户邮件信息
git config user.email xxx@2008.sina.com

// 列出当前仓库的git配置信息
git config --list

// 也可以通过git配置文件查看本地仓库的git配置信息 
cd learngit
cat .git/config

cherry-pick

git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支

image.png


image.png


转移多个提交

image.png

npm和yarn

www.cnblogs.com/jtjianfeng/…

项目初始化安装package.json依赖:

npm install
或者
yarn install

关于锁版本的问题:比如说你的项目模块依赖是图中描述的,@1.2.1代表这个模块的版本。在你安装A的时候需要安装依赖C和D,很多依赖不会指定版本号,默认会安装最新的版本,这样就会出现问题:比如今天安装模块的时候C和D是某一个版本,而当以后C、D更新的时候,再次安装模块就会安装C和D的最新版本,如果新的版本无法兼容你的项目,你的程序可能就会出BUG,甚至无法运行。这就是npm的弊端,而yarn为了解决这个问题推出了yarn.lock的机制,这是作者项目中的yarn.lock文件。

大家会看到,这个文件已经把依赖模块的版本号全部锁定,当你执行yarn install的时候,yarn会读取这个文件获得依赖的版本号,然后依照这个版本号去安装对应的依赖模块,这样依赖就会被锁定,以后再也不用担心版本号的问题了。其他人或者其他环境下使用的时候,把这个yarn.lock拷贝到相应的环境项目下再安装即可。


Yarn 淘宝源安装:


yarn config set registry [https://registry.npm.taobao.org](https://registry.npm.taobao.org/) -g  
yarn config set sass_binary_site <http://cdn.npm.taobao.org/dist/node-sass> -g

踩坑

踩坑1

如果不是通过clone得到的本地仓库,而是通过在本地git init初始化仓库,并且使用git remote的方式关联远程仓库,那么这种情况下本地是没有master分支的,必须进行一次commit之后才会自动生成本地的master分支

配置了git提约束提交

// 跳过验证检查
git commit --no-verify -m "xxx"

参考

yicm.github.io/blog/2018/0…

www.bookstack.cn/read/git-tu…

www.ruanyifeng.com/blog/2020/0…