前言
在进行工作的git总提交, git客户端使用TortoiseGit 先将前一段时间(应该有半年以上都是在本地开发), 离线开发的内容push到git服务器, 这个对, 没有问题.
还有一部分在公司svn服务器目录迁出的工程, 有修改, svn服务器打开后, 这部分提交也没有问题.
想起自己本本上还有很多本地svn归档的开发成果, 这个也想提交到git日志. 如果能提交成功, 以后同事就可以迁出我的git目录, 自己去找. 公司有一份底子.
直接将本地svn目录拷贝到git迁出目录, 将.svn目录都去掉. 然后进行 git add, 然后出现报错如下:
libgit2 returned: path too long:
这个报错是目录或文件的全路径名称太长了. 这个长度限制是MAX_PATH, 不能大于260个字节.
简单测试如下, 可以看出全路径名称的限制就是260.
void test(void)
{
const char* psz_path_name = "D:/my_dev/xxxx_git_checkout/xxxx_rep_xxxxxxxx/local_svn_bk/rz3609_local/src/prj/bottom_board/doc/stm32cube_fw_f0_v1112/STM32Cube_FW_F0_V1.11.0/Projects/STM32072B_EVAL/Applications/FreeRTOS/FreeRTOS_SemaphoreFromISR/SW4STM32/STM32072B_EVAL/STM32F072VBTx_FLASH.ld";
int cb_len = (int)strlen(psz_path_name);
printf("libgit2 returned: path too long: len = %d\n", cb_len);
printf("MAX_PATH = %d\n", MAX_PATH);
cb_len = cb_len;
}
如果目录中有很多超过MAX_PATH(260)的文件, 等TortoiseGit add 报错了, 再去处理(可以压缩一下顶层目录到.7z, .zip文件), 就可以解决add报错的这个文件.
但是git add 之后, 报错只针对这1个文件, 不会将到底有多少个超出MAX_PATH的文件列出来. git add的时间很长(因为本地svn目录很大), 这要是一个一个报错的处理, 没有这么多时间, 效率太低了.
昨天下班前, 等git add 报错一个文件, 我就处理一个文件. 连续处理了3个文件, 感觉这种方法搞不定了. 得想新方法.
今天上班, 换一种思路. 先自己写个程序, 将放到git目录中的去掉.svn的总本地提交目录中的所有超出MAX_PATH的文件都列出来, 一次性处理掉. 然后在用自己程序再检查一遍, 如果没有漏掉的超长文件, 然后再用git add 就能一次成功. 试了一下, 这招好使.
测试程序
230行的小测试工程, VS2017 console
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <tchar.h>
bool cb_proc_find_file_who_path_name_len_greate_than_MAX_PATH(const char* psz_dir, const char* psz_file_name);
typedef bool(*PFN_CB_PROC_FIND_FILE)(const char* psz_dir, const char* psz_file_name);
bool find_file_proc(PFN_CB_PROC_FIND_FILE pfn, const char* psz_dir);
__int64 get_file_size(const char* psz_file);
void test(void)
{
const char* psz_path_name = "D:/my_dev/xxxx_git_checkout/xxxx_rep_xxxxxxxx/local_svn_bk/rz3609_local/src/prj/bottom_board/doc/stm32cube_fw_f0_v1112/STM32Cube_FW_F0_V1.11.0/Projects/STM32072B_EVAL/Applications/FreeRTOS/FreeRTOS_SemaphoreFromISR/SW4STM32/STM32072B_EVAL/STM32F072VBTx_FLASH.ld";
int cb_len = (int)strlen(psz_path_name);
printf("libgit2 returned: path too long: len = %d\n", cb_len);
printf("MAX_PATH = %d\n", MAX_PATH);
cb_len = cb_len;
}
int main(int argc, char** argv)
{
const char* psz_dir = NULL;
bool b_find = false;
do {
setlocale(LC_ALL, ".936");
printf("中文输出测试\n");
if (argc < 2)
{
printf("usage : THE_EXE dir_path_name\n");
printf("e.g. THE_EXE d:\\my_dev_dir\n");
break;
}
psz_dir = argv[1];
printf("base dir = [%s]\n", psz_dir);
b_find = find_file_proc(cb_proc_find_file_who_path_name_len_greate_than_MAX_PATH, psz_dir);
printf("file find %s\n", b_find ? "ok" : "nothing");
} while (0);
return EXIT_SUCCESS;
}
bool find_file_proc(PFN_CB_PROC_FIND_FILE pfn, const char* psz_dir)
{
bool b_rc = false;
HANDLE hFind = INVALID_HANDLE_VALUE;
char szDir[MAX_PATH * 4] = {'\0'};
char szDir_sub[MAX_PATH * 4] = { '\0' };
WIN32_FIND_DATAA ffd;
const char* psz_postfix = "\\*.*";
const char* psz_find_temp = NULL;
do {
memset(szDir, 0, sizeof(szDir));
strncpy(
szDir,
psz_dir,
min((sizeof(szDir) - 1), strlen(psz_dir))
);
strncat(
szDir,
"\\",
min(sizeof(szDir) - 1 - strlen(szDir), strlen("\\"))
);
strncat(
szDir,
"*.*",
min (sizeof(szDir) - 1 - strlen(szDir), strlen("*.*"))
);
hFind = FindFirstFileA(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
printf("error : FindFirstFileA [%s]\n", szDir);
break;
}
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((0 != strcmp(".", ffd.cFileName)) && (0 != strcmp("..", ffd.cFileName)) ) {
memset(szDir_sub, 0, sizeof(szDir_sub));
strncpy(
szDir_sub,
psz_dir,
min((sizeof(szDir_sub) - 1), strlen(psz_dir))
);
strncat(
szDir_sub,
"\\",
min(sizeof(szDir_sub) - 1 - strlen(szDir_sub), strlen("\\"))
);
strncat(
szDir_sub,
ffd.cFileName,
min(sizeof(szDir_sub) - 1 - strlen(szDir_sub), strlen(ffd.cFileName))
);
b_rc = find_file_proc(pfn, szDir_sub);
if (b_rc) {
break;
}
}
} else {
if (!pfn(psz_dir, ffd.cFileName)) {
b_rc = true;
break;
}
}
} while (FindNextFileA(hFind, &ffd) != 0);
} while (0);
if (INVALID_HANDLE_VALUE != hFind) {
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return b_rc;
}
bool cb_proc_find_file_who_path_name_len_greate_than_MAX_PATH(const char* psz_dir, const char* psz_file_name)
{
bool b_continue_process = true;
char sz_buf[MAX_PATH * 4] = { '\0' };
int len = 0;
do {
if ((NULL == psz_dir) || (NULL == psz_file_name)) {
break;
}
memset(sz_buf, 0, sizeof(sz_buf));
strncpy(sz_buf, psz_dir, min((sizeof(sz_buf) - 1), (strlen(psz_dir))));
strncat(sz_buf, "\\", min((sizeof(sz_buf) - 1 - strlen(sz_buf)), (strlen("\\"))));
strncat(sz_buf, psz_file_name, min((sizeof(sz_buf) - 1 - strlen(sz_buf)), (strlen(psz_file_name))));
len = (int)strlen(sz_buf);
if (len > MAX_PATH)
{
printf("error : len[%d] : [%s]\n", len, sz_buf);
}
b_continue_process = true;
} while (0);
return b_continue_process;
}
__int64 get_file_size(const char* psz_file)
{
__int64 file_size = -1;
FILE* pfile = NULL;
int i_rc = 0;
do {
if (NULL == psz_file) {
break;
}
pfile = fopen(psz_file, "rb");
if (NULL == pfile) {
break;
}
i_rc = _fseeki64(pfile, 0, SEEK_END);
if (0 != i_rc) {
break;
}
file_size = _ftelli64(pfile);
} while (0);
if (NULL != pfile) {
fclose(pfile);
pfile = NULL;
}
return file_size;
}
用法
在编译好的THE EXE目录, 写一个cmd, 将找到的超长文件都写到一个txt中. 然后对照这个txt, 处理所有超长的文件或目录.
@echo off
rem find_file_task.cmd
cd /d %~dp0
call find_file_task.exe "D:\my_dev\xxxx_git_checkout\xxxx_rep_xxxx\local_svn_bk" > .\find_result.txt
pause
查找到的超长文件结果文件
结果文件的样例
中文输出测试
base dir = [D:\my_dev\xxxx_git_checkout\xxxx_rep_xxxxxxxx\local_svn_bk]
error : len[261] : [D:\my_dev\xxxx_git_checkout\xxxx_rep_xxxxxxxx\local_svn_bk\xxxxxx_local\src\prj\bottom_board\doc\stm32cube_fw_f0_v1112\STM32Cube_FW_F0_V1.11.0\Projects\STM32072B_EVAL\Applications\FreeRTOS\FreeRTOS_SemaphoreFromISR\SW4STM32\STM32072B_EVAL\STM32F072VBTx_FLASH.ld]
error : len[263] : [D:\my_dev\xxxx_git_checkout\xxxx_rep_xxxxxxxx\local_svn_bk\xxxxxx_local\src\prj\bottom_board\doc\stm32cube_fw_f0_v1112\STM32Cube_FW_F0_V1.11.0\Projects\STM32072B_EVAL\Applications\TouchSensing\TouchSensing_2touchkeys\SW4STM32\STM32072B_EVAL\STM32F072VBTx_FLASH.ld]
error : len[262] : [D:\my_dev\xxxx_git_checkout\xxxx_rep_xxxxxxxx\local_svn_bk\xxxxxx_local\src\prj\bottom_board\doc\stm32cube_fw_f0_v1112\STM32Cube_FW_F0_V1.11.0\Projects\STM32072B_EVAL\Applications\USB_Device\CustomHID_Standalone\SW4STM32\STM32072B_EVAL_USB\STM32F072VBTx_FLASH.ld]
file find nothing
看找到的len记录, 最长的居然有300, 真惊讶. 剩下的事情, 就是按照查找结果文件, 将要提交的全路径名称都处理到260个字节一下就ok.
总结
刚来公司时, 发现以前同事都在用svn, 我也就用svn, 去现场不方便时, 或者在公司懒得开公司svn服务器时, 就在本地做了一个svn目录.
这样导致很多正式的工作内容都在本地svn目录中, 这样有可能以后总提交时, 很多正式工作成果会由于人工遗漏, 提交不到公司svn服务器.
经常到现场开发的同学, 应该对svn不方便离线开发的场景很厌恶.
后来, 用gogs搭建了git服务器.
用了git之后, 就全身心放松了. 只需要第一次git迁出时, 连接git服务器, 以后离线开发随便弄. 开发完, 直接commit到本地, 一年半年不提交到git服务器都行. 等想起来, 再一次push到公司git服务器. 如果此git目录是多个人公用, 需要先update一下, 有冲突解决冲突, 然后push. 如果此git目录就自己在用, 可以push时, 加上force选项, 一次push了事.
git也有权限控制(挂钩子), 如果简单的用, 可以将给每个同事建立他自己的git仓库, 用账号将库隔开. 如果有参考工程要给他, 可以直接拷贝出来给他.而不是将自己的git库账号给他.
|