Skip to content

Instantly share code, notes, and snippets.

@scunz
Created September 9, 2012 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scunz/3684702 to your computer and use it in GitHub Desktop.
Save scunz/3684702 to your computer and use it in GitHub Desktop.
Prove that git_mergebase + 2x git_revwalk can _not_ be used to find the "is 5 ahead 3 behind foo"
#include <assert.h>
#include <stdio.h>
#include <memory.h>
#include "git2.h"
char* gerr = 0;
int find_divergence_single(
git_repository* repo,
const git_oid* base,
const git_oid* dest,
int* steps )
{
int rc;
git_revwalk* walk = NULL;
git_oid current;
assert( base && repo && dest && steps );
if( git_oid_cmp( base, dest ) == 0 )
{
*steps = 0;
return 0;
}
if( git_revwalk_new( &walk, repo ) < 0 )
{
gerr = "Cannot create a walk";
return -1;
}
if( !git_revwalk_push( walk, dest ) < 0 )
{
gerr = "Cannot push base";
return -1;
}
git_revwalk_sorting( walk, GIT_SORT_TOPOLOGICAL );
while( ( rc = git_revwalk_next( &current, walk ) ) >= 0 )
{
if( rc == GIT_ITEROVER )
{
gerr = "dest does not follow to base";
return -1;
}
else if( rc < 0 )
{
gerr = "Cannot walk";
return -1;
}
if( git_oid_cmp( &current, base ) == 0 )
{
break;
}
++(*steps);
}
git_revwalk_free( walk );
return 0;
}
int find_divergence(
git_repository* repo,
const git_oid* me,
const git_oid* they,
int* ahead,
int* behind )
{
char oid_a[41], oid_b[41], oid_c[41];
assert( repo && me && they && ahead && behind );
*ahead = *behind = 0;
git_oid merge_base;
if( git_merge_base( &merge_base, repo, (git_oid*)me, (git_oid*)they ) < 0 )
{
const git_error* e = giterr_last();
printf( "ERR: %s\n", e ? e->message : "???" );
gerr = "Cannot find merge base";
return -2;
}
git_oid_fmt( oid_a, me ); oid_a[ 40 ] = 0;
git_oid_fmt( oid_b, they ); oid_b[ 40 ] = 0;
git_oid_fmt( oid_c, &merge_base ); oid_c[ 40 ] = 0;
// printf( "Base of '%s' and '%s' is '%s'\n", &oid_a[0], &oid_b[0], &oid_c[0] );
if( find_divergence_single( repo, &merge_base, me, ahead ) < 0 )
{
return -1;
}
if( find_divergence_single( repo, &merge_base, they, behind ) < 0 )
{
return -1;
}
return 0;
}
git_oid tags[5];
int read_tags( git_repository* repo )
{
int i;
char oidstr[41];
char tagname[] = "refs/tags/t0";
for( i = 0; i < 5; i++ )
{
tagname[ 11 ] = '1' + i;
if( git_reference_name_to_oid( &tags[ i ], repo, tagname ) < 0 )
{
return -1;
}
git_oid_fmt( oidstr, &tags[ i ] );
printf( "Tag '%s' is at %s\n", &tagname[0], oidstr );
}
return 0;
}
int main(void)
{
int a, b, i, j, rc;
git_repository* repo = NULL;
git_threads_init();
if( git_repository_open( &repo, "../merge_base_test" ) < 0 )
{
puts( "Cannot find repo" );
return -1;
}
read_tags( repo );
for( i = 0; i < 5; i++ )
{
for( j = 0; j < 5; j++ )
{
if( ( rc = find_divergence( repo, &tags[ i ], &tags[ j ], &a, &b ) ) < 0 )
{
printf( "Error: %s\n", gerr );
if( rc != -2 )
{
return -1;
}
}
if( rc == -2 )
{
printf( "t%i is not related to t%i\n",
i+1, j+1 );
}
else
{
printf( "t%i is %i ahead and %i behind of t%i\n",
i+1, a, b, j+1 );
}
fflush(stdout);
}
}
git_repository_free( repo );
git_threads_shutdown();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment