企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
解说: https://ihower.tw/git/ # 基础指令 1、安装 git + source tree 实现可视化 查看文件: ~~~ ls ~~~ 但有些时候文件是隐藏的,此时用到 ~~~ git ls -la ~~~ 即可查看隐藏文件 ~~~ mkdir README ~~~ ↑新建名为 README 的文件 ~~~ rm -rf README ~~~ ↑删除名为 README的文件 ~~~ git reset HEAD^ --hard ~~~ 还原上一个动作 #### setup:可进行一些 git 非常基础的预设。 ~~~ git config --global user.name "amy326" git config --global user.email "amy87326@163.com" git config --global color.ui true ~~~ 之后也可以输入 以下命令,在隐藏文件.gitconfig中直接设置 ~~~ vi ~/.gitconfig ~~~ 比如设置快捷键,用 vi 命令打开.gitconfig 文件以后,按I进入编辑模式,增加以下行: ~~~ [alais] ci = commit ch = checkout br = branch st = status ~~~ ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbdzam4w1j30e70560sx.jpg) # 显示修改的内容 ~~~ git diff git diff --staged ~~~ ↑git diff 可以显示在工作区中被修改电但还没放入暂存空间的内容 但如果已经 git add . 暂存了,则再输入git diff则不显示。此时要输入"git diff --staged" ~~~ git add README(文件名) ~~~ ↑则只对该文件进行暂存 ~~~ git add . ~~~ ↑将所有文件统统放入暂存中等待 commit ~~~ git log ~~~ ↑显示 commit 的时间和名字 ~~~ .cat README ~~~ ↑在屏幕上显示文件里面具体内容但不打开文件 ~~~ vi README(文件名) ~~~ ↑可以直接进入该文件中,再用 vi 命令进行编辑 按 esc 退出后,输入" :wq!" 即可存盘并退出。 ~~~ git status ~~~ ↑显示文档状态。详见《补充:Git 分区原理》 >可反悔: ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbeyg0hmgj30k3032751.jpg) ## 文件操作 #### 删除文件 ~~~ git rm aaa ~~~ ↑意思是在工作区中把名字叫aaa的文档删了并把这一情况记入stage暂存中 ~~~ rm aaa ~~~ ↑与上面的差别意思是只在工作区中删除 aaa,但还未将这一情况放入 stage 中。 #### 重命名 ~~~ git mv b BBB ~~~ ↑把名为b的文件改名成 BBB,并放入暂存中。 #### 复制文件 ~~~ cp BBB DDD ~~~ ↑ 把 BBB 复制一份名叫 DDD。 ## **反悔 revert** 如何把之前 commit 进去 git 的文件删除: 比如上一步执行了复制命令并已经commit 了,但突然不想复制: ~~~ git revert HEAD ~~~ ↑ 可以用 git revert 这个命令。后面的 HEAD 指的是最新的那次操作。如果是前一个,用HEAD^,前两个就用HEAD^^ > 但一般我们可以打开 source tree,用流水号码来执行。 比如上述,找到之前 commit 的文件,查看号码为e44f87e9c01…… 直接输入 ~~~ git revert e44f87e9c01 #不用全部打出来# ~~~ ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbflwc490j30oj0f3tbf.jpg) 此时git会自动新增又一个commit 来记录此次反悔(如图的‘Revert 'add DDD' ’)。 #### 如何查看这个号码 建议直接用source tree查看,但也可以在item 中输入 ~~~ git log --oneline ~~~ 就可以看到了。按:wq退出查看。 ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbfphxmvpj30e50ai3zn.jpg) ## 贴标签 一般可用于查找 ~~~ git tag foo ~~~ ↑给最新的那个 commit 贴一个叫 foo 的标签 ~~~ git tag AAA e44f87e9c01(号码) ~~~ ↑给号码为e44f87e9c01的 commit 贴一个叫 AAAd 标签 #### 删除标签 ~~~ git tag -d AAA #或git tag AAA -d# ~~~ #### 贴备注 ~~~ git tag CCC -m "hello" e44f87e9c01 ~~~ ↑给号码为e44f87e9c01的 commit 贴一个名字叫 CCC 的标签,并写一个备注叫“hello”。 ![](https://box.kancloud.cn/8c71fb70922a00ca700e4a80ae0b48f3_1051x619.png) ## 查看谁写了什么代码在哪个文件里 ~~~ git blame README ~~~ ↑可在 README 这个文件中查看谁写了什么东西。按 “:q” 退出。 ~~~ git blame README -L 100,10 ~~~ ↑从第100行开始往下查看10行。 ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbfzwfom0j30m8098756.jpg) ## **砍掉untracked的档案** 比如刚要删除git rm a + git rm b比较麻烦,可以直接 ~~~ git clean -n ~~~ 列出要清理的档案,再来 ~~~ git clean -f ~~~ 清理掉。 或者直接git clean -x 连在.gitignore里面的都统统清除。 其实效果等于 ~~~ git add . git stash #先把新文档全部暂存入 stage里面,再一次性 stash 清除# ~~~ ↑但其实,git stash 不是删除,而是先放在一个叫 stash 的地方。 ![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbq3nhuayj30l30ast9u.jpg) ## 设置.gitignore执行部分 commit 比如 touch rabish以后,rabish这个文档不想被 commit 进去,可以执行 ~~~ vi .gitignore ~~~ 在里面输入rabish 以后,这个文件就可以不被 commit 了。但要记得,.gitignore这个文件是要被 commit 才可以 ~~~ git add . git commit -m "Add .gitignore" ~~~ #### 空目录(空文件夹)不会被 commit 如果新建mkdir SSS,但里面什么内容都没有,那么 commit 的时候,这个文件是不会被记录的。 ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbgikgrrxj30jk01v3yq.jpg) 但有时候我们又需要 commit 一些空目录,此时用以下命令: ~~~ touch SSS/.gitkeep ~~~ 再进行 commit 的时候,就会把SSS这个空文件夹放进去了。 ## 分支 #### 开分支 ~~~ git checkout -b feature1 ~~~ #### 移动到分支 ~~~ git checkout 分支名 ~~~ 如果输入git branch 分支名,这是要新建的意思,要注意命令不用用错。 #### 显示有哪几个分支 查看分支 ~~~ git branch ~~~ 如果是在 github 上,用这个命令看不到,于是可以用 ~~~ git branch -r ~~~ ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbv038ccjj30j301f3yo.jpg) 显示已被合并的分支 ~~~ git branch -r --merged ~~~ #### 合并分支 一般是先到 master 主干以后,再把分支合进来 ~~~ git br master git merge feature1 ~~~ 如果commit分支中的内容后,又修改主干(**两次修改的是不同文件**),则 commit 时候会都保留,只不过有一个小节点。 ![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbgugrv1yj30d3025dfx.jpg) 但如果 feature 与 master 都对同一个文件进行修改,就会有大冲突,此时需要根据提示来解决才可以。 #### 编辑的都是同一个文件的同一行 比如新建分支feature2并修改 README文档使之第一行为hello ~~~ git ch -b feature2 vi README #假设此时文件时空的,我们在第一行输入 hello# git add . git commit -m "Update README 1" ~~~ 此时又不小心回到master主干并对同一个文件同一行进行编辑。(因为此时还没把第二个分支feature2合并进来主干,所以如果此时回到主干并打开 README 文件时,仍是空的) ~~~ git ch master vi README #此时看到的文件仍是空的,于是我们在第一行也输入文字 hi222# git add . git ci -m "Update README 222" ~~~ 此时在没有合并以前,分歧已经产生。 ![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbhbfug2sj30n702mwf0.jpg) 若在master中执行合并,则会提示错误:both modified: README ![](https://ws4.sinaimg.cn/large/006tNc79gy1fmbhffks0vj30k407jjt1.jpg) 打开这个档案后会发现有提示: ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbhlwtca4j30ik08gq3q.jpg) 此时只要保留真实想要的结果就可以。并且记得把大于号小于号等于号都去掉。再执行 ~~~ git add README #文件名,只要针对这个有冲突的进行保存就可# git commit #此时会跳出预设信息出来,确认一下,没问题后只要:wq!存档以后,就可以自动执行完成git merge# ~~~ ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbht4qvasj30mh01t3yy.jpg) #### 删除分支 如果已经 merge 成功以后,再执行分支删除,此时会显示只剩下 master 这个分支。但原来在 feature1分支中做的内容其实是被保留没有删除的。 ~~~ git branch fearure1 -d #或者 git br -d feature 也一样# ~~~ **强制删除** 如果你的这个分支还没被合并进来,那么执行大写D,就可以强制删除该分支,不用管是不是被合并。 ~~~ git br feature1 -D ~~~ ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbh0659abj30l6042mxu.jpg) ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbib9evvej30ma051409.jpg) #### 重命名分支 ~~~ git branch -m feature2 feature2b ~~~ ↑直接把名字叫 feature2 的分支重命名为feature2 **强制重命名** 如果是你命名到一个已经存在的名字,那么执行大写的M,则会强制覆盖掉已经存在的那个同名文件。 ~~~ git br -M feature2 feature2b ~~~ #### 人为制造流程图小突起 ~~~ git ch -b feature4 git ch master git merge feature4 --no-ff ~~~ 这样可以很方便看到差别。也可以清楚看到,几个 commit 是属于同一个 branch 的。 ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmblrgm38rj30m8024dgc.jpg) #### 合并部分 commit 到 master 比如我们在开分支feature6的时候,写了很多 commit,大部分暂时先不想合并到主干里面,但里面有一个 commit 比如是修改错别字,想先合并到主干里面才不会影响开发。此时可以用 cherry-pick 功能 ~~~ git ch master # 回到主干再操作# git cherry-pick c224fce9840 #这条commit的号码# ~~~ ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbma6azycj30mf0gj78j.jpg) ![](https://ws4.sinaimg.cn/large/006tNc79gy1fmbmboba72j30lj02owf5.jpg) #### 开分支注意事项 如果有冲突,则无法 merge。但此时可以先 commit,只要不push都可以慢慢解决冲突。 可使用 git reset, 或者用git stash。 或者使用git stash 先暂存下来,放在一个叫wip的地方。 ~~~ git stash ~~~ 要再次显示的话,可以 ~~~ git stash apply ~~~ 清除: ~~~ git stash clear ~~~ ![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbq3nhuayj30l30ast9u.jpg) ## 推送到远端仓库 一般使用https://github.com 来储存 git。 #### ssh 码设定 ssh 其实是一种加密方式,通讯协定,类似https:// 用来在你的计算机创建一个私钥id_rsa以及公钥id_rsa.pub。 ~~~ ssh-keygen -t rsa -C"amy87326@163.com" ~~~ ↑邮箱是 github 注册的邮箱。直接按三个回车即可,也不需要输入密码,因为如果现在输入,后续就会一直需要输入,很讨厌。 ~~~ cat ~/.ssh/id_rsa.pub ~~~ ↑显示你的公钥号,然后复制到github中新建一个 ssh 码,并新建一个新的repository。 此时可以推送了 ~~~ git remote add origin git@github.com:amy326/sandbox.git git push -u origin master ~~~ >* 绑定 ssh 码的时候,只输入ssh-keygen 可能是不够的,要输入ssh-keygen -t rsa -C"邮箱号" >* 新建完在调出 ssh时,如果输入more ~/.ssh/id_rsa.pub 也不太合适,使用 cat 这个命令更好,否则可能在git push -u origin master的时候会出现“无法找到ssh”。 >* 在推送git push -u origin master时候,如果提示“无法找到ssh密码”,则可以回到 cd 根目录中,输入cd ~/.ssd 移动到 .ssh这个隐藏文件中查看。 >![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbt14u6uhj30ms02h3zc.jpg) #### clone回来 ~~~ git clone git@github.com:对方账号/要拷贝的专案名字 本地你想新建的专案名字 ~~~ 比如:git clone git@github.com:lololo/sandbox amy_sandbox就是,我从 lololo 这个人的 github 中克隆一个名叫sandbox的专案,并且在本地中我自己取名叫amy_sandbox。 这个命令操作的意思是,第一次把别人的专案完整clone出来。但后续如果在执行小修改的时候,就不需要这个命令了,直接git pull 即可。 ~~~ git pull ~~~ #### 冲突 如果远端已经修改完了最新版,但是本地 git 仓库没有拉回来,又在同一个地方进行修改,那么如果你本地修改完以后想git push origin master,则会提示reject。 ~~~ To github.com:amy326/sandbox.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'git@github.com:amy326/sandbox.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. ~~~ ![](https://ws2.sinaimg.cn/large/006tNc79gy1fmbtr3gxv9j30mh05uwgn.jpg) 此时需要先pull 下来,进行修改后再推上去。但会发现其实 pull 下来以后仍然会有错,错在 README 这个文件中。于是打开 README 这个文件,解决冲突。 ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbtumnkywj30mm04yjt1.jpg) ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmbtwq4jnpj30j10avwew.jpg) #### 推送分支 push 分支 ~~~ git push origin feature6 ~~~ 这时另一台电脑如何拉 feature6? ~~~ git chekcout -t origin/feature6 ~~~ 出现以下错误提示: ~~~ fatal: Cannot update paths and switch to branch 'feature6' at the same time. Did you intend to checkout 'feature6b' which can not be resolved as commit? ~~~ ![](https://ws4.sinaimg.cn/large/006tNc79gy1fmbuso70a4j30mi01g74r.jpg) 此时可以更新远端仓库git fetch,再继续git checkout -t origin/feature6。如果再有冲突,可以把本地的feature6先删除,再直接克隆远端的。 ~~~ git fetch git checkout -t origin/feature6 ~~~ ## 合并分支的方式 reset rebase reverse merge ## git rebase重新整理 commit 类似 merge,但有点不一样。 **整理线型** 一般在分支要合并进主干前,可以用 git rebase 这个 功能来再整理一下 commit,让别人更好理解每个 commit 的意思。 ~~~ git rebase xxx节点 -i #进入互动模式# ~~~ 常用的有: #### 在某个节点之后插入新的一个 commit 插入 commit 可以用到edit 这个功能,只要把默认的pick改成edit 就可以。一般加入 git reset HEAD^,回到你要修改的 commit 之前的一个节点,先重置git reset hEAD^ ,然后 再继续编辑。 ~~~ git reset HEAD^ ~~~ 比如你可以 edit 把原来的一个 commit 变成2个(这个操作就是你只要跟平时一样 commit 两次就可以),然后再继续git rebase --continue继续进行,就可以。 ~~~ git add . #有冲突要先修好,并 add 进去stage才可以# git rebase --continue #可继续把rebase进行完# ~~~ ![](https://ws1.sinaimg.cn/large/006tNc79gy1fmbzfa3ioaj30i60bb0um.jpg) 最好在某个分支里面。因为 git rebase xxx -i 出现互动框后,只会出现你所在的分支的相关 commit 节点,不会出现其他分支的节点,所以如果有分叉出去的 commit,则会被跳过。 ![](https://ws4.sinaimg.cn/large/006tNc79gy1fmc1fsuhj9j30jb060dhk.jpg) #### 删除某个 commit 进入 -i 互动模式,只要找到对应的那行,直接删除(编辑状态下按两下 dd),再继续git rebase --continue 即可。 #### 保留某个 commit 内容,但不单独占用一个 commit 而是合并到前一个 commit 进去 用字母 f #### 改 commit 信息 用字母 r #### 调换顺序 也是一样,进入 -i 互动模式,把那两行直接剪切黏贴到合适的位置就可以。但要记得这是最危险的,因为会非常容易造成冲突。 #### 改善线型 git rebase 以后,commit 的线型可能不是非常好看,比如这个feature/forum 分支,如下图有点乱。 ![](https://ws4.sinaimg.cn/large/006tNc79gy1fmc2h7a49mj307b08pt92.jpg) 我们可以通过 git rebase master 命令让它重新回到 master 里面,变好看点: ~~~ git checkout feature/forum #切换到想修改线型的分支# git rebase master #从分支往主干合并,当然也可以合并到其他分支 git rebase feature1等# git add . #如果有冲突,应先解决,并输入git add .# git rebase --contimue #继续把没完成的 rebase 进行完# ~~~ ![](https://ws3.sinaimg.cn/large/006tNc79gy1fmc2mghljzj30an09sjs0.jpg) ## git reset砍掉 与 revert 不同,reset 是直接砍掉,不留痕迹。 #### 回到要修改的节点 ~~~ git reset xxx git commit -a --amend ~~~ ![](https://ws4.sinaimg.cn/large/006tKfTcgy1fmcfzglu0ej30eo09o74w.jpg) ~~~ git reset xxx号码 #重置 xxx 这个 commit# git reset HEAD^ #保存完马上后悔,于是执行这个文件以后,需要 commit 的内容就会还原到在 working spsce 里面待操作# git reset HEAD^ --soft #修改后放到 stage 里面# git reset HEAD^ --hard #直接清除# ~~~ ## 项目管理分支模式 * develop on mainline 这样的好处是比较清楚,避免后续 merge 的问题; 缺点是速度非常慢,需要前续完成后才能进行,后续必须有增量开发的能力(因为只有一条主线)。 ![](https://ws1.sinaimg.cn/large/006tKfTcgy1fmcheh2ohaj30dw07wq3l.jpg) * branch for release 比如主线是3.0版本,要更新3.1版本的时候,就开一个 release3.1的 branch ,后续也同理。 主要用来修复master 版本的bug。 * branch by feature 根据功能来切分,比较常见。优点多,但要避免开太多。另外需要有一个 leader 来负责主要 merge。 但需要大家都时不时更新主干 code。 * branch by team 也常见。 ![](https://ws3.sinaimg.cn/large/006tKfTcgy1fmchkafjy3j30ec0avq3r.jpg) #### 两个主要分支 master——主干,永远处于最新状态 develop——下一次要发布的版本,目前开发用。 ![](https://ws2.sinaimg.cn/large/006tKfTcgy1fmchma6u6qj306f08c74d.jpg) #### 三种支援分支 ![](https://ws1.sinaimg.cn/large/006tKfTcgy1fmchwi5malj30er0b13ze.jpg) * Feature 开发新功能,或者修 bugs; 从 develop 分出来,完成后 merge 到 develop 中; 如果开发时间长,建议定期同步develop 主干的 code,不然后期可能 merge 不进去 新手用 merge,进阶的建议用 rebase。 可以另设--no-ff的merge节点。 ![](https://ws4.sinaimg.cn/large/006tKfTcgy1fmchr2e6fej309o08sdg0.jpg) * Release branches 准备要 release 的版本,只修复bug; 从 develop 分出来,完成后 **merge** 回 master和 develop。 * Hotfix branches 等不及 release,必须马上修复的 bug; 一般从 master 分出来,完成后 merge 回 master 和 develop。 ![](https://ws4.sinaimg.cn/large/006tKfTcgy1fmchv5q2qqj306y08wq33.jpg) ## 更多 git 功能 * git archive * git bisect * git blame * git grep * git show * git gc * git format-path, send-email, am * git pull --rebase 可以避免不必要的 merge 节点。 ## 弄丢了commit 怎么办 找回: 例如搞砸了 git reset, rebase 或误删branch 在git gc前都有机会,因为预设会保留孤立的 commit90天。 * git reflog 或 git fsck --lost-found * git cherry-pick xxx号码 * git merge xxx号码 ## git 储存 ~~~ git cat-file -p xxxsha1号码 ~~~ ↑可显示文件位置