一、git add
代码的版本管理对于现在的软件开发几乎是无法绕开的。当然,还是有不少的小公司仍然使用定期拷贝到服务器进行备份的方式来进行代码管理,不过属于很小的范围内了。而git就是这种代码版本管理的重要的一种工具。它作为一种分布式的版本控制系统,几乎在稍微上规模的软件团队中都会广泛应用。
在git代码管理过程中,增加新文件即git add到版本管理器中,是最基础也最常见的一个操作命令。它可以被看作为对代码进行真正的管理的开始的步骤,通过这条命令,可以将需要管理的代码的文件夹、文件及相关的内容划入到管理的范畴内,是进行其它git管理操作的前提。
二、分析
对于git管理工具来说,一般可以划分成两大体系即本地和远端。在本地又可以划分成工作区,也可翻译成工作空间或工作目录(Working Directory / Workspace)、暂存区(Staging Area/Index)能主本地仓库(Local Repository)。这其中的本地仓库对应着远端中的远端仓库(Remote Repository)。如果忽略掉远端仓库的更多的分布式功能外,只考虑代码的完整性,可以简单把远端仓库理解为本地仓库映射拷贝。
代码在本地使用时,开发者可直接进行操作的工作环境,如IDE显示的代码、各种文本工具操作看到的代码及工程等等,都可以看作是工作区。开发者可以任意的在这个区域内对其进行增、删、改和隐藏等操作。在这个区域内,开发者可以想当然的认为是没有任何版本管理的存在。
而暂存区则是通过git add等方式进入git版本管理后的一个中间区域或中间状态区,也可以认为是一个缓冲区,用来将处理于改动状态的文件管理起来,告诉开发者是否确定将这些改动提交到版本管理库中,它其实是一个位于.git文件夹下的一个临时的索引文件(直观的认为是一个草稿)。它类似于电商平台上购物的购物车中的商品。既可以付款真正购买也可以直接删除不再购买。
而本地仓库则是刚刚提到的开发者确定将改动提交到git的本地数据库,它一般在.git目录下的objects和refs目录中。可以认为它就是一个文件型的本地数据库或分布式的数据库。只不过,它不对外暴露直接操作的接口罢了。
工作区的对象发生变化需要使用git add增加到git管理器中,其实是进入了暂存区。而通过使用git commit就可以将暂存区对象提交到本地仓库中形成一个递进的管理层次。最终,又可以通过git push将本地仓库和远端仓库连接起来进行数据同步,将本地变化的数据内容提交到远端仓库,保持代码的一致性。
三、增加的形式
git add命令有几种使用的方式,比如对单个文件、多个文件、整个文件夹或模糊匹配等等多种形式。其主要包括:
-
单个文件
这是最基础也是最简单的方式,一般使用:
git add xxx.xx #注意,修改也可以这样增加 -
多个文件
可以使用下面的命令进行多个文件的增加:
git add xxx.xx xxx1.xx xxx2.xx #可以多个 -
所有文件
这个一般只有在特定的情况下才会使用,否则容易出现误加的问题,原则上尽量少使用:
git add . #会将当前目录及子目录下的所有文件增加,包括新增和修改 git add -A # 全量添加,即整个工作区的所有变更,含增、删、改 -
增加目录
将指定目录下的所有新增和修改增加:
git add dic/ #会将当前目录及子目录下的所有文件增加,包括新增和修改 -
使用通配符
这个就比较灵活,但灵活往往意味着有可能大意。一定要小心:
git add *.cpp git add dic/* #不匹配子目录 -
使用修改状态机制
这种机制是比较推荐的一种方法,即只对修改的文件有兴趣,进行增加:
git add -u #只增加修改部分到暂存区,注意无法处理删除文件其本质是git对./git/index文件的遍历,找到跟踪的元数据进行比较,发现修改标识然后进行处理。
四、应用方式
虽然看上去使用git add并不复杂,但实际在应用中却有很多的小细节需要注意。一般来说,使用git add的步骤如下:
- 引入忽略机制
在.gitignore文件增加规则,比如对一些配置文件、日志文件等进行忽略,不提交 - git status查看当前的状态
这点往往很多开发者并不重视,但它其实是验证是否真正提交的一个预览,必须要做 - 使用刚刚提到的某种形式增加文件
这个就好理解了,使用add的形式增加对象到暂存区 - git status再次查看当前的状态
这点极容易被忽略,很多人几乎都不看这个状态的情况,直接就进行了下一步的操作。其实这一步是纠错机制的重要手段,为代码管理提供一道有力的屏障 - 再进行其它操作如git commit等
这就是后来项,不是本文内容,不展开
五、问题处理
-
未提交对比
很多开发者会在提交前对修改内容进行查看,特别关注一下修改的具体的细节。此时如果只是在工作区中未进行任何操作,则可以使用:
git status git diff #全部比较,逐一列出 或 git diff xxx/xxx.xx #只对感兴趣的文件对比 -
提交到暂存区对比
如果在提交后发现有问题,想通过比较一下内容来看是否真正有问题时,可使用:
git diff --staged 或 git diff --cached #如git diff con/json.cpp --staged -
解决冲突
这种问题在多人合作开发同一文件或模块时很可能会出现。解决的方式一般来说也比较简单,打开冲突文件,可以看到类似下面的代码:
<<<<<<< HEAD // owner change ======= // conflicting change >>>>>>> xxx branch根据实际情况,是要使用二者之一还是要二者同时兼容,修改好后重新提交即可
-
恢复未提前前的状态
这是一种非常重要的机制,即错误的恢复机制。比如开发者虽然Add了,但突然又发现这样做是不可以的,想恢复到原来的状态。可以使用下面的命令:
#全部无条件撤销并恢复 git reset 或 git reset HEAD <有问题文件> #只摊销指定文件 #未提交到暂存区 git restore <文件>... #已add后到暂存区 git restore --staged . #清空所有缓冲区 git restore --staged <filename>... #可连续指定多个文件,Git 2.23版本起另外在使用git add时,如果对项目的提交没有把握,则可以使用:
git add -A #或git add -all
git stash
这样一旦提交错误,就可以从临时的栈区恢复相关的修改。是一种最后的备份吧。
使用git status时会有三种情况:
1. 红色的代码状态表示未暂存
2. 绿色状态的代码表示已暂存
3. 无提示则表示工作区干净,与暂存区和本地仓库最新提交一致
## 六、交互式提交
交互式的提交有两类,一类是基于文件为单元的;另外一种是基于文件内代码模块为单元的。
1. 基于文件内代码交互
git add -p <文件名>(如果不加文件名,会遍历所有改动文件)
(1/1) Stage this hunk y,n,q,a,d,e,??
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
e - manually edit the current hunk
? - print help
它其实类似于将代码内分块,按需提交。在一些粒度把握较高的时候儿可以考虑使用
2. 基于文件整体交互
git add -i
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> #可以在此处输入上面的列出的命令,包括缩写,第一个小字母
这其实就是一种防备手滑打错的手段
交互式的提交,往往更适合于大型的项目的提交管理。毕竟一个很小的项目,一会就能全部看完,交互的意义几乎很小,犯不着耗费这个烦神。
## 七、总结
add只是git管理的一个基础,它不代表使用其以后,相关的代码就安全稳固了。它只是进入暂存区,如果此时出现异常如电脑毁等,则有可能无法恢复。确定的代码要及时的commit到仓库包括及时推送到远端仓库。
工具的使用一定要按照严格的流程来操作。虽然大多数情况下可能省略掉一些步骤更轻松便捷,但在遇到问题时往往就头痛了。所以add前要查看状态并比较修改情况,确定是否为自己所需。在每一步的提交后,也要进行相关的检查,这样才可能把问题尽量杀死在萌芽状态。