C++ 操作Git仓库

news2024/9/20 14:43:43
代码
#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");
	else
		git_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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1965366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python零基础详细入门教程

Python零基础详细入门教程可以从以下几个方面展开&#xff0c;帮助初学者系统地学习Python编程&#xff1a; 一、Python基础入门 1. Python简介 Python的由来与发展&#xff1a;Python是一种广泛使用的高级编程语言&#xff0c;以其简洁的语法和强大的功能而受到开发者的喜爱…

2024第二十届中国国际粮油产品及设备技术展示交易会

2024第二十届中国国际粮油产品及设备技术展示交易会 时间&#xff1a;2024年11月15-17日 地点&#xff1a; 南昌绿地国际博览中心 展会介绍&#xff1a; 随着国家逐年加大对农业的投入&#xff0c;调整农业产业结构&#xff0c;提高农产品附加值&#xff0c;促进农民增收。…

CRMEB-众邦科技 使用笔记

1.启动项目报错 Unable to load authentication plugin ‘caching_sha2_password’. 参考&#xff1a;http://t.csdnimg.cn/5EqaE 解决办法&#xff1a;升级mysql驱动 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</ar…

超级弱口令检查工具

一、背景 弱口令问题主要源于用户和管理员的安全意识不足&#xff0c;以及为了方便记忆而采用简单易记的密码。这些密码往往仅包含简单的数字和字母&#xff0c;缺乏复杂性和多样性&#xff0c;因此极易被破解。弱口令的存在严重威胁到系统和用户的数据安全&#xff0c;使得攻击…

在局域网中的另一台主机如何访问windows10WSL中的服务

文章目录 1&#xff0c;开启win10 路由功能2&#xff0c;配置转发规则 1&#xff0c;开启win10 路由功能 2&#xff0c;配置转发规则 netsh advfirewall firewall add rule name"Allowing LAN connections" dirin actionallow protocolTCP localport80 netsh interf…

计算机体系结构:缓存一致性ESI

集中式缓存处理器结构&#xff08;SMP&#xff09; 不同核访问存储器时间相同。 分布式缓存处理器结构&#xff08;NUMA&#xff09; 共享存储器按模块分散在各处理器附近&#xff0c;处理器访问本地存储器和远程存储器的延迟不同&#xff0c;共享数据可进入处理器私有高速缓存…

程序员自曝接单:三年时间接了25个单子,收入12万

程序员接单在程序员的副业中并不少见。程序员接单作为一个起步快、门槛低、类型多样的副业选择&#xff0c;一直深受程序员的青睐。就算你没有接触过接单&#xff0c;也一定对接单有过了解。 程序员接单是指程序员通过接取开发者发布的项目或任务来获取收入的一种工作方式。程序…

“八股文”的江湖:助力、阻力还是空谈?深度解析程序员面试的敲门砖

一、引言&#xff1a;八股文的江湖——助力、阻力还是空谈&#xff1f; 1.1 八股文的定义与背景 八股文&#xff0c;原指我国明清时期科举考试的一种应试文体&#xff0c;因其固定模式和空洞内容而备受诟病。在当今的程序员面试中&#xff0c;程序员的“八股文”通常指的是在技…

告别手动操作:这个微信自动化工具你一定要试试!

随着科技的发展&#xff0c;越来越多的自动化工具应运而生&#xff0c;帮助我们轻松管理微信号。 今天&#xff0c;就给大家揭开这个能让微信自动化的工具的神秘面纱&#xff0c;看看它们能为我们的工作带来哪些便利。 1、批量自动加好友 通过个微管理系统&#xff0c;你可以…

【Unity】 HTFramework框架(五十四)Deployment 轻量级资源部署管线

更新日期&#xff1a;2024年7月31日。 Github源码&#xff1a;[点我获取源码] 索引 Deployment 轻量级资源部署管线使用 Deployment一、创建部署配置二、编辑部署配置三、正式开始资源部署步骤一&#xff1a;资源打包步骤二&#xff1a;资源版本构建步骤三&#xff1a;资源版本…

Redis 初步认识

目录 1. 概述 2. 数据结构 3. 使用方式 4. 优势 1. 概述 Redis &#xff08;remote directory server&#xff09;是一个开源的基于内存的数据存储系统&#xff1b; 可以用作数据库缓存和消息队列等各种场景&#xff0c;也是目前最热门的 NoSQL 数据库之一&#xff1b; 早…

java算法递归算法练习-数组之和

简单找个题目练习一下递归算法&#xff0c;输入一组数组&#xff0c;使用递归的方法计算数组之和。其实这个题目&#xff0c;用循环的方式也很简单就能解决&#xff0c;直接循环遍历一下相加就行了&#xff0c;但是我们用来练习一下递归。 先来找基线条件和递归条件 基线条件…

Stable Diffusion AI 绘画 之 ControlNet 插件及其对应模型的下载安装

一、介绍 ControlNet: ControlNet是一种通过添加附加条件来控制扩散模型&#xff08;例如Stable Diffusion&#xff09;的神经网络结构。一般的使用方法是结合Stable Diffusion来做到精准控图。 通过上面的方式&#xff0c;ControlNet 可以重用SD编码器作为一个深度&#xff0…

企业版邮箱如何提升效率

企业邮箱是如何提升企业效率的呢&#xff1f;企业版邮箱通过专业形象、安全性、稳定性、集成能力等优势提升效率&#xff0c;支持高效内部沟通、团队协作、客户关系管理、安全性与合规性&#xff0c;并支持远程工作&#xff0c;是企业必备的高效工具。 一、企业版邮箱的基本功…

【通俗理解】神经网络动力学——从梯度下降到拓扑结构的桥梁

【通俗理解】神经网络动力学——从梯度下降到拓扑结构的桥梁 神经网络与动力学的类比 你可以把神经网络看作是一个“城市”&#xff0c;其中的神经元是“居民”&#xff0c;他们通过连接&#xff08;道路&#xff09;交互。而动力学则是一个“交通分析师”&#xff0c;它研究居…

【MySQL】事务 【下】{重点了解读-写 4个记录隐藏列字段 undo log日志 模拟MVCC Read View sel}

文章目录 1.MVCC数据库并发的场景重点了解 读-写4个记录隐藏列字段 2.理解事务undo log日志mysql日志简介 模拟MVCC 3.Read Viewselect lock in share modeMVCC流程RR与RC 1.MVCC MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09;是…

typora简单使用教程

一、下载安装typora Typora是一款流行的Markdown文本编辑器&#xff0c;作者是按照这篇文章完成了typora的下载和安装的&#xff1a;http://t.csdnimg.cn/D2U1U 二、偏好设置 进入界面&#xff0c;点击“文件”&#xff0c;点击“偏好设置”。 三、基本使用 作者是跟着这个…

如何解决 hCaptcha:全面指南

hCaptcha 是一种注重隐私的验证码服务&#xff0c;因其有效性和独特的挑战而广受欢迎。值得注意的是&#xff0c;hCaptcha 具有一定的技术复杂性。本指南将探讨 hCaptcha 的特性&#xff0c;并提供自动化解决方法。 什么是 hCaptcha 及其挑战 hCaptcha 以其基于图像的挑战而闻…

mysql--表的基本操作(curd)

一&#xff0c;表的创建 语法&#xff1a; 如果创建表没有指定字符集存储引擎&#xff0c;默认是继承表所在的数据库的。 修改表的字段 &#xff08;1&#xff09;增加 ALTER TABLE tablename ADD (column datatype [DEFAULT expr][,column datatype]...); &#xff08;2&am…

MoE:混合专家模型介绍(一)

MoE&#xff1a;混合专家模型介绍&#xff08;一&#xff09; 本文是对混合专家模型 (MoE) 详解重点摘要与归纳&#xff0c;有兴趣的小伙伴可以点击链接阅读原文。 混合专家模型 (MoEs)特点 与稠密模型相比&#xff0c;预训练速度更快与具有相同参数数量的模型相比&#xff…