Skip to content

Commit 4bdec5e

Browse files
authored
solve commit bug (#162)
1 parent 267849f commit 4bdec5e

4 files changed

Lines changed: 69 additions & 1 deletion

File tree

src/wrapper/index_wrapper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ git_oid index_wrapper::write_tree()
7979
return tree_id;
8080
}
8181

82+
size_t index_wrapper::entry_count() const
83+
{
84+
return git_index_entrycount(*this);
85+
}
86+
8287
bool index_wrapper::has_conflict() const
8388
{
8489
return git_index_has_conflicts(*this);

src/wrapper/index_wrapper.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class index_wrapper : public wrapper_base<git_index>
2323
void write();
2424
git_oid write_tree();
2525

26+
size_t entry_count() const;
27+
2628
void add_entry(const std::string& path);
2729
void add_entries(std::vector<std::string> patterns);
2830
void add_all();

src/wrapper/repository_wrapper.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ void repository_wrapper::create_commit(
293293
{
294294
if (parents_list)
295295
{
296-
// TODO: write a "as_const" function to replace the following
297296
auto pl_size = parents_list.value().size();
298297
git_commit** pl_value = parents_list.value();
299298
auto pl_value_const = const_cast<const git_commit**>(pl_value);
@@ -313,9 +312,29 @@ void repository_wrapper::create_commit(
313312
}();
314313

315314
index_wrapper index = this->make_index();
315+
316+
// Check: initial commit (no parents) with nothing staged
317+
if (parents_count == 0 && index.entry_count() == 0)
318+
{
319+
throw std::runtime_error(
320+
"On branch main\n\nInitial commit\n\nnothing to commit "
321+
"(create/copy files and use \"git add\" to track)"
322+
);
323+
}
324+
316325
git_oid tree_id = index.write_tree();
317326
index.write();
318327

328+
// Check: tree is identical to parent tree (nothing changed since last commit)
329+
if (parents_count > 0 && placeholder[0] != nullptr)
330+
{
331+
const git_oid* parent_tree_id = git_commit_tree_id(placeholder[0]);
332+
if (git_oid_equal(&tree_id, parent_tree_id))
333+
{
334+
throw std::runtime_error("nothing to commit, working tree clean");
335+
}
336+
}
337+
319338
auto tree = this->tree_lookup(&tree_id);
320339

321340
throw_if_error(git_commit_create(

test/test_commit.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,45 @@ def test_commit_message_via_stdin(
8181
assert "Author:" in lines[1]
8282
assert "Date" in lines[2]
8383
assert commit_msg_out in lines[4]
84+
85+
86+
def test_commit_no_changes_initial(commit_env_config, git2cpp_path, tmp_path):
87+
"""Commit on fresh repo with no staged files should fail"""
88+
cmd_init = [git2cpp_path, "init", "."]
89+
p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path)
90+
assert p_init.returncode == 0
91+
92+
# Do NOT add any files — attempt to commit immediately
93+
cmd_commit = [git2cpp_path, "commit", "-m", "empty commit"]
94+
p_commit = subprocess.run(cmd_commit, capture_output=True, cwd=tmp_path, text=True)
95+
96+
# Should fail: nothing to commit
97+
assert p_commit.returncode != 0
98+
assert "nothing to commit" in p_commit.stderr or "nothing to commit" in p_commit.stdout
99+
100+
101+
def test_commit_no_changes_after_first_commit(commit_env_config, git2cpp_path, tmp_path):
102+
"""Commit twice without changes between commits should fail"""
103+
cmd_init = [git2cpp_path, "init", "."]
104+
p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path)
105+
assert p_init.returncode == 0
106+
107+
# Create and commit a file
108+
(tmp_path / "file.txt").write_text("hello")
109+
subprocess.run([git2cpp_path, "add", "file.txt"], cwd=tmp_path, check=True)
110+
p_first = subprocess.run(
111+
[git2cpp_path, "commit", "-m", "first commit"], cwd=tmp_path, capture_output=True, text=True
112+
)
113+
assert p_first.returncode == 0
114+
115+
# Try to commit again without any new changes
116+
p_second = subprocess.run(
117+
[git2cpp_path, "commit", "-m", "second commit (no changes)"],
118+
cwd=tmp_path,
119+
capture_output=True,
120+
text=True,
121+
)
122+
123+
# Should fail: nothing to commit
124+
assert p_second.returncode != 0
125+
assert "nothing to commit" in p_second.stderr or "nothing to commit" in p_second.stdout

0 commit comments

Comments
 (0)