跳转至

tools

约 1 个字 预计阅读时间不到 1 分钟

01.IdeaGit-Demo

约 198 个字 2 行代码 9 张图片 预计阅读时间 1 分钟

准备

  1. 创建一个github repo

  1. 创建一个idea项目

注意到,github repo中是存在一个预先定义的README文件,而idea项目中不存在

尝试提交并推送

找到左侧commit选项,选中全部并点击Commit

commit完成之后右键master分支,将其改名为main,目的是保证和github repo中的分支保持一致

右键main分支,尝试push

此时还未定义git remote,点击Define remote,复制github repo的链接粘贴进去,再次尝试推送

不出意外,应该要出意外了,idea会提示push reject,代表出现冲突

解决办法如下:

  1. 命令行
Bash
git fetch
git pull --rebase origin main
  1. idea手动拉取

首先进行fetch,然后进行pull

我这里选择命令行执行

此时 push 成功,rt

02.IdeaGit 基础操作

约 1713 个字 26 行代码 31 张图片 预计阅读时间 6 分钟

1. 初始化

Bash
git init

查看目录结构中,就可以看到包含有 .git 子目录,这就说明创建版本库成功

相当于idea中的 vcs----create git repository

2. 将文件添加到版本库

2.1 将文件添加到暂存区

Bash
git add 001.txt        // 添加单个文件到暂存区
git add .                // 将当前目录下所有修改添加到暂存区,除按照规则忽略的之外

相当于idea中的git --> add

不同之处是在idea中即便不进行add,依旧可以commit


2.2 将暂存区文件提交到仓库

Bash
git commit        // 如果暂存区有文件,则将其中的文件提交到仓库
git commit -m 'your comments'         // 带评论提交,用于说明提交内容、变更、作用等

这个和idea中的git -commit一致,不同点:注释必须写


2.3 查看仓库状态

Bash
git status

在idea中,直接在commit界面可以看到改动的所有文件以及未add的文件

红色: 代表未add到暂存区
绿色: 代表已在暂存区但是有修改
无标记:代表无修改


2.4 查看仓库中的具体修改

Bash
git diff    // 查看版本库中所有的改动
git diff 001.txt        // 查看具体文件的改动

在idea中,可以在commit界面中双击文件查看,或者也可以通过右键标签--show diff with working tree查看


2.5 查看历史提交记录

Bash
git log     // 显示所有提交的历史记录
git log --pretty=oneline    // 单行显示提交历史记录的内容

相当于idea中的git窗口,同时commit id 位于右下角


2.6 版本回退

Bash
1
2
3
git reset --hard HEAD^        // 回退到上一个提交版本
git reset --hard HEAD^^        // 回退到上上一个提交版本
git reset --hard 'commit_id'    // 会退到 commit_id 指定的提交版本

如下图,某个git仓库中存在2个提交记录,需要版本回退到第一个记录

输入 git reset --hard f731

此时,如果反悔了,不希望回退,如何重新返回?

输入git log,发现仅存在一条提交记录,查询不到第2条提交记录

可以通过git reflog找到之前的提交记录

Bash
git reflog
git reset --hard 'commit_id'


git工作区域

git reset的方式不仅仅只有hard一种,还有softmixedkeep,而在介绍它们之间的异同前,首先需要理解git的工作区域

  • Workspace: 工作区,就是你平时存放项目代码的地方
  • Index / Stage: 暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
  • Repository: 仓库区(或版本库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
  • Remote: 远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

执行reset命令后还存在文件的区域

git reset


2.6.1 git reset --soft

操作

移动本地库HEAD指针

前置准备(其他演示类似不做过多赘述)

类似上文,某个git仓库中存在2个提交记录,需要版本回退到第一个记录

远程仓库如下图所示

输入下述命令,使用soft回滚,并推送到远程仓库

Bash
git reset --soft 'commitid'
git push --force origin master # 注意这里要强制推送

可以看到远程仓库中第2次提交不存在了,意味着版本库发生修改

运行 git statusll(alias for ls -l), 观察结果可知工作区和暂存区未发生修改

结论

soft只影响版本库,不影响工作区和暂存区


2.6.2 git reset --mixed

操作

移动本地库HEAD指针
重置暂存区

输入下述命令,使用mixed回滚,并推送到远程仓库

Bash
git reset --mixed 'commitid'
git push --force origin master # 注意这里要强制推送

可以看到远程仓库中第2次提交不存在了,意味着版本库发生修改

运行 git statusll(alias for ls -l), 观察结果可知工作区未发生修改,暂存区发生修改(丢失了对t2的追踪)

结论

mixed影响版本库和暂存区,不影响工作区


2.6.3 git reset --hard

操作

移动本地库HEAD指针
重置暂存区
重置工作区

输入下述命令,使用hard回滚,并推送到远程仓库

Bash
git reset --hard 'commitid'
git push --force origin master # 注意这里要强制推送

可以看到远程仓库中第2次提交不存在了,意味着版本库发生修改

运行 git statusll(alias for ls -l), 观察结果可知工作区发生修改,暂存区发生修改(丢失了对t2的追踪)

结论

hard影响版本库、暂存区和工作区


2.6.4 git reset --keep

操作

移动本地库HEAD指针
重置暂存区
重置工作区, 保留改动

keep模式和hard模式有些类似,但是对工作区的操作有些不同,具体如下

工作区中文件如果当前版本和退回版本之间没有发生过变动,则工作区的修改保持不便;如果发生了变动,并且工作区也进行了修改,需要自行合并(或者冲突解决)

1. 工作区文件未发生变动

Bash
git reset --keep 'commitid'

hard模式保持一致,版本库、暂存区和工作区均发生修改

2. 工作区文件发生变动

reset之前,将t1文件中的111改为311,并添加到暂存区

执行reset

Bash
git reset --keep 'commitid'

神奇的是,加入暂存区的对应文件发生的变动也被保留了下来

再来看变动的另一种情况,在reset之前,将t1文件中的111改为311,且将t2文件中的222改成322,并添加到暂存区

执行 reset

Bash
git reset --keep 'commitid'

发现出现报错,原因是f731版本中t2文件是不存在的,导致无法merge

结论

keep影响版本库、暂存区和工作区,可以撤销提交而不丢失文件的更改


接下来学习idea git中的版本回退

首先在项目中创建一个名为 GitResetTest.java 的文件

添加到暂存区并提交

修改文件,再次提交

右键希望回退到的版本,选择Reset

选择hard模式

如果希望撤销回滚,同样需要查询reflog, 打开terminal输入git reflog, 找到对应的commitid

通过右键项目的reset head进行回退


2.7 撤销修改

Bash
git checkout -- 004.txt   // 如果 004.txt 文件在工作区,则丢弃其修改
git checkout -- .            // 丢弃当前目录下所有工作区中文件的修改

idea中:

注意到在rollback右侧有一个静默搁置按钮

点击之后修改的代码也会消失,这个功能主要是用于暂存你修改后的代码,并把你工作区的代码回滚到最后commit的记录,恢复的时候通过:

那么这个操作具体使用场景是什么呢?

试想一下,在我们开发的时候,正在写某个需求的代码,然而此时项目经理要求你去做一个更加重要/紧迫的任务,那么现在这部分需求代码暂未写完,是不能提交的,此时就可以使用静默搁置,将代码暂时搁置,等到把项目经理的任务忙完后,选择取消静默,接着写即可


2.8 删除文件

在被 git 管理的目录中删除文件时,可以选择如下两种方式来记录删除动作:

  1. rm + git commit -am "abc"
  2. git rm + git commit -m "abc"

区别在于

  • 如果文件已经被git跟踪,那么 1、2 都可以正常工作
  • 如果文件未被git跟踪
    • rm + git commit -am "abc" 不会提交删除
    • git rm + git commit -m "abc" 可以确保文件删除被git记录并提交

03.IdeaGit 远程仓库

约 149 个字 5 行代码 2 张图片 预计阅读时间 1 分钟

1. 克隆仓库

Bash
git clone 你的仓库地址

idea中即创建项目的时候选择 from version control

2. 添加远程仓库

Bash
git remote add origin 你的仓库地址

3. 查看远程仓库信息

Bash
git remote [-v] // 显示远程仓库信息

idea中

4. 推送本地内容到远程仓库

Bash
git push -u origin <branch>

-u 代表设置上游分支。

在执行 git push -u origin <branch> 后,Git 会将当前本地分支与远程仓库的 <branch> 分支关联。之后,你可以简单地使用 git pushgit pull,Git 会知道应该推送/拉取哪个远程分支,而不需要每次都指定远程分支的名称。

5. 修改本地仓库对应的远程仓库地址

Bash
git remote set-url origin url

04.IdeaGit 分支管理

约 1063 个字 29 行代码 25 张图片 预计阅读时间 4 分钟

1. 查看分支

Bash
1
2
3
git branch        // 查看本地分支信息
git branch -v     // 查看相对详细的本地分支信息
git branch -av     // 查看包括远程仓库在内的分支信息

注意:在 git branch 的输出内容中,有一个分支,前面带有 * 号,这标识我们当前所在的分支。

2. 创建分支

分支创建后,新分支基于当前分支。

Bash
git branch dev 

idea 中

3. 切换分支

Bash
git checkout dev

idea:

4. 创建并切换分支

Bash
git checkout -b dev # 新建 dev 分支,并切换到该分支上

5. 合并分支

Bash
git checkout master        # 切换回 master 分支
git merge dev            # 将 dev 分钟中的修改合并回 master 分支

idea:先check out 到指定标签,在把需要合并的标签右键合并即可。

6. 删除分支

Bash
git branch -d dev # 删除 dev 分支

7. 建立本地分支和远程分支的关联

7.1 本地分支存在,远程分支存在,但之间没有关联关系。

Bash
git push -u origin/remote_branch 命令推送。

7.2 本地分支存在,但远程分支不存在。

Bash
git push origin local_branch:remote_branch 

7.3 本地分支存在,远程分支存在,且关联关系已建立

使用 git push 命令进行推送即可

idea中本地push时直接修改远程分支名即可

8. 从远程仓库拉取

通过 git fetchgit pull 来获取远程仓库的内容。

Bash
git fetch origin master    
git pull origin master

git fetchgit pull 之间的区别:

8.1 git fetch

git fetch 是仅仅获取远程仓库的更新内容,并不会自动做合并。

需要先查看更新:

Bash
git log -p FETCH_HEAD

或者拉取到一个其他分支(目前还没见过分支创建)

如果没有问题,再进行合并:

Bash
git merge origin/master

新建一个本地分支,拉取远程到本地temp,查看不同,没问题则合并,合并后删除即可。

Bash
## 在本地新建一个temp分支,并将远程origin仓库的master分支代码下载到本地temp分支;
$ git fetch origin master:temp

## 比较本地代码与刚刚从远程下载下来的代码的区别;
$ git diff temp

## 合并temp分支到本地的master分支;
$ git merge temp

## 如果不想保留temp分支,删除;
$ git branch -d temp

实机演示:

在远程仓库手动修改t1111511, 在本地仓库的t1文件中添加666commit

1. git fetch origin master:temp

2. git diff temp

3. git merge temp

出现冲突,手动解决

选择全部接受(lazygitb),当然也可以只选择某一个hunk

最终commit log如下所示

4. git branch -d temp


8.2 git pull

git pull 在获取远程仓库的内容后,会自动做合并,可以看成 git fetch 之后 git merge

Bash
1
2
3
# 因为存在冲突故git pull会报错,以下命令二选一即可
git pull --no-rebase # merge冲突
git pull --rebase # rebase冲突


8.3 idea 拉取远程仓库

1. 前置准备

本地创建GitPullTest.java并添加f1函数,提交并推送

本地仓库添加f2函数,并提交

远程仓库添加f3函数,并提交


2. git fetch

找到idea上方git菜单,选择fetch (这里仅演示fetch,不演示pull,思想都是一致的)

选择remote下的main分支,查看更改

检查过后发现没有问题,右键remotemain分支,选择mergerebase合并

选择merge,发现出现冲突,需要解决

点击merge按钮,弹出冲突解决页面

左侧为本地仓库代码,右侧为远程仓库代码

有两种方式解决冲突

  1. 左下角 Accept LeftAccept Right,但只能选择一个仓库的代码作为最终合并文件
  2. 屏幕中间的>><<,可以同时保留本地和远程代码,也可以只选择其中一份

这里选择同时保留本地和远程代码

PS: 中间部分可以随意修改/调换位置,但两侧是无法修改的

最终效果如图所示(merge)

如果选择rebase,最终效果如下图所示


8.4 merge与rebase的区别(存在冲突)

merge:rebase

1. merge

  • 保留分支历史(会产生合并提交 merge commit)。
  • 适合多人协作,不会修改历史记录。

2. rebase

  • 不产生合并提交,而是将 feature 分支上的提交重新应用到 main 分支后面。
  • 历史会被重写(提交哈希值改变),适合保持提交历史整洁。

8.5 merge fast-forward(不存在冲突)

Fast-forward 是 Git 中的一种 合并方式,当你执行 git merge 时,如果当前分支没有新的提交(即该分支的 HEAD 没有分歧),Git 会直接将当前分支指向目标分支的最新提交,而不创建额外的合并提交。

什么时候会发生 Fast-Forward

  • 当目标分支没有新的提交,并且当前分支完全处于目标分支的前面(即目标分支是当前分支的祖先),Git 就可以简单地将当前分支 “快进” 到目标分支的最新提交,而不需要创建新的合并提交。

merge ff:rebase

上面的例子中,dev分支为目标分支,feature分支为当前分支

dev分支中不存在新的提交,且feature分支完全处于dev分支之前,此时进行merge将触发fast-forward,效果与rebase一致

05.IdeaGit 杂项

约 220 个字 10 行代码 9 张图片 预计阅读时间 1 分钟

Cherry-Pick

复用04.IdeaGit 分支管理8.3的前置准备

merge过程上略有不同,保留函数f2,去除函数f3

最终效果如下:

Java
public class GitPullTest {

    public void f1() {
        System.out.println("f1");
    }

    public void f2() {
        System.out.println("f2");
    }
}

此时,继续创建函数f4

问题来了,在实现函数f4时,发现其可以使用函数f3的逻辑简化代码

而想要重新获取之前已经放弃的函数f3,可以选中记录后点击cherry-pick按钮进行合并(可能需要解决冲突),之后会对函数f4在主干上重新提交,被抛弃的代码也可以重新获得。

解决冲突后,最终效果如下图所示

Undo Commit,Revert Commit,Drop Commit

undo:revert:drop

Tag

在项目完工准备发布时,可以对最后一个提交打上Tag

注意:push的时候一定要选中左下角Push tags,否则无法生效

查看远端仓库

Homebrew

约 19 个字 2 行代码 预计阅读时间不到 1 分钟

执行以下代码,跟着配置就行

Bash
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

关闭自动更新

Bash
echo 'export HOMEBREW_NO_AUTO_UPDATE=1' >> ~/.zshrc

oh-my-zsh

约 337 个字 6 行代码 5 张图片 预计阅读时间 1 分钟

本文基于 macos 系统,使用 oh-my-zsh 对终端进行美化。

Oh My Zsh 是基于 zsh 命令行的一个扩展工具集,提供了丰富的扩展功能。

1. 安装 oh-my-zsh

Bash
sh -c "$(curl -fsSL https://install.ohmyz.sh/)"

2. 配置主题

使用 powerlevel10k 主题。

Bash
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k

~/.zshrc 设置 ZSH_THEME="powerlevel10k/powerlevel10k"

运行命令

Bash
source ~/.zshrc

接下来,终端会自动引导你配置 powerlevel10k

如果希望重新配置,输入以下命令

Bash
p10k configure

3. 安装插件

3.1 zsh -autosuggestions

zsh -autosuggestions 是一个命令提示插件,当你输入命令时,会自动推测你可能需要输入的命令,按下右键可以快速采用建议。效果如下:

安装方式:把插件下载到本地的 ~/.oh-my-zsh/custom/plugins 目录

Bash
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

3.2 zsh-syntax-highlighting

zsh-syntax-highlighting 是一个命令语法校验插件,在输入命令的过程中,若指令不合法,则指令显示为红色,若指令合法就会显示为绿色。效果如下:

安装方式:把插件下载到本地的 ~/.oh-my-zsh/custom/plugins 目录。

Bash
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

3.3 z

oh-my-zsh 内置了 z 插件。z 是一个文件夹快捷跳转插件,对于曾经跳转过的目录,只需要输入最终目标文件夹名称,就可以快速跳转,避免再输入长串路径,提高切换文件夹的效率。效果如下:

3.4 启用插件

修改 ~/.zshrc 中插件列表为:

Text Only
plugins=(git zsh-syntax-highlighting zsh-autosuggestions z)

执行 source ~/.zshrc

git commit 规范

约 679 个字 33 行代码 预计阅读时间 3 分钟

Commit message 格式

每次提交,Commit message 都包括三个部分:headerbodyfooter

git commit
1
2
3
4
5
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

其中,header 是必需的,body 和 footer 可以省略。 不管是哪一个部分,任何一行都不得超过72个字符(或100个字符)。这是为了避免自动换行影响美观。

Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。


1. type

用于说明 commit 的类别,只允许使用下面7个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

如果type为featfix,则该 commit 将肯定出现在 Change log 之中。其他情况(docschorestylerefactortest)由你决定,要不要放入 Change log,建议是不要。


2. scope

scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

例如在Angular,可以是 $location, $browser, $compile, $rootScope, ngHref, ngClick, ngView等。

如果你的修改影响了不止一个scope,你可以使用 * 代替。


3. subject

subject是 commit 目的的简短描述,不超过50个字符。

其他注意事项:

  • 动词开头,使用第一人称现在时,比如change,而不是changed或changes
  • 第一个字母小写
  • 结尾不加句号(.)

Body

Body 部分是对本次 commit 的详细描述,可以分成多行。下面是一个范例。

git commit
1
2
3
4
5
6
7
More detailed explanatory text, if necessary.  Wrap it to 
about 72 characters or so. 

Further paragraphs come after blank lines.

- Bullet points are okay, too
- Use a hanging indent

有3个注意点:

  • 使用第一人称现在时,比如使用change而不是changed或changes。
  • 永远别忘了第2行是空行
  • 应该说明代码变动的动机,以及与以前行为的对比

Footer 部分只用于以下两种情况:

  1. 不兼容变动

如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。

git commit
BREAKING CHANGE: isolate scope bindings definition has changed.

    To migrate the code follow the example below:

    Before:

    scope: {
      myAttr: 'attribute',
    }

    After:

    scope: {
      myAttr: '@',
    }

    The removed `inject` wasn't generaly useful for directives so there should be no code using it.
  1. 关闭issue

如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。

git commit
Closes #234

Revert

还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。

git commit
1
2
3
revert: feat(pencil): add 'graphiteWidth' option

This reverts commit 667ecc1654a317a13331b17617d973392f415f02.

Body部分的格式是固定的,必须写成This reverts commit &lt;hash>.,其中的hash是被撤销 commit 的 SHA 标识符。

如果当前 commit 与被撤销的 commit,在同一个发布(release)里面,那么它们都不会出现在 Change log 里面。如果两者在不同的发布,那么当前 commit,会出现在 Change log 的Reverts小标题下面。

参考资料

git commit 规范指南