记录一次深夜的技术漫谈,关于工具、系统与如何优雅地“偷懒”。
原始内容
点击展开
聊天记录整排——git,linux,学习路径和一点鼓励.txt
以下是素材,都是我的发言,这个结构很简单,分几个标题就好了
Git
git init会建立起一个仓库,不要去动生成的.git文件,它能且仅能被git管理
现在,你的树根建立好了,(刚开始,是一个虚的,没有任何文件的根)用git add 来提交文件到暂存区(暂存区是一个你选择文件先放着的地方),然后git commit,你的HEAD往前走一步,你的树延长到下一个节点,然后这个节点就保存着commit的文件信息了。commit也可以附加一些信息
现在你可以单调地加文件把这一切累计上去,这是一条线,就很单调简单。
于是,我们有git reset来回溯你的情况(有三种模式,因为你有三个区域)
这是一棵树,只是一条线,我们可以git log查看这线上的日志,git reflog看头指针的指向,git diff看看差异,但只有一条线就太无聊了,于是我们有了git branch创建分支,git switch在分支切换。
你会觉得分支是一个很重要的节点,于是你switch可以直接丢分支名去跳到branch末尾而不用去记commit id,与此类似的纪念碑是tag
两块分支两颗树有统一的根,后面可能需要合并,合并有两种,一种merge让分支前进一步,把两个分支当父亲并在一起,有时需要解决conflict然后commit,rebase直接找到公共祖先然后把一条分支接到他后面。
git是一个分布式仓库,你需要和别人的tree合作,通过git clone把别人的树拉下来,自己做点修改形成你自己的世界,接下来,你就多了一个upstream和origin的绑定了(是的,git clone会来两颗树,一颗你现在能看到的,另一颗是远程clone的绑定),后面你git fetch都会改变远程绑定的树。你可以用git pull直接把远程树fetch下来后直接merge(是的 pull就是fetch➕merge,当然你config也能改成rebase)
git管理文件是很多的,可能会内嵌别的库但你不想管理,于是就有submodule,对于大文件还有git-lfs。
小技巧,stash临时存放,cherry-pick选择性应用commit
首先放平心态,大部分运维做的日常就是会比你多拨弄几个按钮,能够开关一些选项把电脑调节成好用的状态。至于网络,路由,性能调优,内核优化,devops,灾备这些领域才需要专业知识,但对一般的应用程序部署,只要会配环境会解决报错就行了最深不过反编译和问社区,或者,加入伟大的nix打包大队,一次打包,所有人受益,看一次nix,直接enable就行。
Linux
proc,sys,dev,这几个文件夹可以看看
usr
usr/local
把bash换成zsh可以试试
systemd的unit可以管理很多东西,挂载点,网络,socket,service,还可以设置cgroups
sudo和su不一样,sudo会分配一个tty,这个tty的命令受到限制
w看看做什么
history,:!
bash是可编程的
环境变量很有意思
whoami,passwd,/etc/password,/etc/groups……
iptables直接看清楚防火墙流向
ip是一个命令底下有很多有趣的子命令
bash的字符处理和语法
coreutils里面还有些有用的字符处理命令
查询的grep,查文件的find,找命令在哪的which,把字符转换的tr,切割的cut,读取文件并且把多个文件内容简单连接起来的cat,输出的echo,再复杂点的处理awk也可以用用。配合管道用威力无穷
传入参数$02……
systemd提供很多好用的命令
systemctl ,journalctl hostnamectl……
ssh支持端口转发,不分配tty登录,跳板机,keepalive等诸多参数。ssh-keygen可以做简单的密钥生成和签名
dd 读取和写入
file的类型不止regular file,还有directory socket link char block 反正实现文件操作需要的那几个函数就是file。有一个inode可以了解下
Linux底下一个文件即使被读写,也不会像Windows那边被锁定,直接删掉,只是让引用计数减1,减到0才删除。
kmod动态加载内核模块
软件包管理器和它对应的配置文件
/etc/pacman是archlinux的
记得Ubuntu是/etc/apt?反正翻翻etc系统可以配置什么软件包就清楚了
翻翻sys系统有哪些东西,可以写哪些属性就清楚了
文件系统,tmp是tmpfs,在内存里,读写速度快关机清
ls cd touch cp mv ln 输出输出重定向 here document
lshw可以查看所有硬件
ls开头的东西挺多的
不过也有一些命令行增强的东西
tree不是coreutils,但是可以下
还有一个matrix还是什么的,可以有很酷的界面
watch会隔一段时间执行一次命令然后给你看结果
把东西用管道接到less或more里面分页查看(/开始查找 n查到下一个,shift➕n上一个,空格下一页 )
很多程序都有man作为手册,应该可以man看看具体用法
解压压缩,tar,unzip,zip,gunzip,应该够用了,大不了apt install一个7z
压缩和归档是两回事,不过现在经常是一回事
proc底下有些很好玩的,比如environ看到所有环境变量,cmdline看到参数,mem还是什么的甚至看到内存,self指向所有程序的自己。fd显示有的所有文件描述符(0是stdin,1是stdout,2是stderr),还可以看到cgroups,好像还有selinux上下文?
读写内存映像甚至能动态修改执行的代码(比如把Python改个几行)(不过需要root而且系统好像还有限制)
看内存占用用top就好了,ps看所有进程,不用到proc底下一个个翻
vim的操作可以快如闪电,核心概念 修饰语+行为+对象
shebang#! 快速指定一个文本文件的解释器
不过不会vim还是nano好,sed虽然快但不直观,不写脚本用nano也不是什么问题
消息队列dbus挺不错的。但有自己一套的二进制调试工具,不过直接读写映射的socket也不是不行。systemV的消息队列就,呃,把它当进程IPC吧。
Linux下以.开头的文件默认隐藏,所以知道一些命令的参数很重要,ls -al,很多参数本身就是命令的重要组成部分
bash的逻辑运算符支持短路,意思是已经知道结果了就不会继续
比如&&表示与运算
只要前面那个不成立,那么后面的就不会执行,在简化脚本时有奇效
不过注意,这个并不是基于程序的返回值,而是基于命令是否成功
所以,return 0相当于true,return其他值相当于false
&并不是按与运算,就像|不是按位或而是管道(虽然||是逻辑运算符)
&代表把这个命令放到后台执行,这样你前台就可以干别的事了,jobs看看你后台多少job,bg后台执行,fg前台执行
但是后台是终端的后台,不是整个系统的后台,要想让程序在终端退出后继续进行,tmux终端复用器,或者disown消除你这个终端和程序的联系(一般会被pid 1收养,让pid 1管理这个进程,呃,这里涉及到了Linux如何管理进程的,父进程可以对子进程干很多事情的),或者nohup让进程不接收hang up信号
kill可以发送信号给进程,让他们退出或者干别的
终端的一些快捷操作 Ctrl➕a回到开头(等同home),Ctrl➕d表示停止输入,相当于EOF,有些时候很有用,Ctrl➕C发送terminate命令(不是kill),Ctrl➕e跳到结尾,alt➕f往front跳一个单词(就是往end那里走),alt➕b往回跳(往开头走)
Ctrl➕f和Ctrl➕b类似,但是只走一个字符,现在一般都用←→代替了吧
!开头在终端中一般有特殊意义,可以快速调用之前的命令
如果有一台真的Linux电脑,还得了解下swap分区,grub,以及REISUB向内核通信,Ctrl➕alt➕F1-F6切换控制台,flatpak,桌面环境(wayland,x11),wayland还有好玩的compositor和平铺式桌面管理器,xdg目录规范,xdgportal,xdgmimetype
df du查看硬盘使用情况
mkfs mount umount eject
scp ftp rsync文件传输和备份
这部分可能需要整理和纠错一下
学习路径和一点鼓励
如何从C++的黑框框到好看的应用程序
如果是小程序的话,微信小程序简单的开发纯人力方案翻翻文档
我觉得没开发过小程序的大概半天能出来一个demo,然后根据需要什么去深度获取所需,两三天应该够。
当然,还有各种合规性问题,什么备案啦。
主要是微信把账号系统,统一验证什么的都做好了,虽然生态垄断和api老久让人讨厌,但不得不说有些地方的确有他自己的优势
讨厌微信的话,看看PWA,微信本质就是吃了当时PWA没赶上的市场空缺。单页网页应用技术可以写出很漂亮的页面和交互,很有成就感,而且api比微信灵活,对于和系统交互不多的小程序类的引用,PWA能提供更自由更方便的选择,缺点就是可能要自己去接入支付和账号的api,对于一些要快速出成果地项目这可能是额外的复杂度。
如果要安装到操作系统上,WASM,WASI是比较新的方向,在跨操作系统上建立一个统一的runtime,并提供比PWA更多的接口和更快的速度和绑定,但是不太成熟,一个下位平替是electron或tauri,本质还是web技术
再往下沉,传统原生开发能获得最大的自由度,速度和复杂度。但也是开发耗费心力最多的。就是不经过太多中间层直接面对你需要的平台开发。一般来说平台对api的封装会比较原始,虽然灵活但是要做的更多非核心业务的事情可能就要多了。
就Android来说,你要额外了解service,bind,permission,kotlin,ART之类的核心概念,有时候是额外的噪声。
Windows有win32 api和MFC这种老东西,也有.net,WINUI,以及Qt这种跨平台方案,深入地讲,还得了解句柄,对象模型
如果对Linux开发有兴趣,POSIX标准设计的接口我认为是比较清晰合理的,跨平台UI框架做得也不错,但比起.net封装好的一堆函数,感觉离业务层更远了(虽然系统管理,容器隔离抽象,虚拟网络,内核监控之类的可以说是一绝,但桌面应用就得学会自己去组合各种库,而且开发理念也鼓励这么做。不像Windows有官方指定的标准,有时候技术路线选择也是一种抽象泄露和认知负担)
再往下沉,传统原生开发能获得最大的自由度,速度和复杂度。但也是开发耗费心力最多的。就是不经过太多中间层直接面对你需要的平台开发。一般来说平台对api的封装会比较原始,虽然灵活但是要做的更多非核心业务的事情可能就要多了。
就Android来说,你要额外了解service,bind,permission,kotlin,ART之类的核心概念,有时候是额外的噪声。
Windows有win32 api和MFC这种老东西,也有.net,WINUI,以及Qt这种跨平台方案,深入地讲,还得了解句柄,对象模型
如果对Linux开发有兴趣,POSIX标准设计的接口我认为是比较清晰合理的,跨平台UI框架做得也不错,但比起.net封装好的一堆函数,感觉离业务层更远了(虽然系统管理,容器隔离抽象,虚拟网络,内核监控之类的可以说是一绝,但桌面应用就得学会自己去组合各种库,而且开发理念也鼓励这么做。不像Windows有官方指定的标准,有时候技术路线选择也是一种抽象泄露和认知负担)
总之,根据自己的业务需要,挑选合适的抽象层,然后承担相应的认知负担和抽象泄露,取得一个平衡,会有不同的开发出能看的应用地时间。
至于上架应用市场,只有MVP是不够的,有些会有合规性要求,但这方面我就不太清楚了
什么备案,备案,许可证,营业执照,接入地sdk限制,隐私协议
开发工具,
llm agent能够穿透部分抽象层(虽然更容易抽象泄露),并解决一些烦人的edge case的保护性代码和wrapper,document撰写和注释。
对于中小型项目,我觉得Git,Trae,opencode真的够了。大型的编排器我还没看到什么成果。
另外,小心陷入复杂度陷阱和第二系统困境,做到有时比做完美重要,要敢于对非核心需求说不
vibe当然是可以的,agent能力已经很强了,我有一个朋友靠vibe写了几个有趣的小游戏作为他blog的一些”点缀”
不复杂的部分,就像是blog每页的小游戏,或者他写的一些小说故事里面为了沉浸感加入的交互式的游戏
至少我这边看到的,几句话生成应用的web的上限大概在这
codex,opencode,或者直接让Gemini生成
但是碰到部署到具体的平台上,该用什么工具,该了解什么概念一个不少,就是说,要描述清楚自己需求
分成几个页面,每个页面有哪些按钮,哪些卡片,哪些东西要从服务器那边拿到,服务器那边约定按照什么格式去拿,服务器后端选择什么语言,app的前端已经确定好跨平台框架了,那么跨平台框架有哪些概念(消息循环,渲染,优先级,这些都是ai容易出错而且没法从本质的角度解决的地方,需要人去介入,不然ai会绕圈子绕半天)
所以,vibe固然有他自己优势的区间,但从vibe到真正的工程,到spec coding,文档驱动编程,除了核心业务逻辑之外,还是需要了解一点基本的知识的。
主要是框架的核心概念和分层,数据格式和网络。
就flutter来说,Google官方有手把手的教程教你怎么跑起来。
了解大概的风格就好了,知道哪些可以做哪些需要别的框架帮助做就好了
接着关于里面的各种函数名,非核心的数据类型,完全可以把flutter官方文档丢给ai然后根据描述生成
vibe到spec的途径就是不要被ai带偏
网络的话,web前后端看看MDN,了解一些错误码知道是怎么回事,以及了解服务器上该怎么看日志。
JSON,grpc,tcp,http,稍微知道格式是怎么样的怎么用,出错是哪里的错误就行了。
az,总的来说
我们人本主义一点,不搞苦难哲学那一套,遵循最小惊讶原则和人体工学设计,把时间更多地留给业务逻辑,或者再现实点,多睡会觉,多陪陪家人。不是说得过且过或者将就去欠技术债,生态和灵活度带来的麻烦和开发效率做权衡,工程的艺术。
这边主要是一个资源分享,当然也要整合纠错。
一、 Git:从“一棵树”到“一片森林”
Git 远不止是 git commit -m "fix bug"。把它想象成一棵可以自由生长的树,你的每一次操作,都是在塑造它的形态。
1.1 根基:仓库与提交
一切始于 git init。这个命令在你脚下埋下了一颗种子——.git 目录。切记:这是 Git 的“大脑”,只可远观,不可手动亵玩。
git add:将文件放入“准备区”(暂存区)。好比为拍照挑选要穿的衣服。git commit:按下快门,生成一个永久的快照(节点)。HEAD指针随之向前一步,你的树长出了一节。用-m给这个快照加上注释,是为后人留下的路标。
此时,你的项目历史是一条简单的直线。可以用 git log 回顾旅程,用 git diff 查看变化。
1.2 分叉与穿梭:分支的艺术
直线历史太无聊?是时候分叉了。
git branch <name>:从当前节点生出一根新的枝桠(分支)。git switch <branch>:在枝桠间跳跃。分支名是你设置的“纪念碑”,比冷冰冰的 commit id 好记多了。类似的纪念碑还有tag,常用于标记版本。
1.3 融合:Merge 与 Rebase
两根枝桠终要汇合。合并有两种哲学:
Merge(合并):召开家庭会议。把两个分支作为新节点的“父母”,生成一个全新的合并提交。如果修改冲突了(conflict),你需要充当“和事佬”手动解决,再完成提交。
Rebase(变基):让其中一根枝桠“穿越”到另一根枝桠的起点后面重新生长。结果是历史变成一条更整洁的直线,但“改写历史”需谨慎。
1.4 与世界连接:远程协作
Git 是分布式的。git clone 不仅复制了代码,还为你建立了一个叫 origin 的“远程望远镜”(远程仓库)。
git fetch:用望远镜看看远方(origin)的树长成啥样了,但不动你本地的树。git pull=git fetch+git merge。直接把远方的变化拉下来合并。你也可以配置成rebase模式。git push:把你本地树的生长推送到远方,让世界看到。
1.5 进阶工具箱
git stash:临时把手头的工作打包藏起来,清空舞台去处理急事。git cherry-pick:精心挑选某个分支上的特定“果实”(提交),嫁接到当前分支上。.gitignore:告诉 Git 哪些文件是“隐形”的,不必跟踪。git reset:时间回溯器(谨慎使用!),根据模式(--soft/--mixed/--hard)决定回溯到哪一步。
二、 Linux:在终端里构建你的王国
Linux 不是一堆神秘命令的集合,而是一个高度透明、一切皆文件的操作系统。理解它,你就能从用户晋升为管理员。
2.1 探索系统核心目录
/proc,/sys,/dev:这不是普通的文件夹。它们是通往内核和硬件的“实时接口”。在这里,你可以查看进程信息(/proc/[pid])、调整内核参数(/sys)、与设备对话(/dev)。/usr与/usr/local:前者是系统安装的软件,后者是你自己编译或安装的软件的地盘。分清界限,便于管理。
2.2 Shell:内核和你之间的界面
把
bash升级成zsh(配合 Oh My Zsh),终端体验会获得质的飞跃。管道
|是 Linux 的哲学精髓:让简单命令通过组合完成复杂任务。例如:ps aux | grep nginx | wc -l。环境变量:程序的运行上下文。
echo $PATH看看系统去哪找命令。快捷键:
Ctrl+A(行首),Ctrl+E(行尾),Alt+F/B(按单词移动),Ctrl+R(历史搜索)。掌握它们,告别鼠标手。
2.3 系统管理与洞察
systemd:现代 Linux 的“大管家”。systemctl(管理服务)、journalctl(查看日志)、hostnamectl(主机信息)是它的左膀右臂。sudovssu:sudo以你的身份临时提权执行命令;su是直接切换用户身份。进程管理:
ps(快照),top/htop(动态监视),kill(发送信号)。记住kill -9是最后的强制手段。网络工具:
ip命令(取代老旧的ifconfig)功能强大;ss(取代netstat)查看套接字;iptables/nftables是防火墙的基石。
2.4 文本处理:数据炼金术
grep:文本搜索之王。awk&sed:文本处理的瑞士军刀。awk擅长列处理,sed擅长流编辑。学习曲线陡峭,但威力无穷。find:根据各种条件(名称、类型、时间、大小)查找文件。tr,cut,sort,uniq:简单的文本流转换工具,常与管道联用。
2.5 文件与存储
一切皆文件:普通文件、目录、设备、套接字……在 Linux 眼里都是文件描述符。
lsof命令可以查看进程打开了哪些文件。链接:
ln -s创建软链接(快捷方式),ln创建硬链接(同一文件的别名)。文件系统:
df看磁盘用量,du看目录大小。/tmp通常是内存文件系统(tmpfs),速度极快。
2.6 实用技巧与小工具
ssh:远不止远程登录。端口转发、跳板机、免密登录(SSH Key)是运维必备技能。tmux或screen:终端复用器。让你的会话在断开连接后依然运行。man命令:你最好的老师。遇到不懂的命令,man [command]是第一选择。/etc目录:系统的配置文件中心。想改什么全局设置,多半在这里。
三、 学习路径与一点鼓励:从黑框框到“好看的应用”
如何把 C++ 控制台里的“Hello World”变成一个有界面、能交互的真正的应用程序?这是一条关于“选择”和“权衡”的路。
3.1 起点:小程序与快速原型
如果你只是想快速做个东西出来,看看效果,那别想太复杂。
微信小程序是个现成的选择。它把账号、支付、分享这些麻烦事都给你包圆了,虽然生态封闭、API 有时候让人想骂街,但架不住它快。一个没做过的人,照着文档半天能搓出个 demo,两三天能搞出个能看的东西。代价就是你得接受它的规矩,备案、审核这些破事一个都少不了。
讨厌微信?看看 PWA。这玩意儿本质上就是个加强版的网页,但能装到手机桌面上,体验接近原生 App。微信小程序当年就是吃了 PWA 还没成熟的空子。PWA 自由,API 灵活,写个漂亮的单页应用很有成就感。缺点就是,账号系统、支付这些你得自己找第三方接,或者自己搭后端,对想快速出活的项目来说,这是额外的复杂度。
3.2 下沉:跨平台桌面与移动
当你需要更“像样”的应用,需要安装到系统里,能调用更多系统能力的时候,就得往下走一层。
Electron 和 Tauri 是这条路上的代表。它们本质上还是用 Web 那套技术(HTML, CSS, JS)来写桌面应用。Electron 成名早,VSCode、Slack 都是它写的,但打包出来体积感人。Tauri 是后起之秀,用 Rust 做后端,打包出来小得多。它们的共同点是,你还是在写“网页”,只是这个网页能调用一些系统 API,并且被包装成了一个独立的 .exe 或 .app。
再往下,就是真正的 跨平台原生框架,比如 Flutter 和 React Native。它们的目标是让你用一套代码写出 iOS、Android、甚至桌面和 Web 都能跑的应用,而且性能接近原生。你需要学习 Dart(Flutter)或 React 语法(RN),以及框架自己那套 Widget 或组件生命周期概念。这一步,你开始真正离开浏览器的舒适区,接触到更底层的渲染和线程模型。
3.3 深水区:纯原生开发
如果你追求极致的性能、完全的系统 API 访问权限、或者就是想搞明白东西到底是怎么跑起来的,那就得跳进原生开发的深水区。
Android:Java/Kotlin,Activity,Service,Broadcast Receiver,Content Provider,还有那套权限系统和 ART 虚拟机。想搞点复杂的,还得碰 JNI。
iOS:Swift/Objective-C,UIKit/SwiftUI,View Controller 生命周期,Auto Layout,还有 App Store 那套严格的审核。
Windows:从古老的 Win32 API 和 MFC,到现代的 .NET 和 WinUI。你得理解窗口句柄、消息循环、COM 组件这些概念。
Linux 桌面:GTK、Qt 这些工具包。这里没有“官方钦定”的框架,自由也意味着选择困难。你得自己组合各种库,但 POSIX 接口的清晰和一致性能给你不少安慰。
这一层的共同点是:自由度和复杂度成正比。你能控制一切,但你也得为一切负责。很多在高层框架里被隐藏掉的细节(内存管理、线程同步、事件循环)在这里都会赤裸裸地摆在你面前。
3.4 未来与权衡:WASM、AI 与工程现实
最近总有人提 WebAssembly(WASM) 和 WASI,说这是“一次编译,到处运行”的真正未来。理论上没错,它能让你用 C++、Rust 等语言写高性能代码,在浏览器、服务端甚至操作系统(通过 WASI)里跑。但这玩意儿还在快速发展,生态和工具链远没到成熟的地步,现在入场,多少有点当先驱的意思。
然后就是 AI。现在的大语言模型(LLM)当个“副驾驶”是真不错。生成模板代码、写写注释、解决某个具体的语法错误、甚至根据你的描述生成简单的函数,都很在行。它能帮你穿透一些抽象层,减少写那些繁琐的样板代码的时间。
但是,别指望 AI 能帮你做架构决策,或者理解你业务的核心逻辑。框架的核心概念(比如 Flutter 的 Widget 树、React 的状态流)、系统的分层设计、数据格式的约定、网络通信的模型……这些必须你自己心里有数。AI 很容易在它不懂的地方开始胡编乱造,或者用复杂的方式解决一个简单问题。Vibe 编程可以出原型,但出不了可维护的工程。
3.5 核心建议:平衡的艺术,以及一点人本主义
警惕“第二系统效应”:别一开始就想着设计一个完美无瑕、能应对所有未来需求的架构。先搞出一个 MVP(最小可行产品),让它能跑起来。很多时候,你在做的过程中才会真正明白你需要什么。
为“抽象泄露”做好准备:任何框架都在隐藏底层的复杂性,但总有藏不住的时候。你选的抽象层越高,未来遇到“泄露”(比如性能瓶颈、某个诡异的内存问题)时,需要回头补的底层知识就可能越突然、越痛苦。
关注核心,放过边角:把主要精力花在让你的应用独一无二的业务逻辑上,而不是没完没了地折腾构建工具、美化配置脚本、或者追求某种代码风格的“纯粹性”。用 Git、用 Issue 跟踪、写清晰的 README,这些基础工程实践带来的收益,远大于在次要细节上的过度优化。
人本主义一点:写代码是给人看的,包括六个月后的你自己。遵循“最小惊讶原则”,起个能看懂的函数名,写两句注释解释为什么这么做,而不是只解释做了什么。技术的终极目的不是炫技,而是解决问题,并让人(包括你自己)有更多时间去生活——去睡觉,去读书,去陪家人,去干点代码之外让你觉得活着真好的事。
3.6 最后的碎碎念
从在终端里敲出第一个 git init,到在 Linux 里折腾各种配置,再到纠结该用 Flutter 还是直接撸原生……这条路没有标准答案,也没有终点。
你学 Git,是在学习如何管理复杂、如何与时间线共舞。 你玩 Linux,是在学习如何理解系统、如何从底层掌控你的工具。 你选技术栈,是在一次次地做权衡,用认知负担去交换开发效率,在自由度和可控性之间寻找那个让你舒服的平衡点。
这过程里会有无数个“我操这玩意儿怎么又坏了”的时刻,但也会有“诶,居然跑通了”的微小快乐。
所以,别太焦虑。选一条看起来能走通的路,先弄出点能跑的东西来。剩下的,在路上慢慢学。
工程的艺术,有时候不在于用了多牛的技术,而在于用恰到好处的技术,把事情搞定,然后准时下班。