哈喽 大叫好,我叫人宅 很高兴和大家分享一下 我自己写的git小程序。
这个是人宅版本的git 实例 ,我把它放在了OSS服务器上 (如果对OSS服务器感兴趣的小伙伴可以点击 阿里云OSS服务器课程)
解压打开git 可以看到如下文件
这个程序比较小众,估计也没多少人看~_~
不管怎么样 还是要解释一下如何测试这个程序,因为这个renzhai版本的git版本控制还有很多可以学习的内容。
1.install.bat :安装的意思是模仿git 的安装点击后会自动安在菜单上,如下:
2.uninstall.bat 直接可以从菜单上移除掉。
3.这里我建立了三个文件
client1 //用户2
client2 //用户1
server //git 服务器存储的位置
4.先启动服务器,服务器的启动非常简单,只需要将图中的gitrenzhai_server.exe拷贝到你的server文件里面 作为仓库;
5.双击运行,服务器就算是启动了,非常简单。
6.启动后会自动生成以下文件:
其中:
.git //里面存储着git相关信息,比如用户提交信息,用户各个版本信息,用户具体版本等,我们稍后会分析
git_server //
log //服务器本地日志
README.txt //基础操作
打开.git
其中有以下信息
- version \\这里面存放着各个上传版本的具体内容
- DO8D1043….CD…. \\这个是上传具体版本里面的文件列表
第一个是上传的类型 是覆盖还是删除还是添加
第二个是filename
第三个是crc 校验码
第四个是文件大小 以字节为单位
- file_list.file //当前文件的文件列表
- ignorepath.ig //忽略的路径
- igore_suffix.ig //忽略的后缀
- version.list //各个版本的列表
服务器启动完毕后就可以启动客户端
7.先进入client1
8.鼠标右键启动客户端
9.我们现在启动了一个客户端,通过git init 命令初始化一个仓库:
此时客户端会生成如下内容:
.git //记录着客户端本地信息
git_client //
log //客户端本地日志
10.打开客户端.git
里面生成了三个文件
git.txt //为git 进行git定位
ignore_path.ig // 本地忽略的路径,防止上传不合法的内容
ignore_suffix.ig //忽略的文件的后缀
11.我们可以通过git –help的命令了解更多命令
12 我们可以通过git –global user.name 来注册一个用户的名称这里以人宅为例子:
13 我们可以通过git –global user.email 来注册一个用户的邮箱:
14 然后就是拉去服务器的数据版本,这里我推荐两种方法,这两种方法都可以实现拉取~
方法一:
git remote add origin 【 URL】 // 这里的URL是服务器的路径 URL = M:\Server
git pull // 拉版本
方法二
git clone【 URL】 // 这里的URL是服务器的路径 URL = M:\Server
当我们进行更新后 我们可以看到客户端文件的变化:
成功的拉取了服务的README.txt,并且在.git里面多了如下的内容:
git_user.ini 里面存储着当前客户端账户信息:
version.info 里面存储着当前最新版本提交的信息:
里面存储着当前最新版本列表 因为我们只拉去了服务器的一条数据 README.txt,如果有多条,这里面将显示多条数据:
现在 我们在客户端放置一个测试文件 这个文件是SimpleThread UE4插件的源码:
15我们需要将数据发送到服务的,作为一个新的版本,其他用户会更新你上传的这个版本。你可以通过git add Source 和 git add . 这两种命令进行添加:
方法一:
方法二:
git add [文件名称] //添加文件下所以子文件的子文件
git add .// 添加当前目录下的所有文件
16 添加好后我们可以通过git commit -m “你提交的内容” 描述你提交此次版本的内容;
这一步很关键,如果没有这一步 后面的提交将是失败的。
17 最后我们通过git push 将数据发送到远端的服务器;
你也可以通过git push -u origin master 这个命令来完成推送,当前的小程序暂时不考虑分支方面的操作;
现在我们来看看服务的,是不是多了一个Source ?我们已经完成了一个文件的推送;
18 我们可以通过git status 来查看客户端当前版本文件的变动情况:
19 测试一下 删除和更新 观察服务的变化,这里我删除该文件内的Coroutnes和Runnable 并且将ThreadManage.h的大小进行改变:
我们现在对Source里面的内容进行提交 查看变化情况;
我们现在已经对服务器上的数据进行了修改。从表中我们可以看到我们已经移除了服务器指定的数据,并且我们的git也成功的检测出文件的变化,只更新有变化的文件;
现在,我们通过git status 来查看当前版本的文件变化:
这个小程序 我做了特殊处理,覆盖用灰色,红色代表移除 蓝色代表添加;
我们先看看版本提交的情况,我们可以通过git log来查看 历史提交情况;
我一共提交了两次,可以清晰的看到提交人和提交信息 以及提交的日期;第一个提交是服务器提交的,这个是默认提交内容,只要开启服务器 会自动生成一个。
现在,我们按照这种方法试一下另外一个客户端,看看它们是否可以协调工作。
打开客户端2,我们能清楚的看到这个客户端:
先git init 初始化一个仓库;
再通过 git --global user.name 注册一个名字
最后用git clone 拉取服务端的数据内容。
client2已经成功的将数据从服务器拉去到了
我们现在有两个客户端 一个是人宅 一个是小白;
正常操作中 我们需要这两个客户端不停提交版本,更新版本,方便工作中相互协作,相互合作,那么我们来测试一下迭代更新。
现在小白完成了他的模块 需要提交文件,我们来看看他的操作;
20 我们复制了一份 public 并且 把 Private整体删除;
最后我们进行提交;
21 因为数据太多,我们可以通过git status 来查看上传版本的文件具体行为。
可以看到我们删除了Private 上传了 Public – 副本;
可以看看我们的服务端情况:
和客户端2的结构吻合。
现在我们来到客户端1(人宅) 进行更新。
客户端本地数据信息:
22.最后 我们还剩下一个冲突的测试 如果客户端一提交了版本数据 ,而客户端2修改了本地文件,这个时候客户端2进行更新,更新的文件刚好是客户端1提交的内容,这样就报错了,这个就是一个冲突,我们的git经常有这方面的错误提示,现在我们来测试一下:
还是原来的文件,我们对SimpleThread.build.cs这个文件做一些操作,把它变大;
3 KB – 11KB
现在我们来提交 客户端1的内容:
提交的信息如下:
我们现在对客户端2内容进行修改 :
我们现在更新客户端2
显示我们的客户端2其中SimpleThread.build.cs发生了错误,本地和服务端产生冲突 需要解决。
解决方法很简单 备份本地数据 重新拉去服务器最新数据 ,将修改的数据复制到服务器最新版本,提交即可,这个是git传统的操作方案。git并不像SVN那样可以进行代码行的合并。
现在我们来删除这个文件,这样,就可以获取服务器更新的数据,冲突也就解决了。
拉取版本:
解决了冲突:
我们来查看一下提交信息;
具体提交的状态:
现在我们把问题搞的复杂一些 来全面测试该程序
现在我们对客户端1 的SimpleThreadPlatform.h和ThreadManage.h进行删除 并且修改了文件SimpleThread.h
整个文件修改后变成了这样~
现在我们提交一下客户端1
现在我们再添加再删除,准备一个版本;
再上传
最后我们移除这些文件
客户端1再上传
人宅客户端1上传了 好几个版本,现在我们来看看客户端2小白的更新情况。因为实际项目中比这个更复杂,这种测试是必要的。
大家应该按照操作,可以看到相应的结果,感谢抽时间看到这么远;
服务器源码.h:
#pragma once
//Copyright (C) RenZhai.2019.All Rights Reserved.
//作者 人宅
//该c库的详细源码讲解在AboutCG 《手把手入门硬核c语言》视频工程里面:
//https://www.aboutcg.org/courseDetails/902/introduce
//希望学习其他方面技术 比如做UE4游戏, 可以访问下列网址:
//https://zhuanlan.zhihu.com/p/60117613
//
//bibi可以看到各个人宅系列教程介绍:
//https://space.bilibili.com/29544409
//
//个人博客网站
////renzhai.net
//
//关于本套案例的详细操作 :
//文字版本(详细):
//https://zhuanlan.zhihu.com/p/144558934
//视频版本:
//https://www.bilibili.com/video/BV1x5411s7s3
#include "protocal_type.h"
char git_project_path[MAX_PATH] = { 0 };
char git_version_list_filename[MAX_PATH] = { 0 };
char git_version_filename[MAX_PATH] = { 0 };
char git_server_cache_path[MAX_PATH] = { 0 };
char git_path[MAX_PATH] = { 0 };
char git_version_path[MAX_PATH] = { 0 };
char version_tmp[MAX_PATH] = { 0 };
//具体文件在服务器的状态
typedef struct
{
bool b_exit;
char filename[MAX_PATH];
simple_c_guid crc;
unsigned int filesize;
}ffile_info;
//文件列表
typedef struct
{
int size;
ffile_info data[8196];
}ffile_list;
ffile_list file_list;
typedef struct
{
int size;
char data[MAX_PATH][1024];
}fpath;
fpath ignore_path,ignore_suffix;
//提交版本的信息
typedef struct
{
char name[MAX_PATH];
char commit[MAX_PATH];
char date[MAX_PATH];
simple_c_guid guid;
}fgit_commit;
typedef struct
{
unsigned int size;
fgit_commit commits[1024];
}fgit_commits;
fgit_commits commits;
//文件版本操作类型
typedef enum
{
NONE_File,
ADD_FILE,
SUBTRACT_FILE,
OVERLAP_FILE,
}eversion_operation_type;
//单个文件的版本
typedef struct
{
eversion_operation_type operation_type;
unsigned int file_size;
char file_name[MAX_PATH];//
simple_c_guid crc;
}fgit_version;
//整体文件的版本
typedef struct
{
unsigned int size;
fgit_version paths[2048];
simple_c_guid crc;
}fgit_versions;
//整体文件版本列表
typedef struct
{
unsigned int size;
fgit_versions paths[1024];
}fgit_versions_list;
fgit_versions_list versions_list;
void init_path(fpath* p);
void string_to_path(const char* data, fpath* p);
void path_to_string(char* data, const fpath* p);
void init_commit(fgit_commit *out_commit);
void init_versions(fgit_versions *in_versions);
int get_index_by_commit(const char* client_crc, fgit_commit** out_commit);
int get_nest_index_by_commit(const char* client_crc, fgit_commit** out_commit);
const char *get_git_version_path();
const char *get_git_version_crc_path(const char *crc);
void compare_list_v(const fgit_versions* in_versions_a, const fgit_versions* in_versions_b, fgit_versions* out_versions_add, fgit_versions* out_versions_remove);
void compare_list(const fgit_versions* client_version_list, const def_c_paths* local_paths, def_c_paths* out_paths);
fgit_versions* find_versions(const simple_c_guid *crc);
fgit_versions* get_newest_versions();
void save_newest_versions(const char *crc_buf);
const fgit_commit* get_newest_commit();
char *git_commit_to_string(const fgit_commit *git_commit, char *buf);
void string_to_git_commit(fgit_commit *git_commit, const char *buf);
void string_to_git_commits(fgit_commits *git_commit, const char *buf);
void commits_to_string(const fgit_commits *git_commit, char *buf);
void string_to_ignore_path(const char *buf);
void string_to_ignore_suffix(const char *buf);
void def_c_paths_to_versions(const def_c_paths * c_paths, fgit_versions *v_version);
void versions_to_string(char *buf, const fgit_versions *in_versions);
void string_to_versions(const char *buf, fgit_versions *in_versions);
void commits_to_versions(const fgit_commits *git_commit, fgit_versions_list *in_versions);
const struct simple_c_guid *find_file_list_crc(const char *fliename);
unsigned int find_file_list_filesize(const simple_c_guid *crc);
const char* find_file_list_filename(const simple_c_guid* crc);
ffile_info* find_file_list_version_crc(const simple_c_guid* crc);
ffile_info* find_file_list_version_by_filename(const char* fliename);
int find_file_list_version_by_index(const char* fliename);
bool is_exit_filename_in_filelist_by_filename(const char* fliename);
bool is_exit_filename_in_filelist_by_crc(const simple_c_guid* crc);
void init_file_info(ffile_info* info);
void init_file_list();
void save_file_list();
void read_file_list();
void add_files_list_unique(const fgit_versions *v);
void add_file_list_unique(const fgit_version* git_version);
void remove_file_list_unique(const ffile_info* fi);
void add_file_list(const fgit_version * git_version);
void replace_file_list(int index ,const fgit_version* git_version);
void replace_file_list_s(ffile_info *info, const fgit_version* git_version);
bool add_file_list_check(const fgit_version* git_version);
//将相同版本和不同版本合并为一个具有相同和不同的版本
void compare_list_combine(const fgit_versions *in_versions_a, const fgit_versions *in_versions_b, fgit_versions *out_versions);
//寻找两个版本中 不存在的版本
void compare_list_exit(const fgit_versions *in_versions_a, const fgit_versions *in_versions_b, fgit_versions *out_versions);
const char *get_git_project_path();
const char *get_git_server_cache_path();
const char *get_git_version_filename();
const char *get_git_current_version_filename();
const char *get_git_path();
void init_server(int argc, char *argv[]);
void listening_clients();
void close_server();
bool is_exit_ignore(const char *path);
unsigned char get_protocal(); // 定义255个协议
void get_protocal_content(char *buf);
客户端源码.h
// Copyright (C) RenZhai.2019.All Rights Reserved.
/*
下面的网址讲解了如何使用git renzhai 的版本控制
DocURL: https://www.bilibili.com/video/BV1x5411s7s3
下面的网址讲解如何入门c语言
MarketplaceURL : https://www.aboutcg.org/courseDetails/902/introduce
如果想了解更多关于UE4教程请参考:
URL : https://zhuanlan.zhihu.com/p/60117613
如果想系统了解人宅系列教程以及相关插件迭代更新 可以关注我的博客
URL : //renzhai.net/
如果想了解我们下一节的课程安排可以 可以在微信公众号搜所 人宅 关注即可 我们会推送很多富有技术的文章
新浪博客 https://weibo.com/BZRZ/profile?s=6cm7D0 //这个博客从16年到现在 有三四年没怎么用过 以后说不定可以重新启用 先发个连接
*/
#pragma once
#include "protocal.h"
char project_name[MAX_PATH] = { 0 };
char git_current_version_filename[MAX_PATH] = { 0 };
char git_version_filename[MAX_PATH] = { 0 };
char git_path[MAX_PATH] = { 0 };
char git_client_cache_path[MAX_PATH] = { 0 };
char git_project_remote_url[MAX_PATH] = { 0 };// 远端仓库
char git_project_path[MAX_PATH] = { 0 };//git路径 .git
char git_remote_origin[MAX_PATH] = { 0 };//远端路径 url
char git_local_cofg_filename[MAX_PATH] = { 0 };//用户配置信息
const char git_local_cofg_file[] = ".\\.git\\";//本地配置的目录
int b_exit = false;
//////////////////////////////////////////////////////////////////////////
typedef struct
{
int size;
char data[8196][1024];
}fpath;
fpath server_list, ignore_path, ignore_suffix;
//用户信息
typedef struct fgit_user
{
char name[MAX_PATH];
char password[MAX_PATH];
char email[MAX_PATH];
};
struct fgit_user user;
//提交版本的信息
typedef struct
{
char name[MAX_PATH];
char commit[MAX_PATH];
char date[MAX_PATH];
simple_c_guid guid;
}fgit_commit;
fgit_commit commit;
//fgit_commit Last_commit;
typedef struct
{
unsigned int size;
fgit_commit commits[1024];
}fgit_commits;
//git 的路径
typedef struct
{
char path_src[MAX_PATH];
char path_dis[MAX_PATH];
}fgit_path_2d;
//git 所有提交的所有路径
typedef struct
{
int size;
fgit_path_2d paths[MAX_PATH * 2];
}fgit_path_2ds;
fgit_path_2ds git_path_2ds;
//文件版本操作类型
typedef enum
{
NONE_File,
ADD_FILE,
SUBTRACT_FILE,
OVERLAP_FILE,
}eversion_operation_type;
//单个文件的版本
typedef struct
{
eversion_operation_type operation_type;
unsigned int file_size;
char file_name[MAX_PATH];//
simple_c_guid crc;
}fgit_version;
//整体文件的版本
typedef struct
{
unsigned int size;
fgit_version paths[1024];
}fgit_versions;
fgit_versions versions;
//整体文件版本列表
typedef struct
{
unsigned int size;
fgit_versions paths[1024];
}fgit_versions_list;
//Engine core
//////////////////////////////////////////////////////////////////////////
void init_path(fpath *p);
void init_git_commits(fgit_commits *git_commits);
void git_clone_funcation();
void version_iteration_update();
void string_to_path(const char *data,fpath* p);
void path_to_string( char* data,const fpath* p);
char *get_git_commit(fgit_commit *git_commit);
char *git_commit_to_string(const fgit_commit *git_commit,char *buf);
void string_to_git_commit(fgit_commit *git_commit,const char *buf);
void string_to_git_commits(fgit_commits *git_commit, const char *buf);
void string_to_ignore_path(const char *buf);
void string_to_ignore_suffix(const char *buf);
void compare_list(const fgit_versions* server_version_list, const def_c_paths* local_paths, def_c_paths* out_paths);
void init_versions(fgit_versions *in_versions);
void init_commit(fgit_commit *out_commit);
void init_git_path_2ds(fgit_path_2ds *path_2ds);
void add_git_versions(const char *int_path,eversion_operation_type type, fgit_versions *out_versions);
void versions_to_string(char *buf,const fgit_versions *in_versions);
void string_to_versions(const char *buf,fgit_versions *in_versions);
//core
void init_engine(int argc, char *argv[]);
void engine_loop();
void exit_engine();
//
void read_user();
//
void save_user();
//get
const char *get_git_version_filename();
const char *get_git_current_version_filename();
const char *get_git_path();
char *get_git_client_cache_path();
char *get_git_project_remote_url();
char *get_current_time();
char *get_git_project_path();
char *get_git_local_user_filename();
unsigned char get_protocal();
bool is_exit_ignore(const char *path);
//log
//////////////////////////////////////////////////////////////////////////
协议号
#pragma once
//Copyright (C) RenZhai.2019.All Rights Reserved.
//作者 人宅
//该c库的详细源码讲解在AboutCG 《手把手入门硬核c语言》视频工程里面:
//https://www.aboutcg.org/courseDetails/902/introduce
//希望学习其他方面技术 比如做UE4游戏, 可以访问下列网址:
//https://zhuanlan.zhihu.com/p/60117613
//
//bibi可以看到各个人宅系列教程介绍:
//https://space.bilibili.com/29544409
//
//个人博客网站
////renzhai.net
//
//关于本套案例的详细操作 :
//文字版本(详细):
//https://zhuanlan.zhihu.com/p/144558934
//视频版本:
//https://www.bilibili.com/video/BV1x5411s7s3
#include "git.h"
_CRT_BEGIN_C_HEADER
typedef enum
{
NONE = 0, //什么都不发生
HELLO, //客户端 向服务器 发送 确认 用于链接
HEI, //服务器反馈
COMMIT, //提交信息
COMMIT_VERSION_LIST, //提交版本列表
VERSION_LOG, //请求服务端 版本提交日志
VERSION_STATUS, //版本修改内容 本次版本状态
PROTOCAL_ERROR, //在服务器发生的错误信息
VERSION_PROTOCAL, //获取最新服务器版本信息
VERSION_LIST, //获取最新服务器版本列表
VERSION_NEST, //获取在本版本号的基础上的下一个版本号
VERSION_NEST_COMPLETE, //服务器版本列表发送成功
VERSION_CLASH, //检测 冲突
CLASH_CONTENT, //获取 冲突 内容
NO_CLASH, //无冲突
CHECK_REMOVE_FILENAME, //检查有没有存在客户端删除的副本 有就通知服务端删除该数据
REMOVE_CONTENT, //提交移除的内容
GIT_CLONE, //克隆服务端数据
FILE_EXIT, //文件是否存在
FIND_VERSION_LIST, //根据版本路径寻找数据对应版本内容
CONNECT_TIME_OUT, //连接超时
REMOVE_LOCAL_REQUEST, //发送客户端移除 协议
SAVE_VERSION_REQUEST, //通知服务器 存储当前版本
GIT_RESET_VERSION, //还原版本
}egit_protocal_type;
_CRT_END_C_HEADER
特别提示
本git小程序的内存管理非动态内存,是固定分配一定份额的内存,如果用完就会产生奔溃,支持的项目为小型项目,
比如c或者c++源码等内容版本更新迭代,以后可以考虑扩展为动态内存。
本程序仅仅提供学习,在学习本程序请结合源码学习.
发表回复
要发表评论,您必须先登录。