更多文章欢迎访问 程序员小非 博客
团队开发过程中经常会使用git工具来管理代码,团队中成员使用的终端可能是windows和类Unix系统,由于操作系统的差异可能会给大家使用git带来一些困扰。尤其是将类Unix系统中建立的仓库在windows系统打开的时候。在windows上使用*nix
建立的仓库主要处理好三个事情,换行符、文件权限、软连接。
1.处理换行符
换行符在各个系统中有不同的表示,一般使用两种符号,一种是LF\n
换行,一种是CR\r
回车。windows系统使用的是\r\n
, unix系统使用的是\r
,linux系统使用的是\n
。这样就导致从不同系统checkout代码时出现文件未修改却出现modified的情况,git对此有自动转换的机制,设置core.autocrlf
为true
,在checkout和checkin时就会自动转换换行符。
git config --global core.autocrlf true
2.处理权限
*nix系统对拥有者、组、其他几种用户都有明确的读写执行权限,这些在windows上没有对应的机制,这个问题在使用git时表现为没有修改文件却出现很多modified的文件,git status
显示 typechange。一般出现在增加可执行权限的文件上。git对此也有一定的策略,可以设置core.filemode
为false
,这样就会忽略文件权限带来的改变。
git config --add core.filemode false
如果clone前没有设置,导致已经进行了修改,可以用下面的命令来批量恢复这些修改。
git status | grep typechange | awk '{print $2}' | xargs git checkout
3.处理软链接
这可能是最让人头疼的问题,在*nix系统里我们经常会使用ln
来给文件和文件夹设置软链接,而这些软链接到windwos就失效了,不能进行导航,ide也不识别,如果有关键文件夹设置了软链接,仓库在windows上就基本不可用了。这也是笔者遇到的一大难题。
git暂时还不能像处理换行符一样优雅的处理软链接,需要我们自己手动来处理。windows中也有自己的软链接实现方式,建立软链接使用mklink
命令,mklink
的使用文档是这么写的:
MKLINK [[/D] | [/H] | [/J]] Link Target
/D creates a symbolic link, or a soft link.This essentially acts like a shortcut to a folder in prior versions of Windows, except you don’t have to use an actual shortcut.
/H creates a hard link, which points directly to the file.This option can’t be used for folders directly for some reason, you’ll have to use the next option.
/J creates a “Directory Junction”A Directory Junction is actually just a hard link to a directory. This is a feature that existed prior to Vista as well. If you are trying to symlink to a directory using a hard link, then you should use this option.
主要就分为三种,/D
/J
/H
,/D
和/J
用于目录,/H
用于文件,对链接的修改对不会影响源文件,/D
和/J
不会占用空间,/H
会占用空间。具体可以参考mklink.
现在我们就要将*nix中的所有软链接换成windows的link,主要三步:
- 找到软链接文件
- 使用
git ls-files -s
,git把所有的软链接设置成120000
类型
- 使用
- 修改软链接
- 使用
mklink
命令
- 使用
- 屏蔽软链接的修改
- 使用
git update-index --assume-unchanged
- 使用
上述步骤已经整理成一个python脚本,可以从我的gist获得。脚本只在Babun-windows上最好用的终端 测试过,其他终端可能无法使用,如有错误请自行修改。
考虑国内访问github速度,贴出脚本如下,在仓库根目录执行。
import os
def rindex(lst, value):
try:
return lst.rindex(value)
except ValueError:
return -1
# find symbol link files or dirs
fp = os.popen("git ls-files -s | awk '/120000/{print $4}'")
links = fp.read().strip().split("\n")
# get symbol links' parent dir
link_dir = set()
for link in links:
index = rindex(link, "/")
if (index != -1):
link_dir.add(link[:index])
else:
link_dir.add(".")
work_dir = os.getcwd()
# make link for every symbol link
for d in link_dir:
os.chdir("/".join([work_dir,d]))
fp = os.popen("ls -la")
items = fp.read().strip().split("\n")
for item in items:
if "->" in item:
tks = item.split("->")
src = tks[0].strip().split(" ")[-1]
dst = tks[1].strip().split("/")
if (len(dst) > 1):
dst = "\\\\".join(dst)
else:
dst = dst[0]
print ("link " + src + " -> " + dst)
os.popen("rm " + src)
if (os.path.isfile(dst)):
os.popen("cmd /c mklink /H " + src + " " + dst)
else:
os.popen("cmd /c mklink /j " + src + " " + dst)
# make links unchanged
os.popen("git update-index --assume-unchanged " + "/".join([os.getcwd(), src]))
