|
@@ -955,7 +955,8 @@ class AddTests(PorcelainTestCase):
|
|
|
os.chdir(cwd)
|
|
|
|
|
|
index = self.repo.open_index()
|
|
|
- self.assertEqual(sorted(index), [b"foo/blie"])
|
|
|
+ # After fix: add() with no paths should behave like git add -A (add everything)
|
|
|
+ self.assertEqual(sorted(index), [b"blah", b"foo/blie"])
|
|
|
|
|
|
def test_add_file(self) -> None:
|
|
|
fullpath = os.path.join(self.repo.path, "foo")
|
|
@@ -1053,19 +1054,21 @@ class AddTests(PorcelainTestCase):
|
|
|
target_file = os.path.join(self.repo.path, "target.txt")
|
|
|
with open(target_file, "w") as f:
|
|
|
f.write("target content")
|
|
|
-
|
|
|
+
|
|
|
# Create a symlink to the file
|
|
|
symlink_path = os.path.join(self.repo.path, "link_to_target")
|
|
|
os.symlink("target.txt", symlink_path)
|
|
|
-
|
|
|
+
|
|
|
# Add both the target and the symlink
|
|
|
- added, ignored = porcelain.add(self.repo.path, paths=[target_file, symlink_path])
|
|
|
-
|
|
|
+ added, ignored = porcelain.add(
|
|
|
+ self.repo.path, paths=[target_file, symlink_path]
|
|
|
+ )
|
|
|
+
|
|
|
# Both should be added successfully
|
|
|
self.assertIn("target.txt", added)
|
|
|
self.assertIn("link_to_target", added)
|
|
|
self.assertEqual(len(ignored), 0)
|
|
|
-
|
|
|
+
|
|
|
# Verify both are in the index
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"target.txt", index)
|
|
@@ -1080,20 +1083,20 @@ class AddTests(PorcelainTestCase):
|
|
|
f.write("content1")
|
|
|
with open(os.path.join(target_dir, "file2.txt"), "w") as f:
|
|
|
f.write("content2")
|
|
|
-
|
|
|
+
|
|
|
# Create a symlink to the directory
|
|
|
symlink_path = os.path.join(self.repo.path, "link_to_dir")
|
|
|
os.symlink("target_dir", symlink_path)
|
|
|
-
|
|
|
+
|
|
|
# Add the symlink
|
|
|
added, ignored = porcelain.add(self.repo.path, paths=[symlink_path])
|
|
|
-
|
|
|
+
|
|
|
# When adding a symlink to a directory, it follows the symlink and adds contents
|
|
|
self.assertEqual(len(added), 2)
|
|
|
self.assertIn("link_to_dir/file1.txt", added)
|
|
|
self.assertIn("link_to_dir/file2.txt", added)
|
|
|
self.assertEqual(len(ignored), 0)
|
|
|
-
|
|
|
+
|
|
|
# Verify files are added through the symlink path
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"link_to_dir/file1.txt", index)
|
|
@@ -1108,24 +1111,26 @@ class AddTests(PorcelainTestCase):
|
|
|
target_file = os.path.join(self.repo.path, "original.txt")
|
|
|
with open(target_file, "w") as f:
|
|
|
f.write("original content")
|
|
|
-
|
|
|
+
|
|
|
# Create first symlink
|
|
|
first_link = os.path.join(self.repo.path, "link1")
|
|
|
os.symlink("original.txt", first_link)
|
|
|
-
|
|
|
+
|
|
|
# Create second symlink pointing to first
|
|
|
second_link = os.path.join(self.repo.path, "link2")
|
|
|
os.symlink("link1", second_link)
|
|
|
-
|
|
|
+
|
|
|
# Add all files
|
|
|
- added, ignored = porcelain.add(self.repo.path, paths=[target_file, first_link, second_link])
|
|
|
-
|
|
|
+ added, ignored = porcelain.add(
|
|
|
+ self.repo.path, paths=[target_file, first_link, second_link]
|
|
|
+ )
|
|
|
+
|
|
|
# All should be added
|
|
|
self.assertEqual(len(added), 3)
|
|
|
self.assertIn("original.txt", added)
|
|
|
self.assertIn("link1", added)
|
|
|
self.assertIn("link2", added)
|
|
|
-
|
|
|
+
|
|
|
# Verify all are in the index
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"original.txt", index)
|
|
@@ -1137,14 +1142,14 @@ class AddTests(PorcelainTestCase):
|
|
|
# Create a symlink to a non-existent file
|
|
|
broken_link = os.path.join(self.repo.path, "broken_link")
|
|
|
os.symlink("does_not_exist.txt", broken_link)
|
|
|
-
|
|
|
+
|
|
|
# Add the broken symlink
|
|
|
added, ignored = porcelain.add(self.repo.path, paths=[broken_link])
|
|
|
-
|
|
|
+
|
|
|
# Should be added successfully (Git tracks the symlink, not its target)
|
|
|
self.assertIn("broken_link", added)
|
|
|
self.assertEqual(len(ignored), 0)
|
|
|
-
|
|
|
+
|
|
|
# Verify it's in the index
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"broken_link", index)
|
|
@@ -1155,18 +1160,18 @@ class AddTests(PorcelainTestCase):
|
|
|
outside_file = os.path.join(self.test_dir, "outside.txt")
|
|
|
with open(outside_file, "w") as f:
|
|
|
f.write("outside content")
|
|
|
-
|
|
|
+
|
|
|
# Create a symlink using relative path to go outside
|
|
|
symlink_path = os.path.join(self.repo.path, "link_outside")
|
|
|
os.symlink("../outside.txt", symlink_path)
|
|
|
-
|
|
|
+
|
|
|
# Add the symlink
|
|
|
added, ignored = porcelain.add(self.repo.path, paths=[symlink_path])
|
|
|
-
|
|
|
+
|
|
|
# Should be added successfully
|
|
|
self.assertIn("link_outside", added)
|
|
|
self.assertEqual(len(ignored), 0)
|
|
|
-
|
|
|
+
|
|
|
# Verify it's in the index
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"link_outside", index)
|
|
@@ -1176,11 +1181,11 @@ class AddTests(PorcelainTestCase):
|
|
|
# Create a symlink to a system directory
|
|
|
symlink_path = os.path.join(self.repo.path, "link_to_tmp")
|
|
|
os.symlink("/tmp", symlink_path)
|
|
|
-
|
|
|
+
|
|
|
# Adding a symlink to a directory outside the repo should raise ValueError
|
|
|
with self.assertRaises(ValueError) as cm:
|
|
|
porcelain.add(self.repo.path, paths=[symlink_path])
|
|
|
-
|
|
|
+
|
|
|
# Check that the error indicates the path is outside the repository
|
|
|
self.assertIn("is not in the subpath of", str(cm.exception))
|
|
|
|
|
@@ -1192,21 +1197,21 @@ class AddTests(PorcelainTestCase):
|
|
|
real_file = os.path.join(real_dir, "file.txt")
|
|
|
with open(real_file, "w") as f:
|
|
|
f.write("content")
|
|
|
-
|
|
|
+
|
|
|
# Create a symlink to the directory
|
|
|
link_dir = os.path.join(self.repo.path, "link_dir")
|
|
|
os.symlink("real_dir", link_dir)
|
|
|
-
|
|
|
+
|
|
|
# Try to add the file through the symlink path
|
|
|
symlink_file_path = os.path.join(link_dir, "file.txt")
|
|
|
-
|
|
|
+
|
|
|
# This should add the real file, not create a new entry
|
|
|
added, ignored = porcelain.add(self.repo.path, paths=[symlink_file_path])
|
|
|
-
|
|
|
+
|
|
|
# The real file should be added
|
|
|
self.assertIn("real_dir/file.txt", added)
|
|
|
self.assertEqual(len(added), 1)
|
|
|
-
|
|
|
+
|
|
|
# Verify correct path in index
|
|
|
index = self.repo.open_index()
|
|
|
self.assertIn(b"real_dir/file.txt", index)
|
|
@@ -1406,6 +1411,42 @@ class AddTests(PorcelainTestCase):
|
|
|
index = self.repo.open_index()
|
|
|
self.assertEqual(len(index), 6)
|
|
|
|
|
|
+ def test_add_default_paths_includes_modified_files(self) -> None:
|
|
|
+ """Test that add() with no paths includes both untracked and modified files."""
|
|
|
+ # Create and commit initial file
|
|
|
+ initial_file = os.path.join(self.repo.path, "existing.txt")
|
|
|
+ with open(initial_file, "w") as f:
|
|
|
+ f.write("initial content\n")
|
|
|
+ porcelain.add(repo=self.repo.path, paths=[initial_file])
|
|
|
+ porcelain.commit(
|
|
|
+ repo=self.repo.path,
|
|
|
+ message=b"initial commit",
|
|
|
+ author=b"test <email>",
|
|
|
+ committer=b"test <email>",
|
|
|
+ )
|
|
|
+
|
|
|
+ # Modify the existing file (this creates an unstaged change)
|
|
|
+ with open(initial_file, "w") as f:
|
|
|
+ f.write("modified content\n")
|
|
|
+
|
|
|
+ # Create a new untracked file
|
|
|
+ new_file = os.path.join(self.repo.path, "new.txt")
|
|
|
+ with open(new_file, "w") as f:
|
|
|
+ f.write("new file content\n")
|
|
|
+
|
|
|
+ # Call add() with no paths - should stage both modified and untracked files
|
|
|
+ added_files, ignored_files = porcelain.add(repo=self.repo.path)
|
|
|
+
|
|
|
+ # Verify both files were added
|
|
|
+ self.assertIn("existing.txt", added_files)
|
|
|
+ self.assertIn("new.txt", added_files)
|
|
|
+ self.assertEqual(len(ignored_files), 0)
|
|
|
+
|
|
|
+ # Verify both files are now staged
|
|
|
+ index = self.repo.open_index()
|
|
|
+ self.assertIn(b"existing.txt", index)
|
|
|
+ self.assertIn(b"new.txt", index)
|
|
|
+
|
|
|
|
|
|
class RemoveTests(PorcelainTestCase):
|
|
|
def test_remove_file(self) -> None:
|