跳转至

2025

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

Missing Semester of MacOS - A Vim Enthusiast Programmer’s Perspective

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

前言

当我经历了使用 MacBook Air 开启 docker + n 个 idea 项目 + cursor + vscode + 一堆浏览器标签页 卡到爆炸的体验之后,决定迁移我的开发环境到 MacBook Pro 上,在购买前了解到 mac 有非常"先进"的 Migration Assistant,能无缝复制所有的配置到新的 MacBook 上(内心 os: 哎呀这真是个好东西,看来不用自己再配置一遍了)

然后... 不出意外地出了意外,我的 mba 的 Migration Assistant 抽风了,程序一进入到选择页面就是彻底卡死->黑屏->等待几小时依然黑屏->重启->重新启动程序->彻底卡死->....

我甚至没有在网上搜索到任何一位有跟我类似的卡死受害者,一些方法比如将系统版本升级到最新版都试过了,依然无效。

总之放弃了,正好一直想跟别人推荐我的 MacOS 配置,而且之前使用的过程中还是拉了很多史在自己的电脑里,那么就借此记录一下我是如何从零配置我的 MacOS 的吧。

系统设置

开启三指拖拽

image.png

开启轻点

image.png

去掉动画效果

image.png

自动隐藏 dock

image.png

禁用根据最近使用重排序窗口

image.png

finder 默认打开在 user 文件夹 (打开 finder 窗口,左上角 settings)

image.png

finder sidebar 配置,按自己喜欢的来

image.png

Mac 长按连续输入 (重启生效)

Bash
defaults write -g ApplePressAndHoldEnabled -bool false

禁用键盘自动加句号

image.png

image.png

键盘按键 repeat 拉满

image.png

打开 Terminal,输入

Bash
1
2
3
cd ~/Documents
mkdir {Code,Dev-Tools,docker,Privacy,Resources}
mkdir Code/{github.com,Java,Go,Python,vscode,FrontEnd,CS\ Course}

这是我喜欢的 mac 文件管理方式,我的 mac 的桌面上不会有任何文件

  • Code: 存放代码文件
    • github.com
    • Java
    • Go
    • Python
    • vscode
    • FrontEnd
    • CS Course
  • Dev-Tools:开发工具,比如 maven
  • docker:docker-compose 文件
  • Privacy:隐私文件
  • Resources:学习资料

CS Course.png

keyboard shortcuts 中打开快捷键切换桌面,使用 option+数字键切换 (需要创建多个桌面才会有选项)

image.png

网络

这里使用 Clash Verge

你跟我说要 VPN 才能去 github 下 clash?那你下个 Clash 啊 ()

HomeBrew

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

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

Arc

神中神!下载 Arc 浏览器

Download Arc

image.png

一些快捷键

  • cmd + t :打开搜索框,搜索框内输入不同 space 的名称,找到 focus on space名称 这个选项,即可实现切换 space 效果
  • cmd + shift + c :复制当前网站链接
  • cmd + shift + option + c :以 md 格式复制当前网站链接,名字+链接
  • cmd + s :打开/关闭侧边栏

Raycast

神中神!吊打 spotlight

Raycast - Your shortcut to everything

安装完毕之后,在系统设置的 keyboard shortcuts 中关闭 spotlight

image.png

更改 raycast 快捷键

image.png

image.png

后续下载别的软件后会进一步配置

微信输入法

神!比原生输入法好用,选它主要是我要配置一些东西 + 跨设备复制同步

微信输入法-简洁好用打字快

image.png

现在使用 control + space 或者 fn 切换输入法

Karabiner-Elements

神中神!改键位无敌,真的好用

Karabiner-Elements

先把 mac 内置键盘的 fn 和 control 调换一下位置 (我说 mac 键盘设计真是一坨,control 放那个位置)

image.png

接着进行复杂的键位映射

image.png

  1. 映射 cmd + shiftcontrol + space,现在切换输入法可以使用 cmd + shift
  2. 映射大写键到 cmd + shift + option + control ,大写键现在没用了,设置为辅助键位
  3. 映射大写键 + hjkl 到方向键,vim 用户应该懂这个的含金量,无敌!

相关的配置代码如下

Text Only
{
    "description": "Command + Shift to control + spacebar",
    "manipulators": [
        {
            "from": {
                "key_code": "left_shift",
                "modifiers": { "mandatory": ["left_command"] }
            },
            "to": [
                {
                    "key_code": "spacebar",
                    "modifiers": ["left_control"]
                }
            ],
            "type": "basic"
        }
    ]
}
Text Only
{
    "description": "Change LeftShift+LeftCommand+LeftControl+LeftOption+hjkl to arrow keys",
    "manipulators": [
        {
            "from": {
                "key_code": "h",
                "modifiers": {
                    "mandatory": ["left_shift", "left_command", "left_control", "left_option"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "left_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": ["left_shift", "left_command", "left_control", "left_option"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "down_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "k",
                "modifiers": {
                    "mandatory": ["left_shift", "left_command", "left_control", "left_option"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "up_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": ["left_shift", "left_command", "left_control", "left_option"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "right_arrow" }],
            "type": "basic"
        }
    ]
}
Text Only
{
    "manipulators": [
        {
            "description": "Change caps_lock to command+control+option+shift.",
            "from": {
                "key_code": "caps_lock",
                "modifiers": { "optional": ["any"] }
            },
            "to": [
                {
                    "key_code": "left_shift",
                    "modifiers": ["left_command", "left_control", "left_option"]
                }
            ],
            "type": "basic"
        }
    ]
}

Karabiner-Elements 还可以进行其他配置,比如禁用 mac 的内置键盘,然后你的外置键盘就能直接放在内置键盘上了

image.png

Raycast 再配置

在刚刚进行了 Karabiner-Elements 的配置之后,我们已经将大写键作为辅助键位映射到了 cmd + shift + option + control ,所以我可以 100% 保证不可能有键位冲突

让我们输入 cmd + , 打开 raycast 的 settings,找到 extensions

这里以我 mba 上的配置为例,仅供参考,你可以按你喜欢的来

image.png

现在切换窗口已然变得非常丝滑,应用之间使用 CapsLock+字母 进行切换,如果想切换到桌面,比如访问 finder,那么只需要输入 option+数字 即可

Arc 再配置

改一个键位即可,映射 CapsLock + N 到打开 little arc window

image.png

什么是 little arc window?

这东西灰常好用啊,比如我现在全屏的 obsidian 窗口,我希望查询一个东西,那么就可以打开小窗口,查完 cmd + w 关闭即可,非常的方便

rt

image.png

iterm2

iTerm2 - macOS Terminal Replacement

shell 相关的配置请看 oh-my-zsh

or 你可以直接到我的 dotfiles 仓库 LunaY-dotfiles 找到 zsh 文件夹的 .zshrc

把文件 mv 到 ~ 下

记得安装字体,然后去 iterm2 的 settings 中选择 hack-nerd-font

Bash
brew install font-hack-nerd-font

tmux

tmux 插件管理器

Bash
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
Bash
brew install tmux
tmux

dotfiles 仓库 LunaY-dotfiles 找到 tmux 文件夹下的 .tmux.conf

然后 mv 到 ~ 文件夹下

输入

Bash
tmux source ~/.tmux.conf

键位映射很久之前配的了,说下我常用的

  • prefix: control+z
  • 水平切分窗口prefix + |
  • 垂直切分窗口: prefix + -

Lazygit

神中神!用了都说好,终端里的 git 图形化界面

Bash
brew install lazygit

Snipaste

神!截图软件,苹果自带的截图也是一坨

Snipaste - 截图 + 贴图

这边把截图快捷键映射到大写键+1,因为我的键盘的 f1 键要用 fn+1 才能按出来很不方便

image.png

如何使用?

  • 大写键+1:开始截图
  • ,: 上一张截图
  • :下一张截图

Input Source Pro

神!自动切换输入法

Bash
brew install --cask input-source-pro

或者去官网下载

Input Source Pro - 自动切换输入法加上适时的提示,让每一次输入都游刃有余

一些配置

image.png

image.png

DropOver

一般。相当于给你一个 buffer 复制粘贴文件

但是!这软件免费版移动文件到 buffer 里要先等 3 秒,呃呃

不过还是很好用的

Dropover - Easier Drag and Drop on your Mac.

RunCat

哈基米!挂右上角看系统信息的

总之可爱就行

PicGo

神中神!无需多言

Bash
brew install picgo --cask

Scroll Reverser

翻转鼠标滚轮用的

Scroll Reverser for macOS

idea

我的 ideavim 配置:ideavimrc

vscode

Bash
brew install --cask visual-studio-code

我的 vscode + vscode vim 配置:vscode

neovim

我的 neovim 配置:neovim

最长回文子串

约 623 个字 38 行代码 1 张图片 预计阅读时间 3 分钟

题目链接: 5. 最长回文子串

题解链接:5. 最长回文子串 - 力扣(LeetCode)

中心扩散法

从每一个位置出发,向两边扩散即可。遇到不是回文的时候结束。举个例子,str=acdbbdaa 我们需要寻找从第一个 b(位置为 3)出发最长回文串为多少。怎么寻找?

  1. 首先往左寻找与当期位置相同的字符,直到遇到不相等为止。
  2. 然后往右寻找与当期位置相同的字符,直到遇到不相等为止。
  3. 最后左右双向扩散,直到左和右不相等。如下图所示:

image.png

每个位置向两边扩散都会出现一个窗口大小(cur_len)。如果 cur_len > length(用来表示最长回文串的长度)。则更新 length 的值。

因为我们最后要返回的是具体子串,而不是长度,因此,还需要记录一下 length 时的起始位置(start),即此时还要 start = left。

Python
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if s is None or len(s) == 0:
            return ''
        n = len(s)
        start = length = 0
        for i in range(n):
            left, right, cur_len = i - 1, i + 1, 1
            while left >= 0 and s[left] == s[i]:
                left -= 1
                cur_len += 1
            while right < n and s[right] == s[i]:
                right += 1
                cur_len += 1
            while left >= 0 and right < n and s[left] == s[right]:
                left -= 1
                right += 1
                cur_len += 2
            if cur_len > length:
                length = cur_len
                start = left + 1
        return s[start:start+length]

动态规划

中心扩散的方法,其实做了很多重复计算。动态规划就是为了减少重复计算的问题。动态规划听起来很高大上。其实说白了就是空间换时间,将计算结果暂存起来,避免重复计算。作用和工程中用 redis 做缓存有异曲同工之妙。

我们用一个 boolean dp[l][r] 表示字符串从 i 到 j 这段是否为回文。

试想如果 dp[l][r]=true,我们要判断 dp[l-1][r+1] 是否为回文,只需要判断字符串在 (l-1) 和(r+1) 两个位置是否为相同的字符。

进入正题,动态规划关键是找到初始状态和状态转移方程。

初始状态,l=r 时,此时 dp[l][r]=true。

状态转移方程,dp[l][r]=true 并且 (l-1) 和(r+1) 两个位置为相同的字符,此时 dp[l-1][r+1]=true。

Python
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if s is None or len(s) == 0:
            return ''
        n = len(s)
        start = end = 0
        length = 1
        dp = [[False] * n for _ in range(n)]
        for r in range(n):
            for l in range(r):
                if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
                    dp[l][r] = True
                    if r - l + 1 > length:
                        length = r - l + 1
                        start, end = l, r
        return s[start:end+1]

if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]): 这个判断条件的含义是

1. s.charAt(l) == s.charAt(r)

这一部分表示:当前字符串左右两端的字符是否相等

  • 如果 s[l] 和 s[r] 不相等,那么从 l 到 r 之间的子串显然不可能是回文串,因此直接跳过后续判断。

  • 如果相等,就进一步判断该子串中间部分是否是回文,从而确定整个子串是否是回文串。

2. (r - l <= 2 || dp[l + 1][r - 1])

这一部分表示:在两种情况下,从位置 l 到 r 的子串可以被确认是回文串

(1) r - l <= 2

如果 r - l <= 2,说明 l 和 r 之间最多只有 0 个或 1 个字符,这种情况下:

  • s[l] == s[r] 就足以判断该子串是回文串了,因为中间的部分要么为空(r - l = 1),要么只有一个字符(r - l = 2)。

  • 示例:对于 aba、aa,只需要两端相等即可确认它们是回文。

(2) dp[l + 1][r - 1]

如果 r - l > 2,说明 l 和 r 之间至少隔着两个字符,那么子串 [l+1, r-1] 是否是回文就变得重要。

  • dp[l + 1][r - 1] 是一个动态规划数组,记录从位置 l+1 到 r-1 的子串是否是回文。

  • 如果 dp[l + 1][r - 1] == true,说明该子串是回文串,再加上 s[l] == s[r],可以确认 [l, r] 也是回文串。

  • 如果 dp[l + 1][r - 1] == false,那么中间部分不是回文,即使两端字符相等,也无法形成回文串。

手撕快速排序

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

题目连接: 912. 排序数组

代码 (三路快排)

Python
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        self.quick_sort(nums, 0, len(nums) - 1)
        return nums

    def quick_sort(self, nums: List[int], left: int, right: int) -> None:
        if left >= right:
            return
        le, gt = self.partition(nums, left, right)
        self.quick_sort(nums, left, le - 1)
        self.quick_sort(nums, gt, right)

    def partition(self, nums: List[int], left: int, right: int):
        random_index = random.randint(left, right)
        nums[random_index], nums[left] = nums[left], nums[random_index]
        pivot = nums[left]

        # 循环不变量:
        # [left, le - 1] < pivot
        # [le, i] = pivot
        # [gt, right] > pivot
        le = left
        gt = right + 1
        i = left + 1
        while i < gt:
            if nums[i] < pivot:
                nums[i], nums[le] = nums[le], nums[i]
                le += 1
                i += 1
            elif nums[i] == pivot:
                i += 1
            else:
                gt -= 1
                nums[i], nums[gt] = nums[gt], nums[i]
        return le, gt

三路快排

思想:把整个数组分成三个部分,引入两个指针,le (less equal) 和 gt (great than)

image.png

此时有:

  1. nums[left, le - 1] 均小于 V
  2. nums[gt, right] 均大于 V

初始值:

  • le = left
  • gt = right + 1

遍历指针 i 从 left + 1 开始

  1. 遇到比 V 小的,交换 (le, i),le、i 均后移一位
  2. 遇到等于 V 的,不用交换,i 后移一位
  3. 遇到比 V 大的,gt 前移一位,交换 (gt, i)
    • 注意:此时 i 不能后移,因为交换过来的 nums[gt] 之前未看过

现在考虑退出循坏的条件,i 碰到 gt 即可

不要取 "=",因为 i 没看过,表示下一个要看,gt 的值都看过了,故 while i < gt

循环停止时

image.png

此时有:

  1. nums[left, le - 1] 均小于 V
  2. nums[gt, right] 均大于 V
  3. nums[le, gt - 1] 均等于 V

返回 le, gt, 并回到 quick_sort 函数

  • 递归调用左区间 [left, le - 1]
  • 递归调用右区间 [gt, right]
  • 直到排序完成

K 个一组翻转链表

约 138 个字 36 行代码 预计阅读时间 1 分钟

题目链接: 25. K 个一组翻转链表

Python
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        '''
        pre 是这次翻转后的头节点
        p0 是上一次翻转的尾节点
        nxt = p0.next 是这次翻转前的头节点/这次翻转后的尾节点
        cur 是下一次翻转前的头节点
        在一次翻转完成之后
        nxt.next = cur 这一次翻转的尾节点应指向下一次的头节点
        p0.next = pre 上次翻转的尾节点应指向这次翻转的头节点
        p0 变为这次翻转后的尾节点
        '''
        n = 0
        cur = head
        while cur:
            cur = cur.next
            n += 1
        p0 = sentinel = ListNode(next=head)
        pre, cur = None, head
        while n >= k:
            n -= k
            for _ in range(k):  
                nxt = cur.next
                cur.next = pre
                pre = cur
                cur = nxt
            nxt = p0.next
            nxt.next = cur
            p0.next = pre
            p0 = nxt
        return sentinel.next

pre 是这次翻转后的头节点

p0 是上一次翻转的尾节点

nxt = p0.next 是这次翻转前的头节点/这次翻转后的尾节点

cur 是下一次翻转前的头节点


在一次翻转完成之后

nxt.next = cur 这一次翻转的尾节点应指向下一次的头节点

p0.next = pre 上次翻转的尾节点应指向这次翻转的头节点

p0 变为这次翻转后的尾节点

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,否则无法生效

查看远端仓库

ArchLinux安装与配置

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

安装

我是跟着下述教程安装的,体验下来并不难 archlinux 基础安装 | archlinux 简明指南

我个人不是很推荐第一次安装用archinstall,用起来不是很舒服...(看个人吧)

安装成功!系统信息如下:

1f11b2036d0a3e1b5d0790cb4b84588c_720

[解决] grub 找不到 Windows 引导

背景如下:

我的 ArchLinux 安装在一块新买的固态硬盘上,我个人认为是这个原因导致其无法找到 Windows Boot,即 运行命令 grub-mkconfig -o /boot/grub/grub.cfg 后,在 grub 界面只能找到 ArchLinux 引导但没有 Windows

排查流程如下:

运行命令 fdisk -l 查找 WindowsEFI 分区

cd3acee020854d26b7e41660c946db16

观察到 WindowsEFI分区位于 /dev/nvme0n1p1 目录下

运行命令 mount /dev/nvme0n1p1 /mntWindows EFI 挂载到 /mnt

运行命令 lsblk 查看是否正确挂载

1abbd9d2c00c07c241ddeca5f2a668f9

运行命令 os-prober 发现 Windows 引导

运行命令 grub-mkconfig -o /boot/grub/grub.cfg 生成 grub 配置文件

e7aa8d1ce4ebc6e5e972a16b405b71f3

最后grub 成功发现 Windows 引导,问题成功解决!!!

安装NVIDIA显卡驱动

查看显卡

Bash
lspci -k | grep -A 2 -E "(VGA|3D)"

安装驱动

Bash
sudo pacman -S nvidia nvidia-utils nvidia-settings
Bash
sudo nvim /etc/default/grub

GRUB_CMDLINE_LINUX中添加nvidia_drm.modeset=1

Bash
sudo grub-mkconfig -o /boot/grub/grub.cfg
Bash
sudo nvim /etc/mkinitcpio.conf

MODULES中加入nvidia nvidia_modeset nvidia_uvm nvidia_drm

kmsHOOKS中去掉

Bash
sudo mkinitcpio -P

reboot 重启

nvidia-smi 验证是否安装成功

安装Hyprland

Bash
1
2
3
4
sudo pacman -S hyprland kitty waybar
sudo pacman -S sddm
sudo pacman -S ttf-jetbrains-mono-nerd adobe-source-han-sans-cn-fonts adobe-source-code-pro-fonts
sudo systemctl enable sddm
Bash
1
2
3
4
5
6
7
vim ~/.config/hypr/hyprland.conf
#添加NVIDIA环境变量
env = LIBVA_DRIVER_NAME,nvidia
env = XDG_SESSION_TYPE,wayland
env = GBM_BACKEND,nvidia-drm
env = __GLX_VENDOR_LIBRARY_NAME,nvidia
env = WLR_NO_HARDWARE_CURSORS,1

执行完上述命令且无报错后,reboot 重启

以下是 Hyprland 的基本操作

  • Win+Q 开启终端
  • Win+C 关闭窗口
  • Win+R 呼出菜单
  • Win+数字 切换桌面
  • Win+Shift+数字 将当前窗口移动到对应工作区
  • Win+鼠标左键 拖动窗口
  • Win+鼠标右键 调整窗口大小
  • Win+V 让窗口浮动出来

安装基础组件

  1. 安装输入法
Bash
1
2
3
4
5
sudo pacman -S fcitx5-im # 输入法基础包组
sudo pacman -S fcitx5-chinese-addons # 官方中文输入引擎
sudo pacman -S fcitx5-anthy # 日文输入引擎
sudo pacman -S fcitx5-pinyin-moegirl # 萌娘百科词库。二刺猿必备(archlinuxcn)
sudo pacman -S fcitx5-material-color # 输入法主题

通过 vim 创建并编辑文件 ~/.config/environment.d/im.conf

Bash
vim ~/.config/environment.d/im.conf

在文件中加入以下内容并保存退出

Text Only
1
2
3
4
5
6
# fix fcitx problem
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
SDL_IM_MODULE=fcitx
GLFW_IM_MODULE=ibus
  1. 配置输入法
Bash
fcitx5-configtool
  1. 安装paru
Bash
1
2
3
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si
  1. 安装代理
Bash
paru -S clash-verge-rev
  1. 安装rofi
Bash
sudo pacman -S rofi
  1. 安装google和vscode
Bash
paru -S google-chrome
sudo pacman -S code
  1. 配置声音
Bash
sudo pacman -S pavucontrol-qt
pavucontrol-qt

最终效果

帅!