Git的简单应用与实践
Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。本文将会基于孟宁老师的文章[1],使用vscode自带的git与leetcode70题“爬楼梯”,模拟在现实应用中的若干开发情景,初步实现Git的简单应用和实现。
0.基础准备[2]
0.0 vscode
vscode下载链接:https://code.visualstudio.com/Download
按部就班的下载完毕vscode后,安装相应的Cpptools工具

0.1 minGW
MinGW,是Minimalist GUN for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。
MinGW下载地址:https://sourceforge.net/projects/mingw-w64/files/
下载完毕后,还需配置环境变量,可以在cmd下键入gcc看是否成功配置环境。
0.2 配置C++环境
进入vscode,新建一个cpp文件,键入以下代码:
1 #include <stdio.h> 2 #include <windows.h> 3 int main() 4 { 5 printf("Hello World\n"); 6 system("pause"); 7 return 0; 8 }
此时代码尚无法运行,笔者在此处两个头文件下方都有波浪线显示错误。使用CTRL+shift+D进入调试界面,添加配置环境,选择 C++(GDB/LLDB),再选择 g++.exe,之后会自动生成 launch.json 配置文件,修改配置文件的路径(如"miDebuggerPath"等项应该为你的环境下的路径),之后会有tasks.json文件的修改,形式也是同理的。
{ // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "(gdb) 启动", "type": "cppdbg", "request": "launch", "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": true, "MIMode": "gdb", "miDebuggerPath": "F:\\minGW\\mingw64\\bin\\gdb.exe", "setupCommands": [ { "description": "为 gdb 启用整齐打印", "text": "-enable-pretty-printing", "ignoreFailures": true } ], "preLaunchTask": "task g++" //修改此项 } ] }
一切修改结束后,再按下F5发现没有报错,程序顺利通过。

0.3 建立远程仓库
注册GitHub账号后,可以在your repositories中新建一个数据仓库

至此,基本准备工作已经就绪。
1.Git本地库基础用法
1.1 初始化本地库
在基本工作准备阶段,我们已经在GitHub上面建立了远程仓库,所以这里我们只需要打开相应的路径,通过git语句将远程仓库的文件克隆下来即可。
git clone https://github.com/Whuzjc/git_test
如果没有在GitHub上建立仓库,也可以用如下语句建立本地库
git init
1.2 本地版本库基本操作

Git的本地库只涉及上图的红圈部分。本地仓库由gi维护的三棵树组成,分别为工作目录(workspace),暂存区(index)和存储库(repository),这三棵树构成了本地闭环版本库。在本地库操作中,你可以对当前版本文件提出更改,并将这些更改放在暂存区(也就是图中所示的workspace执行add操作,将文件放入index中),命令如下所示:
git add <filename>
git add *
这是git基本工作流程的第一步,使用如下代码可以进行实际的提交改动(即图中的执行commit指令,将index文件提交至repository):
git commit -m "代码提交信息"
这样就可以将改动提交到了HEAD[3]。使用reset指令可以删除在index中的文件:
git reset [--soft | --mixed | --hard] [HEAD]
--mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。--soft 参数用于回退到某个版本。--hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交。
1.3 实际操作
下面我们将在实际操作一下。
在本地库中添加jump.cpp文件
1 #include<iostream> 2 #include<vector> 3 #include<windows.h> 4 using namespace std; 5 int jump_ans(int N){ 6 if(N==1||N==0) return 1; 7 else return jump_ans(N-1)+jump_ans(N-2); 8 } 9 int main(void){ 10 int N,ans; 11 cout << "input the number of steps:" <<endl; 12 cin >> N; 13 ans=jump_ans(N); 14 cout << "the methods to reach order "<< N<< " are as follow:"<< ans <<endl; 15 system("pause"); 16 return 0; 17 }
该代码以递归的方法实现了leetcode70题的爬楼梯,感兴趣的读者可以点击此处来理解代码含义【4】。我们在vscode下先运行一下此代码,在终端输入5,表示青蛙(以一步或者两步)跳上5层台阶一共有多少种跳法。
PS C:\Users\ASUS\Desktop\git_test> & 'c:\Users\ASUS\.vscode\extensions\ms-vscode.cpptools-1.0.1\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-qaewzu3h.buj' '--stdout=Microsoft-MIEngine-Out-in1pfsgn.kdt' '--stderr=Microsoft-MIEngine-Error-2kreqetk.geu' '--pid=Microsoft-MIEngine-Pid-epi2scuu.zon' '--dbgExe=F:\minGW\mingw64\bin\gdb.exe' '--interpreter=mi'
input the number of steps:
5
the methods to reach order 5 are as follow:8
Press any key to continue . . .
可以看到,青蛙跳上5层台阶的跳法共有8种,验算结果正确。此时我们可以使用git status指令查看当前状态:
PS C:\Users\ASUS\Desktop\git_test\git_test> git status On branch master Your branch is up to date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) jump.cpp jump.exe nothing added to commit but untracked files present (use "git add" to track)
在git status指令下可以看到当前分支,且存在两个尚未确认的文件jump.exe和jump.cpp(因为是c++代码,生成一个.exe文件)。此时我们可以使用git add指令将文件提交到index下面后,再次执行git status指令:
PS C:\Users\ASUS\Desktop\git_test\git_test> git add jump.cpp PS C:\Users\ASUS\Desktop\git_test\git_test> git status On branch master Your branch is up to date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: jump.cpp Untracked files: (use "git add <file>..." to include in what will be committed) jump.exe
在执行了git add指令后,似乎什么也没有发生,但是执行了git status后,可以看到明显的区别:jump.cpp文件已经被提交至index,但是jump.exe还未被确认。既然将文件添加到了暂存区index,也可以使用reset指令将其删除,实机演示如下:
PS C:\Users\ASUS\Desktop\git_test\git_test> git reset HEAD jump.cpp PS C:\Users\ASUS\Desktop\git_test\git_test> git status On branch master Your branch is up to date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) jump.cpp jump.exe nothing added to commit but untracked files present (use "git add" to track)
然后我们再试着将jump.cpp提交到本地版本库,使用commit指令即可:
PS C:\Users\ASUS\Desktop\git_test\git_test> git add jump.cpp PS C:\Users\ASUS\Desktop\git_test\git_test> git commit -m "1th time" [master ff3b3b4] 1th time 1 file changed, 17 insertions(+) create mode 100644 jump.cpp PS C:\Users\ASUS\Desktop\git_test\git_test> git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Untracked files: (use "git add <file>..." to include in what will be committed) jump.exe nothing added to commit but untracked files present (use "git add" to track)
可以看到,jump.cpp成功提交到了本地库,至此基本的本地操作均已实现。
2.Git远程版本库的基本用法

远程版本库的操作就涉及上图中的push、pull和clone操作(clone已经实现过操作,这里不再赘述),即使用push操作,可以将当前的本地版本库送到远程版本库中,也可以使用pull操作将远程服务器上的文件下载到本地的workspace中。
使用push指令后:
PS C:\Users\ASUS\Desktop\git_test\git_test> git push Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 535 bytes | 535.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/Whuzjc/git_test.git 1c95411..ff3b3b4 master -> master
在终端可以看到完成了相关的文件传输工作,此时打开浏览器上GitHub,也可以看到在远程的版本库上也存在了我们上传的jump.cpp。

然后再新建一个文件夹名为git_test2,使用git pull指令将远程的代码下载到本地库:
PS C:\Users\ASUS\Desktop\git_test2> git pull Cloning into 'git_test'... remote: Enumerating objects: 7, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (6/6), done. remote: Total 7 (delta 1), reused 3 (delta 0), pack-reused 0 Unpacking objects: 100% (7/7), done.
可以看到,内容与远程库的文件信息一致

3.团队项目中的分支合并
3.1 分支合并操作
几乎每一种版本控制系统都以某种形式支持分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作,所以有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。下面我们来看一下git中涉及的分支指令操作。[5]
创建分支命令:
git branch (branchname)
切换分支命令:
git checkout (branchname)
合并分支命令:
git merge
3.2 操作流程
一般来说,分支合并操作的流程可以按照如下四步:
(1)克隆或同步最新的代码到本地存储库;
(2)为自己的工作创建一个分支,该分支应该只负责单一功能模块或代码模块的版本控制;
(3)在该分支上完成某单一功能模块或代码模块的开发工作;
(4)最后,将该分支合并到主分支。
3.3 实际操作
(1)创建分支
使用git checkout指令创建了mybranch分支,同时完成了分支的切换,如下所示:
PS C:\Users\ASUS\Desktop\git_test\git_test> git checkout -b mybranch Switched to a new branch 'mybranch' PS C:\Users\ASUS\Desktop\git_test\git_test> git branch master * mybranch
(2)修改分支文件
在master分支中,我们采用了递归的方法求解,此处我们将jump_ans函数修改为使用动态规划的方法来求解。
int jump_ans(int N){ vector<int> dp; for(int i=0;i<=N;i++){ if(i==1||i==0) dp.push_back(1); else dp.push_back(dp[i-1]+dp[i-2]); } return dp[dp.size()-1]; }
(3)在分支mybranch上提交
PS C:\Users\ASUS\Desktop\git_test\git_test> git add jump.cpp PS C:\Users\ASUS\Desktop\git_test\git_test> git status On branch mybranch Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: jump.cpp Untracked files: (use "git add <file>..." to include in what will be committed) jump.exe PS C:\Users\ASUS\Desktop\git_test\git_test> git commit -m "2th time" [mybranch 637e04d] 2th time 1 file changed, 6 insertions(+), 2 deletions(-)
(4)合并
切换回到master分支,下载远程版本库的文件,然后使用merge指令实现master和mybranch的合并,最终将合并的结果上传到远程版本库,终端结果如下所示:
PS C:\Users\ASUS\Desktop\git_test\git_test> git checkout master Switched to branch 'master' Your branch is up to date with 'origin/master'. PS C:\Users\ASUS\Desktop\git_test\git_test> git pull Already up to date. PS C:\Users\ASUS\Desktop\git_test\git_test> git merge --no-ff mybranch Merge made by the 'recursive' strategy. jump.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) PS C:\Users\ASUS\Desktop\git_test\git_test> git push Enumerating objects: 6, done. Counting objects: 100% (6/6), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 479 bytes | 479.00 KiB/s, done. Total 4 (delta 3), reused 0 (delta 0) remote: Resolving deltas: 100% (3/3), completed with 2 local objects. To https://github.com/Whuzjc/git_test.git ff3b3b4..f691045 master -> master
在GitHub上查看network,如下图所示:

4.Git Rebase
4.1 Git Rebase概念
git rebase 算是git里的高级操作了,他主要用来解决两种情况。
(1)有时候我们对于一个简单的需求提交了多次,这样非常不利于code review,所以我们需要将多次提交合并成一次提交。(即多次commit合并成一次commit)
(2)你从master创建一个分支开发,然后你的同事又从master创建一个分支开发,但是他比你先提交,所以远程的master分支比你的本地master走的远,所以现在要将你的分支代码基于远程的master来实现提交。[5]
4.2 实际操作
使用git rebase指令,可以看到进入了一个命令行的文本编辑器:
PS C:\Users\ASUS\Desktop\git_test\git_test> git rebase -i pick ff3b3b4 1th time pick 637e04d 2th time # Rebase 1c95411..637e04d onto 1c95411 (2 commands) # # Commands: # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
删掉第一行“pick ff3b3b4 1th time”,保存并退出,会发现出现错误:
PS C:\Users\ASUS\Desktop\git_test\git_test> git rebase -i HEAD^^ CONFLICT (modify/delete): jump.cpp deleted in HEAD and modified in 637e04d... 2th time. Version 637e04d... 2th time of jump.cpp left in tree. error: could not apply 637e04d... 2th time Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 637e04d... 2th time
即存在冲突,当修改完成后解决冲突,就可以继续使用add,commit等常规操作。此时查看git log,可以看到原先的两个版本变成了一个版本。
PS C:\Users\ASUS\Desktop\git_test\git_test> git log commit 1c954115b0c772da603e50cd8520b6bc42bd99d3 (HEAD -> mybranch) Author: Dlzjc <35788413+Whuzjc@users.noreply.github.com> Date: Thu Oct 8 16:04:33 2020 +0800 Initial commit
5.心得与体会
本文主要根据孟宁老师的五大场景玩转git一文,实现了在vscode上的git代码管理,对于git的使用有了一些感性和理性的认识,希望在今后的生活和工作中多多运用这一强有力的工具来武装自己。
参考文献:
[1]https://mp.weixin.qq.com/s/Km5KuXPETvG0wCGHrvj9Vg
[2]https://www.cnblogs.com/bpf-1024/p/11597000.html
[3]https://www.runoob.com/manual/git-guide/
[4]https://leetcode-cn.com/problems/climbing-stairs/
[5]https://blog.csdn.net/jygqm/article/details/94592049?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight

浙公网安备 33010602011771号