目前所知,使用 repo sync 同步远端服务器代码,不能强制覆盖本地修改。如果想要强制覆盖本地修改,可以用 repo forall -c 来执行git丢弃本地修改的命令,git checkout 和 git reset 命令都可以丢弃本地修改。
一般来说,可以使用
git checkout .
命令来丢弃当前目录下的改动,但是实际执行
repo forall -c git checkout .
命令会报错:
$ repo forall -c git checkout .
error: pathspec '.' did not match any file(s) known to git.
而使用
repo forall -c 'git reset --hard'
命令不会报错,可以用这个命令来丢弃所有git仓库的本地改动,然后再用 repo sync 命令来同步远端服务器代码。
在实际项目开发时,可能会在本地创建开发分支,这个分支没有关连到服务器分支。我们同步远端服务器代码,可能只是想获取到最新代码。此时,并不想丢弃本地开发分支的改动。但是上面的
repo forall -c 'git reset --hard'
命令无法区分这种情况,会丢弃开发分支的改动。
下面这个看起来很复杂的命令就用于解决这个问题,它先判断当前本地分支在远端服务器存在同名分支时,才强制覆盖本地修改并pull服务器代码:
repo forall -c "branch_name=$(git rev-parse --abbrev-ref HEAD) && git rev-parse --abbrev-ref ${branch_name}@{upstream} && git reset --hard && git pull --stat --no-tags" |& cat
对这个命令的各个部分说明如下。
repo forall -c
:对所有git仓库都执行后面的跟着的命令,这里使用双引号把多个git命令都括起来,作为一个整体传给repo,可以做一些复杂的操作。
branch_name=$(git rev-parse --abbrev-ref HEAD)
:这是bash shell的语法,
$(cmd)
会执行 cmd 命令,得到它的输出,这里把输出结果赋值给
branch_name
变量。
git rev-parse --abbrev-ref HEAD
命令输出且只输出本地分支名。
&&
:bash shell的与操作,前一个命令执行结果为true,才会执行下一个命令。
git rev-parse --abbrev-ref ${branch_name}@{upstream}
:
${branch_name}
表示获取
branch_name
变量的值。
branch_name
变量在前面被赋值为当前本地分支名。整个git命令获取本地分支在远端服务区分支名。如果获取不到,执行结果是false。
git reset --hard
:基于
&&
操作符的特性,如果上一个git命令获取不到本地分支在远端服务器的分支名,就不会往下执行。所以执行到这里时,说明本地分支名跟远端服务器分支名相同,我们假设本地开发分支没有关连到远端服务器分支,那么当前分支就不是开发分支,用 git reset 丢弃本地修改。