跳到主要内容

git

配置:​

查看git相关配置​

bash
# 查看目前全局git配置信息
git config -l
git config --list

# 在当前项目查看git配置
git config --show-origin --get user.name
git config --show-origin --get user.email
git config --get user.name

换行符​

  • 在window系统中,clone代码下来,会自动把换行符LF(linefeed character) 转换成回车符CRLF(carriage-return character)
  • 可以使用git执行以下命令关掉自动转化(git默认是打开的)
bash
git config --global core.autocrlf false

配置git用户​

bash
git config --global user.name qiuweikangdev
git config --global user.email 642827353@qq.com

git配置大小写​

场景: 本地代码运行正常,但是发现push上去的代码运行后报错/在cicd编译报错,发现有个文件没注意大小写

  • git默认是忽略大小写的,改变了大小写,git是不会识别出来的
  • 需要设置git设置大小写敏感
bash
# 查看git大小写配置
git config core.ignorecase
# 设置大小写
git config core.ignorecase false

给不同目录配置不同的git config​

开发的时候,一个电脑上会遇到有多个源的git仓库和git用户名。比如公司仓库一个名字,自己的私人仓库一个名字

  • 因为用同一个名字或者邮箱,会造成冲突、污染、暴露隐私
  • 个人和公司或者其他项目,应该对应不同的用户和邮箱,每个都是独立的git配置,互不干扰

传统的方式:​

  • 单独给每个项目都设置一遍,但是如果项目太多,这种方式不太实际,浪费时间且繁琐
bash
# 进入要单独设置用户名的仓库.git文件夹中
cd .git
# 设置单独用户名
git config user.name "user1"
# 设置邮箱
git config user.email "user1@gmail.com"
# 查看当前仓库配置
cat .git/config

使用includeIf方式 【推荐】​

  • 在用户的根目录下.gitconfig配置includeIf

    • 如C:\Users\qwk64\.gitconfig

    注意,如果修改用户根目录的.gitconfig不生效的话,可以修改git的安装目录下的.gitconfg

    • 如D:\tools\Git\etc\.gitconfig
  • 可以单独建一个config配置的文件夹,便于管理,在此文件夹中,配置多个不同的gitconfig配置

    • 如 D:/my-config/git/.gitconfig-github、D:/my-config/git/.gitconfig-gitee

Git\etc\.gitconfig、C:\Users\qwk64\.gitconfig

js
[includeIf "gitdir:D:/a-frontEnd/"]
path = D:/my-config/git/.gitconfig-github

[includeIf "gitdir:D:/work/waga"]
path = D:/my-config/git/.gitconfig-gitee

my-config/git/.gitconfig-github

bash
[user]
name = qiuweikangdev
email = 642827353@qq.com

my-config/git/.gitconfig-gitee

bash
[user]
name = 丘伟康
email = 642827353@qq.com

git commit场景​

如何修改commit?​

三种情况

  • 1、刚刚commit,还没有push,使用git commit --amend;
  • 2、刚刚push,要修改最近一个push的commit信息,使用git commit --amend;
  • 3、修改历史push的commit信息,使用git rebase -i HEAD~n【其中的n为记录数】,配合2中的命令

用commit信息关闭Issue​

如果某个提交修复了一个Issue,当提交到master分支时,提交信息里可以使用 fix/fixes/fixed , close/closes/closed 或者 resolve/resolves/resolved等关键词,后面再跟上Issue号,这样就会关闭这个Issue。

text
$ git commit -m "Fix screwup, fixes #12"

这将会关闭Issue #12,并且在Issue讨论列表里关联引用这次提交。

强制提交​

bash
git commit -m 'xx' --no-verify

git push 场景​

首次提交上游分支问题​

一般首次提交可能出现报错提示需要把当前分支设置为上游分支,因为没有将本地的分支与远程仓库的分支进行关联

bash
//将当前分支推送到远程分支
git push origin HEAD
// 可能会出现错误,本地分支与远程分支没有关联
  • --set-upstream 【简写是 -u】

当前分支 feature-3.31.1-upgrade 没有上游分支。

要推送当前分支并将远程设置为上游

使用--set-upstream就可以把本地分支与远程仓库进行关联

bash
git push --set-upstream origin feature-3.31.1-upgrade
// 使用简写
git push -u origin feature-3.31.1-upgrade

总结:

  • 当我们设定了远程仓库和本地分支关联之后, 才可以直接简约的git push
  • 第一次推送到远程的时候,没有加任何参数,git会提示你设置上游分支

删除远程分支​

bash
# 删除远程分支
git push --delete origin BranchName

git branch场景​

基于tag创建分支​

  • 从tag创建新的分支
bash
git branch <new-branch-name> <tag-name>

git checkout场景​

从某个commit提交,检出为新的分支​

bash
1、git log 查看提交
2、// 通过checkout 跟上commitId 即可创建制定commit之前的本地分支
git checkout commitId -b 本地新branchName
// 依然通过push 跟上你希望的远程新分支名字即可
3、git push origin HEAD:远程新branchName

恢复成未修改时的样子​

bash
git checkout .
# 这条命令把 当前目录所有修改的文件 从HEAD中签出并且把它恢复成未修改时的样子.

快速切换最近分支​

  • 当你经常工作于 A 与 B 两个分支,需要来回切。这时命令应该是 git checkout A,但这里有一个更简单的命令,git checkout -,-表示切到最近的一次分支
bash
git checkout -

git reset场景​

撤销add,commit操作​

text
git reset --mixed HEAD^

撤销commit​

text
git reset --soft HEAD^

回滚某个版本,删除工作空间改动代码,撤销commit,撤销git add .​

text
git reset --hard HEAD^ 回退到上个版本
git reset --hard HEAD~3 回退到前3次提交之前,以此类推,回退到n次提交之前

回滚操作​

参考:https://juejin.cn/post/7046720828901163016?utm_source=gold_browser_extension#comment

1、reset的作用是当你希望提交的commit从历史记录中完全消失就可以用

2、比如你在master分支提交了A-->B-->C提交了三个记录,这个时候如果C记录有问题你想回滚到B就可以用git reset进行

3、这个命令大概率的情况都是用在我们主分支的,因为我们上线的分支一般是master分支然后从develop进行功能开发

4、开发完成之后将分支合并到master,如果在上线之前发现合并的分支用问题可以将develop合并过来的分支进行回滚

5、说白了就是取消develop的本次合并

6、但是有一种情况就是协作开发的时候大家都合并到master之后就不能用reset强行回滚commit因为这样会把其他人的提交记录给冲掉, 这时候就可以用revert来进行操作

例子:commit记录有A、B、C

  • 回滚到B
    • 注意: 如果直接git push会有警告,这是因为本地的记录因为我们的回滚已经落后于仓库的代码了,这个使用需要使用git push -f进行强制提交
bash
git log //查看记录,查看需要回滚的commitId
git reset xxxxxxx // commid一般是前7位就够用
git push -f
  • 回滚版本、想要让Git回退历史,有以下步骤:

    1、使用git log命令,查看分支提交历史,确认需要回退的版本 2、使用git reset --hard commit_id命令,进行版本回退 3、使用git push origin命令,推送至远程分支

快捷命令:

js
回退上个版本:git reset --hard HEAD^

git revert场景​

参考:https://www.ruanyifeng.com/blog/2019/12/git-undo.html

git revert介绍:

1、revert的原理是,在当前提交后面,新增一次提交,抵消掉上一次提交导致的所有变化。它不会改变过去的历史,所以是首选方式,没有任何丢失代码的风险

2、revert可以抵消上一个提交,那么如果想要抵消多个需要执行 git revert 倒数第一个commit id 倒数第二个commit

3、这个就常用于当你提交了一次commit之后发现提交的可能有问题就可以用到revert

4、还有一种情景是已经有很多人提交过代码,但是想改之前的某一次commit记录又不想影响后面的也可以使用revert,他会把你后面提交的记录都放到工作区只是合并的时候需要注意一点

撤销提交​

一种常见的场景是,提交代码以后,你突然意识到这个提交有问题,应该撤销掉,这时执行下面的命令就可以了。

js
# 撤销上一个提交
git revert HEAD

上面命令的原理是,在当前提交后面,新增一次提交,抵消掉上一次提交导致的所有变化。它不会改变过去的历史,所以是首选方式,没有任何丢失代码的风险。

回滚撤回某个提交​

我们既不想破坏之前的提交记录,又想撤回之前写的代码,这时候就可以使用git revert

  • 如果使用git reset的话,之前的commit会从历史记录中完全消失
bash
# 查看日志,查看commit的id
git log
# 撤销某个commit
git revert commit-id

会新增一个提交,用于抵消撤回之前的提交记录

git tag场景​

  • 使用git tag 主要是给commit的hash校验和取的一个名字,比较直观,方便记忆和使用

    • 因为commitId是hash,不太直观
  • tag 对应某个commit的,相当于给branch分支取一个别名,用来标记一个版本

  • 在上线之前我们需要对当前的commit记录打一个tag方便上线的代码有问题可以及时回滚

bash
# 创建tag
git tag tagName(你的tag名称)
# 新建一个tag标签带有备注信息
git tag -a tagName -m "tag备注"
# 查看当前tag信息
git show tagName(你的tag标签名)
# 把所有tags提交到远端
git push --tags // 把所有tags提交到远端
# 指定tag提交到远端
git push origin tagName
# 删除tag
git tag -d tagName
# 删除远端的tag
git push --delete origin tagName

git rebase/git merge场景​

git rebase:​

用于把一个分支的修改合并到当前分支上

rebase可以给commit重新设置基础点 (也就是父commit)

可以让分叉的提升历史重新回到一条线,也就是重新设置基础点,就是rebase含义

git rebase有三种特别常用的地方:

  1. 拉取远程代码
  2. 合并多次提交
  3. 合并分支

git merge​

git pull = git fetch + git merge

将当前分支合并到指定分支

git merge的时候,会生成一个新的提交,并且master分支的HEAD会移动到新的分支上 【HEAD表示指向指向当前分支的最新提交】

会导致commit历史分叉

  • 如果不希望commit历史出现分叉,可以使用rebase来代替merge

    • 为什么会出现历史分叉?因为在merge之后,commit历史就会出现分叉

    假设有3个开发一起工作,那就有3个开发的分支,如果使用merge,你的代码历史树就会出现3个分支跟这个主的分支交织在一起

    • 如果使用rebase,rebase永远都不会导致多个历史分支进行交织,它永远都是一条线

rebase基本命令​

bash
git rebase feature // 将feature分支rebase(变基)到当前分支 【feature和当前分支会合并到一条线上】
git rebase --continue // 合并冲突,结合"git add 文件"命令一起用与修复冲突
git rebase --skip // 来跳过这次 rebase 操作。
git rebase --abort // 会放弃合并,回到rebase操作之前的状态,之前的提交的不会丢弃

使用rebase拉取远程代码​

bash
git pull --rebase
  • 如果有冲突,会显示冲突代码

    • 解决冲突
    bash
    git add .
    git rebase --continue

git rebase --continue 会出现vim操作界面,提醒你修改commit的相关信息

按i进入编辑模式,修改完毕后按Esc退出,然后输入:wq保存并退出编辑。(如果你只是保留了其中一个版本,而不是对两者进行整合,那么不会弹出vim操作界面)

使用rebase合并commit​

分支开发完成后,很可能有一堆commit,但是合并到主干的时候,往往希望只有一个(或最多两三个)commit,这样不仅清晰,也容易管理

那么,怎样才能将多个commit合并呢?这就要用到 git rebase 命令。

bash
git rebase -i origin/master

git rebase命令的i参数表示互动(interactive), 这时git会打开一个互动界面

上面的互动界面,先列出当前分支最新的4个commit(越下面越新)。每个commit前面有一个操作命令,默认是pick,表示 该行commit被选中,要进行rebase操作。

4个commit的下面是一大堆注释,列出可以使用的命令。

  • pick:正常选中
  • reword:选中,并且修改提交信息;
  • edit:选中,rebase时会暂停,允许你修改这个commit(参考这里)
  • squash:选中,会将当前commit与上一个commit合并 【简写s】
  • fixup:与squash相同,但不会保存当前commit的提交信息 【简写f】
  • exec:执行其他shell命令

巧妙处理另外一种合并commit的简便方法

  • 就是先撤销过去5个commit,然后再建一个新的。
bash
git reset HEAD~5 # 合并多少个commit
git add .
git commit -m "Here's the bug fix that closes #28"
git push

rebase导致冲突太多如何解决?​

由于rebase是把根据commit一次一次合并到当前分支,需要依次的解决冲突

解决办法:

  • 在rebase合并代码之前,可以先把本地多次commit合并成一个commit
bash
git rebase -i HEAD~3 // 从最近3次commit合并
或者
git rebase -i 5753fc5b5959380ec999f8e51252019487860f0f
(从head找到5753截止,但不包括5753)

git merge 和 git rebase 的区别​

解决冲突区别:

  • 在解决冲突的时候,用 merge 只需要解决一次冲突即可,而用 rebase 的时候 ,需要依次解决每次的冲突,才可以提交

    因为rebase是一次一次合并的 按照commit

分支分叉区别:

  • 使用merge会导致commit 历史就会出现分叉,而rebase不会导致多个历史分支进行分叉,它永远都是一条线

merge-rebase

git stash场景​

使用 git stash 来暂存文件

会有这么一个场景,现在你正在用你的 feature 分支上开发新功能。这时,生产环境上出现了一个 bug 需要紧急修复,但是你这部分代码还没开发完,不想提交,怎么办?这个时候可以用 git stash 命令先把工作区已经修改的文件暂存起来

基本命令如下

bash
git stash //把本地的改动暂存起来【不包含add新增的文件,只包含modify修改过的文件】
git stash -u // 可以把新增的文件也暂存起来 【包含add、modify文件,-u选项代表"update",它的作用是包括未跟踪的文件(untracked files)】
git stash save "message" 执行存储时,添加备注,方便查找。
git stash pop // 应用最近一次暂存的修改,并删除暂存的记录
git stash apply // 应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即 git stash apply {0},如果要使用其他个,git stash apply {$num} 。
git stash list // 查看 stash 有哪些存储
git stash clear // 删除所有缓存的 stash

git status场景​

可以查看哪些文件被改动

查看文件是否 修改/添加/删除状态​

  • --porcelain: 可以识别文件 修改/添加/删除等状态
bash
git status --porcelain

git log场景​

查看分支分叉情况​

bash
git log --graph

log日志搜索​

  • 对提交的git日志搜索,有时候需要查找一些提交内容来定位问题
  • 通过对log日志搜索,可以快速定位到修改过此代码的成员以及commitId
bash
git log --grep 搜索内容
// 比如要搜索 表格问题
git log --grep 表格问题

git rm场景​

删除 Git 缓存文件

场景: 有些情况开发者把原有不需要提交的代码提交到了远端仓库,再使用.gitignore忽略文件不生效。哪怕我们删除后再提交也没有办法忽略。这种情况下我们应该怎么解决?

方法: 我们可以使用git rm --cache 删除原来git跟踪的文件缓存,再在.gitignore里面添加忽略文件

bash
## 当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用
git rm file_path

## 当我们需要删除暂存区或分支上的文件, 但本地又需要使用, 只是不希望这个文件被版本控制, 可以使用
# PS: file_path 为文件路径
git rm --cached file_path

git submodule场景​

submodule允许你将一个Git 仓库当作另外一个Git 仓库的子目录

通过 git submodule 的方式,我们可以将代码封装成一个公共的 Git 仓库,然后复用到不同的应用中,但也需要经历如下的步骤

在复杂工程项目中,可能会遇到在一个 Git 仓库中添加其他 Git 仓库的场景,Submodule是仓库的一份引用。

bash
# 添加子模块
git submodule add 仓库地址

# 更新子模块
git submodule update --remote 模块名称

## 删除子模块
1. git rm --cached 模块名称
2. 删除 .gitmodules 下相应子模块信息
3. 删除 .git/config 下相应子模块信息

## 工程绑定子仓库命令:
git submodule init
git submodule update (若子仓库没有权限则会报错)
git submodule update --init --recursive

## git submodule foreach 遍历仓库中的每个子模块,并在每个子模块的目录中执行指定的命令
## git submodule foreach 命令的作用是在主仓库中遍历所有子模块
git submodule foreach git pull

如果你已经克隆了项目但忘记了 --recurse-submodules,那么可以运行 git submodule update --init 将 git submodule init 和 git submodule update 合并成一步。如果还要初始化、抓取并检出任何嵌套的子模块, 请使用简明的 git submodule update --init --recursive。

git submodule、 git subtree区别​

  • git子模块:git submodule 或 git subtree
  • git submodule相当于是引用的关系,引用,不会占用额外空间
    • git submodule 允许你在一个 Git 项目中引用另一个 Git 仓库
  • git subtree 相当于是拷贝,会占用空间
    • git subtree 允许你在一个 Git 项目中拷贝到另一个 Git 仓库

Git Submodule是Git自带的工具,它允许在一个Git仓库中添加一个指向另一个Git仓库的引用。这个引用被称为子模块,它允许在父仓库中记录子仓库的版本号,并可以将子仓库更新到最新版本。但是,Git Submodule不会自动将子仓库的代码合并到父仓库中,这需要手动执行。

Git Subtree是一个由Git社区开发的外部工具,它可以将一个Git仓库中的一个子目录提取到另一个Git仓库中。它允许在父仓库中记录子目录的版本号,并可以将子目录的更改合并到父仓库中。相比之下,Git Subtree没有子模块那样复杂,更容易使用和管理。

因此,Git Submodule适用于需要管理多个不同版本的子模块的项目,而Git Subtree适用于将一个单独的子目录作为一个单独的项目进行管理的项目。

git不同仓库设置不同用户名相关操作​

开发的时候,一个电脑上会遇到有多个源的git仓库和git用户名。比如公司仓库一个名字,自己的私人仓库一个名字

bash
# 查看目前全局git配置信息
git config -l
# 输出内容中user.name就是目前设置的用户名

# 进入要单独设置用户名的仓库.git文件夹中
cd .git
# 设置单独用户名
git config user.name "user1"
# 设置邮箱
git config user.email "user1@gmail.com"
# 查看当前仓库配置
cat .git/config

# 如果需要设置全局
git config --global user.name "global_user"

问题:

  • 报了403,说明访问被拒绝。 意思很明白,userB没有权限对userA的test进行push更改

原因:

  • 由于该电脑使用git bash配过SSH,系统已经将指向github.com的用户设置为了userB,每次push操作的时候,都将读取到userB的用户信息,类似于 记住密码。

解决方案:

git reflog场景​

要避免使用 git reset <commit id> --hard。因为这是一种破坏性的操作。一旦执行,之前的修改全部丢失了,但有时候又避免不了使用 reset,在你执行 reset 之后,却发现,之前的某些提交还是有用的,想再看下之前的代码,这个时候可以使用 git reflog

  • 利用 git reflog 找回丢失的 commit 记录

git cherry-pick场景​

  • 工作中有时候会有一些定制功能,会遇到代码迁移的需求,代码在 2 条分支线上,往往不能直接合并
  • 执行 git cherry-pick <commit id> 可以非常方便地帮助我们实现代码迁移,但是前提是 commit 提交清晰,功能明确。

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

bash
git cherry-pick <commitHash>

Cherry pick 支持一次转移多个提交。

bash
git cherry-pick <HashA> <HashB>

git cherry-pick 与 git merge 不同的是:​

  • cherry-pick 可以迁移单个 commit 迁移,会生成一个新的 commit id
  • merge 必须全部功能合并过去,但不会生成新的 commit id,而是commit指针指向新的分支

git 别名配置

git flow工作流

  • git flow feature start demo

    • 开始一个新的功能分支,分支名称为 demo
    • 用于在该分支上完成相关功能的开发。执行该命令会检查当前仓库是否在 develop 分支上,如果不在,则会自动切换到 develop 分支。该命令还将自动拉取 origin/develop 分支最新更新内容,保证本地 develop 分支是最新的
  • git flow feature finish demo

    • 完成一个功能分支的开发,将分支合并至 develop 分支中。执行该命令会先将本地 demo 分支合并到 develop 分支,然后删除本地 demo分支, 并删除远端的 origin/demo 分支

    • 在合并分支之后,该命令会将最新的 develop 分支推送到远端仓库,保证分支同步

bash
git flow init
# 特性分支 从develop新建一个新的分支: feature/1.0.0
git flow feature start 1.0.0
# 合并feature分支到develop, 合并完之后,会自动删除feature/1.0.0, 自动切到develop
git flow feature finish 1.0.0

# 新建一个release分支
git flow release start 1.0.0
# 完成release分支, 并且打tag, 自动合并release到develop和master, 同时会删掉release分支
# 会在 release 分支上打上对应的 tag,并将这个 tag 合并到 develop 分支上
# tag对应某个commit的信息,tag标记这个版本的发布,此时tag是对应prod打包的commit记录,tag相当于给上线的版本的一个记录名字,可以理解别名、快照的意思
git flow release finish 1.0.0

git版本管理工具

Fork常用的版本管理软件对比

可视化操作界面可视化分管理直观的代码差异对比多仓库管理代码搜索大量文件改动时性能
Fork有有有有有流畅
Source Tree有有有有有卡顿

Fork​

支持特性

  • diff对比高亮
  • 处理合并冲突

配置环境

  • 配置SSh Keys

Source Tree​