Git技巧
一、多个客户端之间的同步
有时候期望两个人之间去互相pull
和push
代码,那怎么做呢?
假如有同事A和B,同事A机器的IP是192.168.2.128,同事B机器的IP是192.168.2.129,现在同事A和同事B想项目同步。此时可以使用ssh
协议同步,在同事A的机器上:
git remote add ubuntu_3 ssh://fly1@192.168.2.129/home/fly1/source/nginx-docs
即ubuntu_3是远程机器的名字,可以任意取,但是不能再是origin
了,因为origin
已经用于中央仓库了,192.168.2.129是同事B的机器IP地址,/home/lizhiyong/source/nginx-docs
是同事B的repo
的绝对路径。
这样可以使用git pull
和git push
去推送代码了,比如在同事B机器上commit
一些内容,然后在同事A上使用:
git pull ubuntu_3 master # 拉取远程ubuntu_3上的master分支代码
git push ubuntu_3 master # 把本地的commit推送到远程ubuntu_3上的master
但是不幸的是push
的时候出现了下图所示的error
信息,原因是同事B的仓库不是一个裸仓库,它是有工作区间的,那么我们push
的结果是不会反应在工作区间的,也即在远程仓库的目录下对应的文件还是之前的内容。
此时必须在同事B的机器上的.git/config
文件里添加:
[receive]
denyCurrentBranch = ignore
此时在同事B的机器上还看不到内容,但是可以看到commit
记录了,需使用git reset --hard
才能看到内容。
二、git stash 暂存修改
大家可能也遇到这么一种情况,你正在聚精会神地开发某个feature
或者是在重构(FT-12345分支),但是突然线上冒出了一个BUG,你是那个牛逼的人,于是去解BUG,但是目前的修改怎么办才好呢?如果提交则会产生一个没有意义的commit
。此时我们可以使用git stash
这个神器了。保证你用了它之后会爱上它。
比如我现在FT-12345
的分支上做了修改,内容如下:
现在要切到master
分支上去修改BUG
了,那在切换到master
分支前我们可以暂存修改,即:
git stash # 暂存修改
git stash pop # 从缓存里取出修改
调用git stash
后就可以使用git checkout master
分支上去修复bug
了,修复完了之后再git checkout FT-12345
后git stash pop
。
git stash
的一些命令:
git stash # 将工作区的修改保存到缓存区,默然取名为:
# WIP on <branch_name> : <latest_commit_id> <latest_commit_message>
git stash save <name> # 将工作区的修改保存到缓存区,且取名为name
git stash pop # 取出缓存区栈顶(即最近一次)的内容,并且会删除此次pop的内容
git stash list # 查看缓存里所有存储的修改
git stash apply stash@{X} # 取出stash里的内容,X为序号,但是不会删除stash@{X}
git stash drop stash@{X} # 删除stash@{X}
git stash clear # 删除缓存区里所有的记录
三、如何解决项目之间的依赖
比如我们在产品开发中,基本都会遇到这样的情况,把产品架构设计划分成了很多个模块,不同团队开发不同模块,比如源码的src
目录有以下模块:
src
|------- buffer
|------- f-threadpool
|------- iniconfig
|------- intf
|------- store
|------- router
甚至是依赖了第三方的项目,那么我们可以使用git
的submodule
来管理这些依赖,submodule
允许父项目可以有很多的独立的 Git子项目,这些子项目可以单独提交/push/pull
等管理,而且父项目中的提交不会影响到子项目。这有很多好处:
- 把子模块单独作为一个 git 项目,他们可以独立开发,他们的错误并不会影响到父项目。
- 团队分模块工作在不同 git 项目上,减少了代码提交的依赖,减少了很多更新操作。
3.1、submodule的使用方式
添加submodule
:
git submodule add <url> <path> # url是子模块的repo地址,path是在父项目中的存放路径
git submodule add git@106.52.144.219:lee/ringbuffer.git server/src/ringbuffer
添加submodule
后,会发现在父项目中出现一个.gitmodules
文件,文件里的内容包括:记录名字,路径和url
,然后我们需要把这几个文件添加到git
版本管理里:
git add .
git commit –a –m "add bloomfilter and ringbuffer submodule"
git push
3.2、如何clone submodule
一个项目仓库中并不真正保存了子模块的代码文件,他只是保存了这些配置信息而已,当我们clone
仓库的时候,并不会在clone
出子模块的代码,仅仅是有一个文件目录而已,里面没有任何文件,有两种方法拉取子模块的代码:
git clone
时加上--recurse-submodules
参数,如:git clone <url> --recurse-submodules
。git pull
后,执行git submodule update --init --recursive
。
3.3、submodule的坑
仓库都是由commit
记录的,是有版本的,那么在使用submodule
的时候,也是一样的,仅仅是指向他的特定版本,比如我们使用git submodule status
可以查看到指向的“版本”(某个commit
记录),如果我们在bloomfilter
这个项目上(假设有这个项目)有更新是不能自动反应到这个主repo
上的,bloomfilter
已经更新到了a1532ce
了,但是主repo
的submodule
并没有指向这里,那么也就不能自动“checkout
”最新代码了。那如何做?
3.3.1、如何更新submodule的内容
子模块有新的提交了,如何更新?就以上文所述,我们的bloomfilter
项目已经更新了,那如何更新项目里这个submodule
的版本?方法如下:
cd server/src/bloomfilter
git pull
git checkout commit-id # 手动移动submodule的指针到某个commit-id上,
# 然后我们在主repo上:git submodule status,
# 可以看到 submodule更新了(前面有个‘+’号),
# 此时我们应该提交这个更新,这样别人才能获取到这个更新操作
# 提交对submodule的更新
git commit server/src/bloomfilter –m "move bloomfilter submodule to a1532ce02"
git push # 推送更新到远程仓库
3.3.2、如何同步submodule的更新
刚刚,我们更新了submodule
的内容了,也把submodule
的这个“指向”更新推送到了远程仓库了,那其它的开发人员如何“同步”这种更新呢?
git pull # 拉取最新变化
git submodule update - -remote #更新子模块为远程项目的最新版本
3.3.3、在子模块中工作
submodule
让我们看起来以为是一个仓库,我们想当然的想在里面做一些修改,可是并非如此,我们cd
到该子目录后,使用git status
会发现“HEAD detached at a1532ce
”,这其实就告诉了我们,当前并没有处于一个分支上,并不能去提交修改,当然我们可以使用git checkout master/dev
的方式切换到某个分支上,做一些修改,然后提交submodule
的更新,尽管可以这么做,但是依然不建议大家如此。
HEAD detached at al532ce
nothing to commit, working directory clean
3.3.4、删除子模块
一般我们不会删除某个子模块,除非是我们的技术方案有调整,但是总之还是有可能的,此时我们可以使用git rm submodule
的方式删除。
git rm
用于从 Git 版本控制中移除文件或目录。如果你想移除一个子模块,步骤稍微复杂一些,因为子模块管理了一个独立的 Git 仓库。移除子模块的简要步骤:
-
删除子模块条目:使用
git rm
命令来删除子模块的路径。这个命令会从索引中移除子模块,但不会删除实际的文件。git rm path/to/submodule
-
清理 .gitmodules 文件:手动编辑
.gitmodules
文件,删除对应的子模块条目。 -
更新 Git 配置:如果有必要,更新
.git/config
中对应的子模块配置,删除相关条目。 -
删除子模块的目录:最后,手动删除子模块的实际目录:
rm -rf path/to/submodule
-
提交更改:提交你的更改以更新主仓库:
git commit -m "Removed submodule"
四、Git备份到另一台服务器上
为了容灾,在大厂里都会对git
的仓库进行备份,那如何做的呢?在解释步骤前,先介绍下场景:
总共有以下步骤:
-
设置ssh的免密登录方式:
ssh-kengen –t rsa # 以rsa算法生成密钥对 vim ~/.ssh/id_rsa.pub # 把id_rsa.pub的内容拷贝后放在git仓库的/root/.ssh/authorized_keys里 chmod 400 /root/.ssh/authorized_keys # 在git服务器上设置文件的权限为400
-
书写以下脚本:使用
ssh
协议进行git clone
,--mirror
是拷贝镜像的意思(不能省掉,因为git
仓库有很多的分支和tag
信息)。
-
通过crontab添加定时任务:
crontab –e # 在定时任务中添加: 0 0 * * * sh /srv/backup_remote_git.sh,然后保存 systemctl restart cron # 重启cron服务,如果在centos是systemctl restart crond
五、总结
通过本文介绍的 Git 技巧,可以更加从容地处理代码管理中的各种挑战。从有效地同步多台机器上的代码、临时保存开发中的修改、管理复杂项目中的模块依赖,到确保 Git 仓库的备份和恢复,这些方法都是提升工作效率和确保代码安全的重要手段。掌握这些技巧,不仅能让开发流程更加顺畅,还能帮助团队更好地协作和应对突发情况。