How do I create a branch using the libgit2 library, the API has reference to a commit target, but what should I use for this parameter?
This is the code I have got so far, based on example code in tests, but they use many hard coded references so its difficult to discover what you should use in a real-world scenario like what i should pass as 'target' in this instance.
git_reference *branch = NULL, *head = NULL;
/* Create the branch */
git_branch_create( &branch, open_repo, "MyNewBranch", target, 0 );
/* Make HEAD point to this branch */
git_reference_symbolic_create( &head, open_repo, "HEAD", git_reference_name( branch ), 1 );
git_reference_free( head );
git_reference_free( branch );
what i should pass as 'target' in this instance.
The resolved commit that you'd like your new branch to point to.
As stated in the header
#param target Object to which this branch should point. This object
must belong to the given repo and can either be a git_commit or a
git_tag. When a git_tag is being passed, it should be dereferencable
to a git_commit which oid will be used as the target of the branch.
Note: Surprisingly, the header is not in sync with the code. The header makes the reader think that passing a git_object would be fine. However, only a git_commit is accepted.
Update
And how would i get 'the resolved commit';
Provided you know the oid of the commit, git_commit_lookup() would be the way to go.
If you're already having a hold on a git_object which happens to be a commit (git_object_type() returns GIT_OBJ_COMMIT), you could just cast it and pass (git_commit *)my_object to the function.
Related
i try to Checkout a Remotebranch via LibGitSharp. In git itself you use this comands:
git fetch origin
git checkout -b test origin/test
in newer Versions it is just:
git fetch
git checkout test
So i tried this Code:
repo.Fetch("origin");
repo.Checkout("origin/" + Name);
The Fetch and Checkout runs without any problems but there is no copy of the Remotebranch.
Does anyone have an idea to Checkout the Remote with other methods?
My alternative would be to create the Branch in the Repository and push it into Remote:
Branch newBranch = repo.Branches.Add(Name, repo.Branches["master"].Commits.First());
repo.Network.Push(newBranch);
but i get this Exception:
The branch 'Test1' ("refs/heads/Test1") that you are trying to push does not track an upstream branch.
maybe i could set the Branch to an upstream Branch, but i don't know how.
Edit: I haven't explained it properly, so I try to describe it better what the Fetch and Checkout does in my program. The Fetch command is performed correctly. Now if i use the checkout command it should be create an local Branch of the Remotebranch, but it doesn't. I've also tried repo.Checkout(name), without "origin/" ,but it cast an Exception: No valid git object identified by '...' exists in the repository.
If I correctly understand your question, you're willing to create a local branch which would be configured to track the fetched remote tracking branch.
In other words, once you fetch a repository, your references contains remote tracking branches (eg. origin/theBranch) and you'd like to create a local branch bearing the same name (eg. theBranch).
The following example should demonstrate how to do this
const string localBranchName = "theBranch";
// The local branch doesn't exist yet
Assert.Null(repo.Branches[localBranchName]);
// Let's get a reference on the remote tracking branch...
const string trackedBranchName = "origin/theBranch";
Branch trackedBranch = repo.Branches[trackedBranchName];
// ...and create a local branch pointing at the same Commit
Branch branch = repo.CreateBranch(localBranchName, trackedBranch.Tip);
// The local branch is not configured to track anything
Assert.False(branch.IsTracking);
// So, let's configure the local branch to track the remote one.
Branch updatedBranch = repo.Branches.Update(branch,
b => b.TrackedBranch = trackedBranch.CanonicalName);
// Bam! It's done.
Assert.True(updatedBranch.IsTracking);
Assert.Equal(trackedBranchName, updatedBranch.TrackedBranch.Name);
Note: More examples can be found in the BranchFixture.cs test suite.
My task is to do all these steps programmatically:
Create a new transport request, I managed to do this with TR_INSERT_REQUEST_WITH_TASKS
Add package content to the newly created transport, this is the part I am stuck in.
Release the transport, I managed to do this with TR_RELEASE_REQUEST
My problem is that I can manually add the package to the transport request via transaction SE03 and then release it with FM TR_RELEASE_REQUEST, but that is not the goal, everything from step 1 to 3 has to happen in one program execution if anyone can guide me how to do step 2 it would be very helpful, thanks in advance.
In your program, you must :
First get the list of objects which belong to the package, via the table TADIR (object in columns PGMID, OBJECT, OBJ_NAME, and package in column DEVCLASS)
And add these objects to the task or transport request via the non-released function modules TRINT_APPEND_COMM or TR_APPEND_TO_COMM_OBJS_KEYS.
To add the whole project into request you must first select all the objects from package and add them one by one. You can do it like this:
DATA: l_trkorr TYPE trkorr,
l_package TYPE devclass VALUE 'ZPACKAGE'.
cl_pak_package_queries=>get_all_subpackages( EXPORTING im_package = l_package
IMPORTING et_subpackages = DATA(lt_descendant) ).
INSERT VALUE cl_pak_package_queries=>ty_subpackage_info( package = l_package ) INTO TABLE lt_descendant.
SELECT pgmid, object, obj_name FROM tadir
INTO TABLE #DATA(lt_segw_objects)
FOR ALL ENTRIES IN #lt_descendant
WHERE devclass = #lt_descendant-package.
DATA(instance) = cl_adt_cts_management=>create_instance( ).
LOOP AT lt_segw_objects ASSIGNING FIELD-SYMBOL(<fs_obj>).
TRY.
instance->insert_objects_in_wb_request( EXPORTING pgmid = <fs_obj>-pgmid
object = <fs_obj>-object
obj_name = CONV trobj_name( <fs_obj>-obj_name )
IMPORTING result = DATA(result)
request = DATA(request)
CHANGING trkorr = l_trkorr ).
CATCH cx_adt_cts_insert_error.
ENDTRY.
ENDLOOP.
Note, that you cannot add objects that are already locked in another request, it will give you cx_adt_cts_insert_error exception. There is no way to unlock objects programmatically, only via SE03 tool.
You can check code behind, Write Transport Entry in SE80 right click on package menu.
I am trying to create a cache of POD6 by precompiling them using the CompUnit set of classes.
I can create, store and retrieve pod as follows:
use v6.c;
use nqp;
my $precomp-store = CompUnit::PrecompilationStore::File.new(prefix=>'cache'.IO);
my $precomp = CompUnit::PrecompilationRepository::Default.new(store=> $precomp-store );
my $key = nqp::sha1('test.pod6');
'test.pod6'.IO.spurt(q:to/CONTENT/);
=begin pod
=TITLE More and more
Some more text
=end pod
CONTENT
$precomp.precompile('test.pod6'.IO, $key, :force);
my $handle = $precomp.load($key, )[0];
my $resurrected = nqp::atkey($handle.unit,'$=pod')[0];
say $resurrected ~~ Pod::Block::Named;
So now I change the POD, how do I use the :since flag? I thought that if :since contains a time after the compilation, then the value of the handle would be Nil. That does not seem to be the case.
my $new-handle = $precomp.load($key, :since('test.pod6'.IO.modified));
say 'I got a new handle' with $new-handle;
Output is 'I got a new handle'.
What I am doing wrong?
Here is a pastebin link with code and output: https://pastebin.com/wtA9a0nP
Module loading code caches look ups and essentially start with:
$lock.protect: {
return %loaded{$id} if %loaded{$id}:exists;
}
So the question becomes "how do I load a module and then unload it (so i can load it again)?" to which the answer is: you cannot unload a module. You can however change the filename, distribution longname ( via changing the name, auth, api, or version ), or precomp id -- whatever a specific CompUnit::Repository uses to uniquely identify modules -- to bypass the cache.
What seems to be overlooked is that $key is intended to represent an immutable name, such that it will always point at the same content. What version of foo.pm should be loaded for Module Used::Inside::A if foo.pm is being loaded by Module A and B at the same time, Module A loads foo first, and then Module B modifies foo? The old version Module A loaded, or the ( possibly conflicting with previous version ) Module B loaded version? And how would this differentiation work for precomp file generation themselves ( which again can happen in parallel )?
Of course if we ignore the above we could add code to make expensive .IO.modified calls for every single module load for all CompUnit::Repository types ( slowing down startup speed ) to say "hey this immutable thing changed". But the granularity of file system modified timestamps on some OS's made the check pretty fragile ( especially for multi-threaded module loading with precomp files being generated ), meaning that even more expensive calls to get a checksum would be necessary every single time.
There is a sha value represent to the status for git repository in current status?
The sha value to be updated each time the Object Database updated and References changed if git has this sha value.
In other words, the sha value represent to the current version of whole repository.
Here is my code for calculate a sha for current references. There is a git level API or interface?
private string CalcBranchesSha(bool includeTags = false)
{
var sb = new StringBuilder();
sb.Append(":HEAD");
if (_repository.Head.Tip != null)
sb.Append(_repository.Head.Tip.Sha);
sb.Append(';');
foreach (var branch in _repository.Branches.OrderBy(s => s.Name))
{
sb.Append(':');
sb.Append(branch.Name);
if (branch.Tip != null)
sb.Append(branch.Tip.Sha);
}
sb.Append(';');
if (includeTags)
{
foreach (var tag in _repository.Tags.OrderBy(s => s.Name))
{
sb.Append(':');
sb.Append(tag.Name);
if (tag.Target != null)
sb.Append(tag.Target.Sha);
}
}
return sb.ToString().CalcSha();
}
There is a sha value represent to the status for git repository in current status?
In git parlance, the status of a repository usually refers to the paths that have differences between the working directory, the index and the current HEAD commit.
However, it doesn't look like you're after this. From what I understand, you're trying to calculate a checksum that represents the state of the current repository (ie. what your branches and tags point to).
Regarding the code, it may be improved in some ways to get a more precise checksum:
Account for all the references (beside refs/tags and refs/heads) in the repository (think refs/stash, refs/notes or the generated backup references in refs/original when one rewrite the history of a repository).
Consider disambiguating symbolic from direct references. (ie: HEAD->master->08a4217 should lead to a different checksum than HEAD->08a4127)
Below a modified version of the code which deals with those two points above, by leveraging the Refs namespace:
private string CalculateRepositoryStateSha(IRepository repo)
{
var sb = new StringBuilder();
sb.Append(":HEAD");
sb.Append(repo.Refs.Head.TargetIdentifier);
sb.Append(';');
foreach (var reference in repo.Refs.OrderBy(r => r.CanonicalName))
{
sb.Append(':');
sb.Append(reference.CanonicalName);
sb.Append(reference.TargetIdentifier);
sb.Append(';');
}
return sb.ToString().CalcSha();
}
Please keep in mind the following limits:
This doesn't consider the changes to the index or the workdir (eg. the same checksum will be returned either a file has been staged or not)
There are ways to create object in the object database without modifying the references. Those kind of changes won't be reflected with the code above. One possible hack-ish way to do this could be to also append to the StringBuuilder, the number of object in the object database (ie. repo.ObjectDatabase.Count()), but that may hinder the overall performance as this will enumerate all the objects each time the checksum is calculated).
There is a git level API or interface?
I don't know of any equivalent native function in git (although similar result may be achieved through some scripting). There's nothing native in libgit2 or Libgit2Sharp APIs.
I am trying to use libgit2 to read the name of the current branch. Do I have to do some sort of resolve?
I tried using
git_branch_lookup
to look up the git_reference for HEAD, but it results in
Unable to find local branch 'HEAD'
Thanks!
Running git branch -a doesn't list HEAD. In libgit2, HEAD isn't considered a valid branch either. It's only a reference.
If you want to discover which reference is the current branch, then you should
Load the current HEAD reference (try the git_repository_head() convenience method)
Determine its type (using git_reference_type())
Depending on its type (GIT_REF_SYMBOLIC or GIT_REF_OID) retrieve one of the following
The name of the branch (using git_reference_symbolic_target())
The commit being pointed at (using git_reference_target())
I did not find the existing answer/comments helpful, when having this exact problem. Instead I combined git_reference_lookup() and git_reference_symbolic_target().
git_reference* head_ref;
git_reference_lookup(&head_ref, repo, "HEAD");
const char *symbolic_ref;
symbolic_ref = git_reference_symbolic_target(head_ref);
std::string result;
// Skip leading "refs/heads/" -- 11 chars.
if (symbolic_ref) result = &symbolic_ref[11];
git_reference_free(head_ref);
This feels like something of a dirty hack, but it's the best I've managed. The result string either ends up empty (e.g. detached head, there is no checked out branch) or contains the name of the checked out branch. The symbolic target is owned by the ref, so copy that value into the string before freeing it!
There is an example for this at https://libgit2.org/libgit2/ex/HEAD/status.html . It is based around the method get_reference_shorthand. This should give the branch name instead of the reference, so no string manipulation needed, and it should also work in the edge case where branch and remote have different names.
static void show_branch(git_repository *repo, int format)
{
int error = 0;
const char *branch = NULL;
git_reference *head = NULL;
error = git_repository_head(&head, repo);
if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
branch = NULL;
else if (!error) {
branch = git_reference_shorthand(head);
} else
check_lg2(error, "failed to get current branch", NULL);
if (format == FORMAT_LONG)
printf("# On branch %s\n",
branch ? branch : "Not currently on any branch.");
else
printf("## %s\n", branch ? branch : "HEAD (no branch)");
git_reference_free(head);
}