当前位置: 首页 > news >正文

C++ 操作Git仓库

代码
#include "common.h"
#include "args.c"
#include "common.c"enum index_mode {INDEX_NONE,INDEX_ADD
};struct index_options {int dry_run;int verbose;git_repository* repo;enum index_mode mode;int add_update;
};/* Forward declarations for helpers */
static void parse_opts(const char** repo_path, struct index_options* opts, struct args_info* args);
int print_matched_cb(const char* path, const char* matched_pathspec, void* payload);int lg2_add(git_repository* repo, int argc, char** argv)
{git_index_matched_path_cb matched_cb = NULL;git_index* index;git_strarray array = { 0 };struct index_options options = { 0 };struct args_info args = ARGS_INFO_INIT;options.mode = INDEX_ADD;/* Parse the options & arguments. */parse_opts(NULL, &options, &args);strarray_from_args(&array, &args);/* Grab the repository's index. */check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);/* Setup a callback if the requested options need it */if (options.verbose || options.dry_run) {matched_cb = &print_matched_cb;}options.repo = repo;/* Perform the requested action with the index and files */if (options.add_update) {git_index_update_all(index, &array, matched_cb, &options);}else {git_index_add_all(index, &array, 0, matched_cb, &options);}/* Cleanup memory */git_index_write(index);git_index_free(index);return 0;
}/** This callback is called for each file under consideration by* git_index_(update|add)_all above.* It makes uses of the callback's ability to abort the action.*/
int print_matched_cb(const char* path, const char* matched_pathspec, void* payload)
{struct index_options* opts = (struct index_options*)(payload);int ret;unsigned status;(void)matched_pathspec;/* Get the file status */if (git_status_file(&status, opts->repo, path) < 0)return -1;if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {printf("add '%s'\n", path);ret = 0;}else {ret = 1;}if (opts->dry_run)ret = 1;return ret;
}static void parse_opts(const char** repo_path, struct index_options* opts, struct args_info* args)
{if (args->argc <= 1)return;for (args->pos = 1; args->pos < args->argc; ++args->pos) {const char* curr = args->argv[args->pos];if (curr[0] != '-') {if (!strcmp("add", curr)) {opts->mode = INDEX_ADD;continue;}else if (opts->mode == INDEX_NONE) {fprintf(stderr, "missing command: %s", curr);break;}else {/* We might be looking at a filename */break;}}else if (match_bool_arg(&opts->verbose, args, "--verbose") ||match_bool_arg(&opts->dry_run, args, "--dry-run") ||match_str_arg(repo_path, args, "--git-dir") ||(opts->mode == INDEX_ADD && match_bool_arg(&opts->add_update, args, "--update"))) {continue;}else if (match_bool_arg(NULL, args, "--help")) {break;}else if (match_arg_separator(args)) {break;}else {fprintf(stderr, "Unsupported option %s.\n", curr);}}
}struct blame_opts {char* path;char* commitspec;int C;int M;int start_line;int end_line;int F;
};
static void parse_opts(struct blame_opts* o, int argc, char* argv[]);int lg2_blame(git_repository* repo, int argc, char* argv[])
{int line, break_on_null_hunk;git_object_size_t i, rawsize;char spec[1024] = { 0 };struct blame_opts o = { 0 };const char* rawdata;git_revspec revspec = { 0 };git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT;git_blame* blame = NULL;git_blob* blob;git_object* obj;parse_opts(&o, argc, argv);if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT;if (o.start_line && o.end_line) {blameopts.min_line = o.start_line;blameopts.max_line = o.end_line;}/*** The commit range comes in "committish" form. Use the rev-parse API to* nail down the end points.*/if (o.commitspec) {check_lg2(git_revparse(&revspec, repo, o.commitspec), "Couldn't parse commit spec", NULL);if (revspec.flags & GIT_REVSPEC_SINGLE) {git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.from));git_object_free(revspec.from);}else {git_oid_cpy(&blameopts.oldest_commit, git_object_id(revspec.from));git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.to));git_object_free(revspec.from);git_object_free(revspec.to);}}/** Run the blame. */check_lg2(git_blame_file(&blame, repo, o.path, &blameopts), "Blame error", NULL);/*** Get the raw data inside the blob for output. We use the* `committish:path/to/file.txt` format to find it.*/if (git_oid_is_zero(&blameopts.newest_commit))strcpy(spec, "HEAD");elsegit_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit);strcat(spec, ":");strcat(spec, o.path);check_lg2(git_revparse_single(&obj, repo, spec), "Object lookup error", NULL);check_lg2(git_blob_lookup(&blob, repo, git_object_id(obj)), "Blob lookup error", NULL);git_object_free(obj);rawdata = (const char*)git_blob_rawcontent(blob);rawsize = git_blob_rawsize(blob);/** Produce the output. */line = 1;i = 0;break_on_null_hunk = 0;while (i < rawsize) {const char* eol = (const char*)memchr(rawdata + i, '\n', (size_t)(rawsize - i));char oid[10] = { 0 };const git_blame_hunk* hunk = git_blame_get_hunk_byline(blame, line);if (break_on_null_hunk && !hunk)break;if (hunk) {char sig[128] = { 0 };break_on_null_hunk = 1;git_oid_tostr(oid, 10, &hunk->final_commit_id);snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);printf("%s ( %-30s %3d) %.*s\n",oid,sig,line,(int)(eol - rawdata - i),rawdata + i);}i = (int)(eol - rawdata + 1);line++;}/** Cleanup. */git_blob_free(blob);git_blame_free(blame);return 0;
}/** Tell the user how to make this thing work. */
static void usage(const char* msg, const char* arg)
{if (msg && arg)fprintf(stderr, "%s: %s\n", msg, arg);else if (msg)fprintf(stderr, "%s\n", msg);fprintf(stderr, "usage: blame [options] [<commit range>] <path>\n");fprintf(stderr, "\n");fprintf(stderr, "   <commit range>      example: `HEAD~10..HEAD`, or `1234abcd`\n");fprintf(stderr, "   -L <n,m>            process only line range n-m, counting from 1\n");fprintf(stderr, "   -M                  find line moves within and across files\n");fprintf(stderr, "   -C                  find line copies within and across files\n");fprintf(stderr, "   -F                  follow only the first parent commits\n");fprintf(stderr, "\n");exit(1);
}/** Parse the arguments. */
static void parse_opts(struct blame_opts* o, int argc, char* argv[])
{int i;char* bare_args[3] = { 0 };if (argc < 2) usage(NULL, NULL);for (i = 1; i < argc; i++) {char* a = argv[i];if (a[0] != '-') {int i = 0;while (bare_args[i] && i < 3) ++i;if (i >= 3)usage("Invalid argument set", NULL);bare_args[i] = a;}else if (!strcmp(a, "--"))continue;else if (!strcasecmp(a, "-M"))o->M = 1;else if (!strcasecmp(a, "-C"))o->C = 1;else if (!strcasecmp(a, "-F"))o->F = 1;else if (!strcasecmp(a, "-L")) {i++; a = argv[i];if (i >= argc) fatal("Not enough arguments to -L", NULL);check_lg2(sscanf(a, "%d,%d", &o->start_line, &o->end_line) - 2, "-L format error", NULL);}else {/* commit range */if (o->commitspec) fatal("Only one commit spec allowed", NULL);o->commitspec = a;}}/* Handle the bare arguments */if (!bare_args[0]) usage("Please specify a path", NULL);o->path = bare_args[0];if (bare_args[1]) {/* <commitspec> <path> */o->path = bare_args[1];o->commitspec = bare_args[0];}if (bare_args[2]) {/* <oldcommit> <newcommit> <path> */char spec[128] = { 0 };o->path = bare_args[2];sprintf(spec, "%s..%s", bare_args[0], bare_args[1]);o->commitspec = spec;}
}// git add调用
void testAdd(git_repository* repo) {int argc = 2;//const char** argv = { "add", "--verbose", "--dry-run", "--git-dir", "--update", NULL };char* argv1 = "add";char* argv2 = "main.cpp";char* argv[] = { argv1, argv2, NULL };lg2_add(repo, argc, argv);
}// git blame调用
void testBlame(git_repository* repo) {int argc = 2;//const char** argv = { "add", "--verbose", "--dry-run", "--git-dir", "--update", NULL };char* argv1 = "blame ";char* argv2 = "`HEAD~10..HEAD`";char* argv3 = "-F";char* argv[] = { argv1, argv2, argv3, NULL };lg2_blame(repo, argc, argv);
}void test() {git_libgit2_init();git_repository* repo;const char* repo_path = "D:\\libgit2\\.git";auto error = git_repository_open(&repo, repo_path);if (error) {printf("open git error");return;}testAdd(repo);	// git add调用testBlame(repo);	// git blame调用git_repository_free(repo);
}
输出
Blame error [-3] - the path '`HEAD~10..HEAD`' does not exist in the given tree
 参考

https://github.com/libgit2/libgit2

Libraries / libqgit2 · GitLab


创作不易,小小的支持一下吧!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【C语言版】数据结构教程(一)绪论(上)
  • 1.GPIO
  • YAML语法格式详解
  • 为什么要使用双亲委派机制?
  • 一文搞懂GIT
  • 本地部署持续集成工具Jenkins并配置公网地址实现远程自动化构建
  • 【Android】数据存储之SQLite数据库知识总结
  • C语言数据在内存中的存储超详解
  • nacos 2.3.2 若依使用mysql
  • 智慧环卫可视化:科技赋能城市清洁管理
  • Java--二,十,十六进制间的相互转换
  • 【初阶数据结构篇】归并排序和计数排序(总结篇)
  • Python面试题:结合Python技术,如何使用Scrapy构建爬虫框架
  • [极客大挑战 2019]Secret File-web
  • 校园点餐系统
  • #Java异常处理
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 10个最佳ES6特性 ES7与ES8的特性
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • css布局,左右固定中间自适应实现
  • CSS居中完全指南——构建CSS居中决策树
  • express如何解决request entity too large问题
  • Git 使用集
  • Java IO学习笔记一
  • JavaWeb(学习笔记二)
  • Laravel Telescope:优雅的应用调试工具
  • Linux中的硬链接与软链接
  • Mysql5.6主从复制
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Python socket服务器端、客户端传送信息
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • SpiderData 2019年2月23日 DApp数据排行榜
  • vue 个人积累(使用工具,组件)
  • vue-cli3搭建项目
  • 程序员该如何有效的找工作?
  • 从输入URL到页面加载发生了什么
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 应用生命周期终极 DevOps 工具包
  • ​渐进式Web应用PWA的未来
  • #70结构体案例1(导师,学生,成绩)
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (2024)docker-compose实战 (9)部署多项目环境(LAMP+react+vue+redis+mysql+nginx)
  • (4)STL算法之比较
  • (笔记)M1使用hombrew安装qemu
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)ssm码农论坛 毕业设计 231126
  • (六)Flink 窗口计算
  • (算法设计与分析)第一章算法概述-习题
  • (译) 函数式 JS #1:简介
  • **《Linux/Unix系统编程手册》读书笔记24章**
  • .FileZilla的使用和主动模式被动模式介绍