add already tracked file to index - libgit2

in git it would be
1. create file a.txt
2. commit file a.txt
3. a.txt is tracked
I can do that in libgit2 easily.
However, If I modify a.txt and wanted to add it to index I will do
git add a.txt
Unfortunately I cannot emulate that with libgit2. I have tried virtually everything the internet offered yet nothing worked. So I feel I miss something basic here. Note that I can add new files that aren't tracked to index with no problem, only I cannot find the way to add them.
Here is the code that I have.
void add_file(char *file)
{
git_index *index;
int error;
const git_index_entry *entry;
git_index_entry new_entry;
error = git_repository_index(&index, m_repo);
entry = git_index_get_bypath(index,file, 0);
if(entry)
{
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = file;
new_entry.mode = GIT_FILEMODE_BLOB;
error = git_index_add(index, &entry);
}
else
error = git_index_add_bypath(index, file);
error = git_index_write(index);
git_index_free(index);
}
EDIT:
After Ed's post I update my code but it is still adding only new files that aren't tracked.
git_index *index;
git_oid tree;
int error;
error = git_repository_index(&index, m_repo);
error = git_index_add_bypath(index, file);
error = git_index_write(index);
error = git_index_write_tree(&tree, index);
git_index_free(index);

Your git_index_get_bypath gives you the index entry as it exists currently. You're then memcpying the entry that is in the index and git_index_adding it right back. You're not actually changing the entry at all.
(That is, unless the index entry is currently executable. In which case you are removing the execute bit by setting the mode to GIT_FILEMODE_BLOB.)
You probably don't want to use git_index_add here, as that actually edits the low-level contents of the index directly. You would need to add the file to the object database and then update the index with the resultant OID.
If the file is changed on disk, then just run git_index_add_bypath and let libgit2 update the index with the contents as they exist on disk.

Related

Why redis RENAME executes an implicit DEL rather than UNLINK?

As the docs of RENAME says:
Renames key to newkey. It returns an error when key does not exist. If newkey already exists it is overwritten, when this happens RENAME executes an implicit DEL operation, so if the deleted key contains a very big value it may cause high latency even if RENAME itself is usually a constant-time operation.
As we know, DEL is blocking while UNLINK is non-blocking.
So I have two questions:
If the deleted key contains a very big value, it seems that executing an implicit UNLINK would be better. Why redis determines to use DEL?
If I manully execute UNLINK then RENAME with transaction, will the high latency be avoided?
The "implicit DEL operation" is not the same as a DEL command called by a user.
You can config it to use async or sync delete. The reason behind it is to probably give the user more control.
In the redis config file, on the part of LAZY FREEING, it says
DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled.
It's up to the design of the application to understand when it is a good
idea to use one or the other. However the Redis server sometimes has to
delete keys or flush the whole database as a side effect of other operations.**
Specifically Redis deletes objects independently of a user call in the
following scenarios:
....
For example the RENAME command may delete the old key content when it is replaced with >another one.
....
In all the above cases the default is to delete objects in a blocking way,
like if DEL was called. However you can configure each case specifically
in order to instead release memory in a non-blocking way like if UNLINK
was called, using the following configuration directives.
Then there's the config
lazyfree-lazy-server-del no
Just switch it to YES then it will behave like UNLINK
I checked the source code,
For Redis version 5.0, this function is called when you call RENAME command
void renameGenericCommand(client *c, int nx) {
// some code....
// When source and dest key is the same, no operation is performed,
// if the key exists, however we still return an error on unexisting key.
if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) samekey = 1;
// some code ...
if (samekey) {
addReply(c,nx ? shared.czero : shared.ok);
return;
}
...
/* Overwrite: delete the old key before creating the new one
* with the same name. */
dbDelete(c->db,c->argv[2]);
}
This is the dbDelete function it called
int dbDelete(redisDb *db, robj *key) {
return server.lazyfree_lazy_server_del ? dbAsyncDelete(db,key) :
dbSyncDelete(db,key);
}
As you can see, it does refer to the config of lazyfree-lazy-server-del

"Resource not valid: must be an absolute path with no references to parent directories" error when iterating through a folder

I'm new to Rust and the ggez game engine, and I am trying to load in a bunch of images from one folder. I keep getting the same error.
I've tried using the Path type, Strings, full directory to the file, and string literals and nothing seems to work. I've spent about 6 hours of coding on this issue.
This is the code that seems to be the problem:
for number in 0..read_dir("resources/images")?.count() - 1 {
let image_path = format!("{0}/{1}.png", "resources/images", number);
images.push(graphics::Image::new(ctx, image_path)?);
}
I expect all the files to load in. It's that simple.
Here's a git repository of a MCVE.
I've also tried using the DirEntry type:
for (number, item) in fs::read_dir(&images_path)?.enumerate() {
images.push(graphics::Image::new(ctx, item?.path())?);
}
It yields the same error.

Why does GetBasicPropertiesAsync() sometimes throw an Exception?

In Windows8, I'm trying to use GetBasicPropertiesAsync() to get the size of a newly created file. Sometimes, but not always (~25% of the time), this call gives an exception of:
"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))".
The file is created using DotNetZip. I'm adding thousands of files to the archive which takes a few minutes to run:
using (ZipFile zip = new ZipFile())
{
zip.AddFile(...); // for thousands of files
zip.Save(cr.ArchiveName);
}
var storageFile = await subFolder.GetFileAsync(cr.ArchiveName);
// storageFile is valid at this point
var basicProperties = await storageFile.GetBasicPropertiesAsync(); // BOOM!
A few apparently random things seem to decrease the likelihood of the exception:
Deleting an existing copy of cr.ArchiveName before the start of the loop.
Not viewing the directory using File Explorer
Weird, huh? It smells like it might be a bug related to File System Tunneling or maybe it's some internal caching that DotNetZip is performing and holding onto resources (maybe renaming the TEMP file) even after the ZipFile is disposed?
Trying to (unsuccessfully) answer my own question.
At first, I though this was a known issue with DotNetZip holding onto file handles until the next garbage collection. I am using the SL/WP7 port of DotNetZip from http://slsharpziplib.codeplex.com/ which presumably doesn't include the bug fixed by this workitem:
http://dotnetzip.codeplex.com/workitem/12727
But, according to that theory, doing:
GC.Collect();
GC.WaitForPendingFinalizers();
should have provided a work around, which it didn't.
Next I tried using handle, which didn't show any other activity on the failing StorageFile.
So for now, I'm still stumped.

Replacing or recreating a file in Windows 8 RT keeps the old DateCreated value

I'm attempting to cache data in a file for a Windows Store app, and using the DateCreated value to determine if it is out of date.
I first tried doing this:
var file = await rootFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.ReplaceExisting);
FileIO.WriteTextAsync(file, contents);
but when it saves the file only the DateModified value is changed, even though the comments for the ReplaceExisting option clearly state that it recreates the file and replaces an existing one.
So I decided to force it to delete the file and recreate it with this:
var file = await rootFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.ReplaceExisting);
// force delete because windows rt is not doing what it's supposed to in the line above!!
await file.DeleteAsync();
file = await rootFolder.CreateFileAsync(filename);
FileIO.WriteTextAsync(file, contents);
but amazingly, I still get the same result! The file is deleted and recreated with the OLD CREATION DATE!
Is this a bug, or am I doing something wrong here?
This is by design, a feature called "File system tunneling". This KB article explains the behavior and rationale.
The workaround it documents requires registry editing, clearly you cannot rely on that in a Store application. You'll need to find a workaround, like using the last-written timestamp or alternating between two files or keep track of age in a separate file.
Thanks for the comments everyone, it turns out the Modified date IS available but you have to get it through the GetBasicPropertiesAsync() method as shown here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.fileproperties.basicproperties.datemodified.aspx

How do I get the name of the current branch in libgit2?

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);
}