Skip to content

Acquire last effected commit for a git object #2217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/git2/commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "oid.h"
#include "object.h"

#define VISITED (1 << 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this #define be private and moved into the .c file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flags should go with the other ones in src/commit_list.h, and it should not override the meaning of existing ones.


/**
* @file git2/commit.h
* @brief Git commit parsing, formatting routines
Expand Down Expand Up @@ -351,6 +353,12 @@ GIT_EXTERN(int) git_commit_amend(
const char *message,
const git_tree *tree);

GIT_EXTERN(int) git_commit_entry_last_commit_id(
git_oid *out,
const git_repository *repo,
const git_commit *commit,
const char *path);

/** @} */
GIT_END_DECL
#endif
93 changes: 93 additions & 0 deletions src/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
#include "common.h"
#include "odb.h"
#include "commit.h"
#include "commit_list.h"
#include "signature.h"
#include "message.h"
#include "revwalk.h"

void git_commit__free(void *_commit)
{
Expand Down Expand Up @@ -477,3 +479,94 @@ int git_commit_nth_gen_ancestor(
*ancestor = parent;
return 0;
}

int git_commit_entry_last_commit_id(git_oid *out, git_repository *repo, const git_commit *commit, char *path)
{
int error;
unsigned int i;
bool go;
git_revwalk *walk;
git_tree *root_tree;
git_tree_entry *source_tree_entry;
git_commit_list *list = NULL, *next = NULL;
git_commit_list_node *node;

assert(out && commit && path);

if ((error = git_commit_tree(&root_tree, commit)) < 0)
return error;

if ((error = git_tree_entry_bypath(&source_tree_entry, root_tree, path)) < 0)
return GIT_ENOTFOUND;

if (git_revwalk_new(&walk, repo) < 0)
return -1;

if ((node = git_revwalk__commit_lookup(walk, &commit->object.cached.oid)) == NULL)
return -1;

if (git_commit_list_insert(node, &list) == NULL)
return -1;

while (list) {
node = list->item;
next = list->next;
go = false;

if (error = git_commit_list_parse(walk, node) < 0)
return error;

for (i = 0; i < node->out_degree; i++) {
git_commit_list_node *p = node->parents[i];
git_tree_entry *entry;
git_commit *parent;
bool eq;

if ((error = git_commit_lookup(&parent, repo, &p->oid)))
goto cleanup;

if ((error = git_commit_tree(&root_tree, parent)) < 0)
goto cleanup;

if ((error = git_tree_entry_bypath(&entry, root_tree, path)) < 0) {
if (error == GIT_ENOTFOUND) {
error = GIT_OK;
continue;
}
goto cleanup;
}
eq = git_oid__cmp(&entry->oid, &source_tree_entry->oid) == 0;

if (eq &&!(p->flags & VISITED)) {
if ((node = git_revwalk__commit_lookup(walk, &parent->object.cached.oid)) == NULL)
return -1;

if (git_commit_list_insert(node, &next) == NULL) {
error = GIT_ERROR;
goto cleanup;
}
p->flags |= VISITED;
}
go = go || eq;
}

if (!go)
break;

git__free(list);
list = next;
}

git_oid_cpy(out, &list->item->oid);

cleanup:
while (list)
{
next = list->next;
git__free(list);
list = next;
}
git_revwalk_free(walk);

return error;
}