diff --git a/demo/.gitattributes b/demo/.gitattributes
new file mode 100644
index 0000000..939be60
--- /dev/null
+++ b/demo/.gitattributes
@@ -0,0 +1,17 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+#Explicitly declare text files you want to always be normalized and converted
+#to native line endings on checkout.
+*.cpp text
+*.c text
+*.h text
+*.gd text
+*.cs text
+
+#Declare files that will always have CRLF line endings on checkout.
+*.sln text eol=crlf
+
+#Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpg binary
diff --git a/demo/bin/win64/libgitapi.dll b/demo/bin/win64/libgitapi.dll
index b04ca2a..004298d 100644
Binary files a/demo/bin/win64/libgitapi.dll and b/demo/bin/win64/libgitapi.dll differ
diff --git a/demo/bin/win64/libgitapi.exp b/demo/bin/win64/libgitapi.exp
index 6fa6383..e3495f5 100644
Binary files a/demo/bin/win64/libgitapi.exp and b/demo/bin/win64/libgitapi.exp differ
diff --git a/demo/bin/win64/libgitapi.lib b/demo/bin/win64/libgitapi.lib
index 6dfa3d0..fe8ba5f 100644
Binary files a/demo/bin/win64/libgitapi.lib and b/demo/bin/win64/libgitapi.lib differ
diff --git a/demo/new_script.gd b/demo/new_script.gd
index 0cfed86..dd2f28f 100644
--- a/demo/new_script.gd
+++ b/demo/new_script.gd
@@ -7,7 +7,10 @@ extends Node
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
-# This is a test change for the VCS addon
+
+func _some_function():
+ pass
+
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass
diff --git a/demo/project.godot b/demo/project.godot
index 6510017..6d981cc 100644
--- a/demo/project.godot
+++ b/demo/project.godot
@@ -21,6 +21,7 @@ _global_script_class_icons={
[application]
config/name="demo"
+run/main_scene="res://demo.tscn"
config/icon="res://icon.png"
[gdnative]
diff --git a/godot-git-plugin/godot-git-plugin.vcxproj b/godot-git-plugin/godot-git-plugin.vcxproj
index 9148296..bf2ab66 100644
--- a/godot-git-plugin/godot-git-plugin.vcxproj
+++ b/godot-git-plugin/godot-git-plugin.vcxproj
@@ -129,13 +129,11 @@
-
-
diff --git a/godot-git-plugin/godot-git-plugin.vcxproj.filters b/godot-git-plugin/godot-git-plugin.vcxproj.filters
index 391df48..c294095 100644
--- a/godot-git-plugin/godot-git-plugin.vcxproj.filters
+++ b/godot-git-plugin/godot-git-plugin.vcxproj.filters
@@ -21,9 +21,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -35,9 +32,6 @@
Header Files
-
- Header Files
-
Header Files
diff --git a/godot-git-plugin/src/git_api.cpp b/godot-git-plugin/src/git_api.cpp
index 4f83022..afc5b73 100644
--- a/godot-git-plugin/src/git_api.cpp
+++ b/godot-git-plugin/src/git_api.cpp
@@ -2,7 +2,7 @@
namespace godot {
-bool GitAPI::is_initialized = false;
+GitAPI *GitAPI::singleton = NULL;
void GitAPI::_register_methods() {
@@ -13,6 +13,7 @@ void GitAPI::_register_methods() {
register_method("_get_initialization_settings_panel_container", &GitAPI::_get_initialization_settings_panel_container);
register_method("_get_is_vcs_intialized", &GitAPI::_get_is_vcs_intialized);
register_method("_get_modified_files_data", &GitAPI::_get_modified_files_data);
+ register_method("_get_file_diff", &GitAPI::_get_file_diff);
register_method("_get_project_name", &GitAPI::_get_project_name);
register_method("_get_vcs_name", &GitAPI::_get_vcs_name);
register_method("_initialize", &GitAPI::_initialize);
@@ -31,42 +32,41 @@ void GitAPI::_commit(const String p_msg) {
git_signature *default_sign;
git_oid tree_id, parent_id, commit_id;
git_tree *tree;
+ git_index *repo_index;
git_commit *parent;
- git_index *index;
git_signature_default(&default_sign, repo);
-
git_reference_name_to_id(&parent_id, repo, "HEAD");
- /* Get the index and write it to a tree */
- git_repository_index(&index, repo);
+ git_repository_index(&repo_index, repo);
for (int i = 0; i < staged_files.size(); i++) {
- git_index_add_bypath(index, ((String)staged_files[i]).alloc_c_string());
+ git_index_add_bypath(repo_index, ((String)staged_files[i]).alloc_c_string());
}
- git_index_write_tree(&tree_id, index);
+ git_index_write_tree(&tree_id, repo_index);
git_tree_lookup(&tree, repo, &tree_id);
- /* Get HEAD as a commit object to use as the parent of the commit */
GIT2_CALL(git_reference_name_to_id(&parent_id, repo, "HEAD"), "Could not get HEAD reference for parent ID", NULL);
git_commit_lookup(&parent, repo, &parent_id);
- /* Do the commit */
git_commit_create_v(
- &commit_id,
- repo,
- "HEAD", /* The commit will update the position of HEAD */
- default_sign,
- default_sign,
- NULL, /* UTF-8 encoding */
- p_msg.alloc_c_string(),
- tree, /* The tree from the index */
- 1, /* Only one parent */
- parent /* No need to make a list with create_v */
+ &commit_id,
+ repo,
+ "HEAD",
+ default_sign,
+ default_sign,
+ NULL,
+ p_msg.alloc_c_string(),
+ tree,
+ 1,
+ parent
);
+ staged_files.clear();
+
+ git_index_write(repo_index);
+ git_index_free(repo_index);
git_signature_free(default_sign);
- git_index_free(index);
git_commit_free(parent);
git_tree_free(tree);
}
@@ -81,10 +81,13 @@ void GitAPI::_stage_file(const String p_file_path) {
void GitAPI::_unstage_file(const String p_file_path) {
- staged_files.erase(p_file_path);
+ if (staged_files.find(p_file_path) != -1) {
+
+ staged_files.erase(p_file_path);
+ }
}
-void GitAPI::create_gitignore() {
+void GitAPI::create_gitignore_and_gitattributes() {
File *file = File::_new();
@@ -101,37 +104,61 @@ void GitAPI::create_gitignore() {
);
file->close();
}
+
+ if (!file->file_exists("res://.gitattributes")) {
+
+ file->open("res://.gitattributes", File::ModeFlags::WRITE);
+ file->store_string(
+ "# Set the default behavior, in case people don't have core.autocrlf set.\n"
+ "* text=auto\n\n"
+
+ "#Explicitly declare text files you want to always be normalized and converted\n"
+ "#to native line endings on checkout.\n"
+ "*.cpp text\n"
+ "*.c text\n"
+ "*.h text\n"
+ "*.gd text\n"
+ "*.cs text\n\n"
+
+ "#Declare files that will always have CRLF line endings on checkout.\n"
+ "*.sln text eol=crlf\n\n"
+
+ "#Denote all files that are truly binary and should not be modified.\n"
+ "*.png binary\n"
+ "*.jpg binary\n");
+ file->close();
+ }
}
void GitAPI::create_initial_commit() {
git_signature *sig;
- git_index *index;
git_oid tree_id, commit_id;
+ git_index *repo_index;
git_tree *tree;
GIT2_CALL(git_signature_default(&sig, repo), "Unable to create a commit signature. Perhaps 'user.name' and 'user.email' are not set", NULL);
- GIT2_CALL(git_repository_index(&index, repo), "Could not create intial commit", NULL);
- GIT2_CALL(git_index_write_tree(&tree_id, index), "Could not create intial commit", NULL);
-
- git_index_free(index);
+ GIT2_CALL(git_repository_index(&repo_index, repo), "Could not get repository index", NULL);
+ GIT2_CALL(git_index_write_tree(&tree_id, repo_index), "Could not create intial commit", NULL);
GIT2_CALL(git_tree_lookup(&tree, repo, &tree_id), "Could not create intial commit", NULL);
GIT2_CALL(
git_commit_create_v(
- &commit_id,
- repo,
- "HEAD",
- sig,
- sig,
- NULL,
- "Initial commit",
- tree,
- 0
+ &commit_id,
+ repo,
+ "HEAD",
+ sig,
+ sig,
+ NULL,
+ "Initial commit",
+ tree,
+ 0
),
"Could not create the initial commit",
NULL);
+ git_index_write(repo_index);
+ git_index_free(repo_index);
git_tree_free(tree);
git_signature_free(sig);
}
@@ -153,12 +180,11 @@ bool GitAPI::_get_is_vcs_intialized() {
Dictionary GitAPI::_get_modified_files_data() {
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- opts.flags += GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
- opts.flags += GIT_STATUS_OPT_INCLUDE_UNTRACKED;
- opts.flags += GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
- opts.flags += GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
- git_status_list *statuses = NULL;
+ opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
+ opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
+ opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
+ git_status_list *statuses = NULL;
GIT2_CALL(git_status_list_new(&statuses, repo, &opts), "Could not get status information from repository", NULL);
Dictionary diff; // Schema is
@@ -209,6 +235,28 @@ Dictionary GitAPI::_get_modified_files_data() {
return diff;
}
+String GitAPI::_get_file_diff(const String file_path) {
+
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff *diff;
+ char *pathspec = file_path.alloc_c_string();
+
+ opts.context_lines = 0;
+ opts.interhunk_lines = 0;
+ opts.flags = GIT_DIFF_DISABLE_PATHSPEC_MATCH | GIT_DIFF_INCLUDE_UNTRACKED;
+ opts.pathspec.strings = &pathspec;
+ opts.pathspec.count = 1;
+
+ git_diff_index_to_workdir(&diff, repo, NULL, &opts);
+
+ diff_content_container = "";
+ git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, diff_line_callback_function, NULL);
+
+ git_diff_free(diff);
+
+ return diff_content_container;
+}
+
String GitAPI::_get_project_name() {
return String("project");
@@ -223,6 +271,8 @@ bool GitAPI::_initialize(const String p_project_root_path) {
ERR_FAIL_COND_V(p_project_root_path == "", false);
+ singleton = this;
+
int init = git_libgit2_init();
if (init > 1) {
@@ -237,7 +287,7 @@ bool GitAPI::_initialize(const String p_project_root_path) {
GIT2_CALL(git_repository_init(&repo, p_project_root_path.alloc_c_string(), 0), "Could not initialize repository", NULL);
if (git_repository_head_unborn(repo) == 1) {
- create_gitignore();
+ create_gitignore_and_gitattributes();
create_initial_commit();
}
@@ -250,6 +300,7 @@ bool GitAPI::_initialize(const String p_project_root_path) {
bool GitAPI::_shut_down() {
git_repository_free(repo);
+
GIT2_CALL(git_libgit2_shutdown(), "Could not shutdown Git Addon", NULL);
return true;
diff --git a/godot-git-plugin/src/git_api.h b/godot-git-plugin/src/git_api.h
index 2c5f921..6ac723b 100644
--- a/godot-git-plugin/src/git_api.h
+++ b/godot-git-plugin/src/git_api.h
@@ -9,11 +9,10 @@
#include
#include
-#include
-
#include
#include
-#include
+
+#include
namespace godot {
@@ -21,20 +20,21 @@ class GitAPI : public EditorVCSInterface {
GODOT_CLASS(GitAPI, EditorVCSInterface)
- static bool is_initialized;
+ static GitAPI *singleton;
Array staged_files;
-
+
PanelContainer *init_settings_panel_container;
Button *init_settings_button;
git_repository *repo;
-
+
void _commit(const String p_msg);
Control *_get_commit_dock_panel_container();
Control *_get_initialization_settings_panel_container();
bool _get_is_vcs_intialized();
Dictionary _get_modified_files_data();
+ String _get_file_diff(const String file_path);
String _get_project_name();
String _get_vcs_name();
bool _initialize(const String p_project_root_path);
@@ -45,7 +45,13 @@ class GitAPI : public EditorVCSInterface {
public:
static void _register_methods();
- void create_gitignore();
+ static GitAPI *get_singleton() { return singleton; }
+
+ bool is_initialized;
+
+ String diff_content_container;
+
+ void create_gitignore_and_gitattributes();
void create_initial_commit();
void _init();
diff --git a/godot-git-plugin/src/git_callbacks.cpp b/godot-git-plugin/src/git_callbacks.cpp
deleted file mode 100644
index df76c67..0000000
--- a/godot-git-plugin/src/git_callbacks.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include
-
-int status_callback(const char *p_path, const char *p_matched_pathspec, void *p_payload) {
-
- StatusPayload p = *(StatusPayload *)(p_payload);
- int ret;
- unsigned int status;
-
- if (git_status_file(&status, p.repo, p_path)) {
-
- return -1;
- }
-
- if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {
-
- godot::Godot::print("Staged '%s'", p_path);
- ret = 0;
- } else {
-
- ret = 1;
- }
-
- return ret;
-}
diff --git a/godot-git-plugin/src/git_callbacks.h b/godot-git-plugin/src/git_callbacks.h
deleted file mode 100644
index 47820ef..0000000
--- a/godot-git-plugin/src/git_callbacks.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef GIT_CALLBACKS_H
-#define GIT_CALLBACKS_H
-
-#include
-#include
-
-#include
-
-int status_callback(const char *p_path, const char *p_matched_pathspec, void *p_payload);
-
-#endif // !GIT_CALLBACKS_H
diff --git a/godot-git-plugin/src/git_common.cpp b/godot-git-plugin/src/git_common.cpp
index 00e9581..e2c389e 100644
--- a/godot-git-plugin/src/git_common.cpp
+++ b/godot-git-plugin/src/git_common.cpp
@@ -1,4 +1,5 @@
#include
+#include
void check_git2_errors(int error, const char *message, const char *extra) {
@@ -24,3 +25,25 @@ void check_git2_errors(int error, const char *message, const char *extra) {
printf("Git API: %s [%d]%s%s\n", message, error, lg2spacer, lg2msg);
}
}
+
+extern "C" int diff_line_callback_function(const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload) {
+
+ // NULL terminate the line text
+ char *content = new char[line->content_len + 1];
+ memcpy(content, line->content, line->content_len);
+ static int i = 0;
+ content[line->content_len] = '\0';
+
+ godot::String prefix;
+ switch (line->origin) {
+
+ case GIT_DIFF_LINE_ADD_EOFNL:
+ case GIT_DIFF_LINE_ADDITION: prefix = "+"; break;
+
+ case GIT_DIFF_LINE_DEL_EOFNL:
+ case GIT_DIFF_LINE_DELETION: prefix = "-"; break;
+ }
+ godot::GitAPI::get_singleton()->diff_content_container += "\n" + prefix + godot::String(content);
+
+ return 0;
+}
diff --git a/godot-git-plugin/src/git_common.h b/godot-git-plugin/src/git_common.h
index cad7eed..7c15cd1 100644
--- a/godot-git-plugin/src/git_common.h
+++ b/godot-git-plugin/src/git_common.h
@@ -7,11 +7,8 @@
void check_git2_errors(int error, const char *message, const char *extra);
+extern "C" int diff_line_callback_function(const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload);
+
#define GIT2_CALL(function_call, m_error_msg, m_additional_msg) check_git2_errors(function_call, m_error_msg, m_additional_msg);
-struct StatusPayload {
-
- git_repository *repo;
-};
-
#endif // !GIT_COMMON_H