Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 76f2528

Browse files
committed
Merge branch 'five'
2 parents 0c6b1be + 08f3d7b commit 76f2528

7 files changed

Lines changed: 326 additions & 6 deletions

File tree

gitgud/skills/newbasics/__init__.py

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _test(self):
4242
file_operator = operations.get_operator()
4343

4444
# There are two commits
45-
if len(file_operator.get_all_commits()) != 2:
45+
if len(file_operator.get_commits()) != 2:
4646
return False
4747

4848
# The first commit has one file
@@ -73,11 +73,170 @@ def _test(self):
7373
return True
7474

7575

76+
class FiveCommits(BasicLevel):
77+
def status(self):
78+
complete = "✔️"
79+
incomplete = "✘"
80+
untested = "•"
81+
82+
tests = [
83+
(self._test1, "Commit 1: Add a file"),
84+
(self._test2, "Commit 2: Add another file"),
85+
(self._test3, "Commit 3: Modify both files"),
86+
(self._test4, "Commit 4: Delete the file from commit 1"),
87+
(self._test5, "Commit 5: Rename the file from commit 2")
88+
]
89+
90+
failed = False
91+
for test, user_text in tests:
92+
if not failed:
93+
if test():
94+
goal_status = complete
95+
else:
96+
goal_status = incomplete
97+
failed = True
98+
else:
99+
goal_status = untested
100+
101+
print(f"{goal_status} {user_text}")
102+
103+
def _test1(self):
104+
# Test if a single file has been added to the first commit
105+
file_operator = operations.get_operator()
106+
107+
commits = file_operator.get_commits()
108+
109+
if len(commits) < 1:
110+
return None
111+
112+
content = file_operator.get_commit_content(commits[0])
113+
if len(content.keys()) != 1:
114+
return False
115+
116+
return True
117+
118+
def _test2(self):
119+
# Test if a single file has been added to the second commit
120+
file_operator = operations.get_operator()
121+
122+
commits = file_operator.get_commits()
123+
124+
if len(commits) < 2:
125+
return None
126+
127+
content1 = file_operator.get_commit_content(commits[0])
128+
content2 = file_operator.get_commit_content(commits[1])
129+
130+
# There is only one more file in the second commit
131+
if len(content1) + 1 != len(content2):
132+
return False
133+
134+
filename1 = next(iter(content1.keys()))
135+
136+
if filename1 not in content2:
137+
return False
138+
if content1[filename1] != content2[filename1]:
139+
return False
140+
141+
return True
142+
143+
def _test3(self):
144+
# Test that both files were modified in commit three
145+
file_operator = operations.get_operator()
146+
147+
commits = file_operator.get_commits()
148+
149+
if len(commits) < 3:
150+
return None
151+
152+
content2 = file_operator.get_commit_content(commits[1])
153+
content3 = file_operator.get_commit_content(commits[2])
154+
155+
# Same number of files
156+
if len(content2) != len(content3):
157+
return False
158+
159+
# Both files have new content and same name
160+
for filename in content2:
161+
if filename not in content3:
162+
return False
163+
if content2[filename] == content3[filename]:
164+
return False
165+
166+
return True
167+
168+
def _test4(self):
169+
# File 1 was removed in commit 4
170+
file_operator = operations.get_operator()
171+
172+
commits = file_operator.get_commits()
173+
174+
if len(commits) < 4:
175+
return None
176+
177+
content1 = file_operator.get_commit_content(commits[0])
178+
content3 = file_operator.get_commit_content(commits[2])
179+
content4 = file_operator.get_commit_content(commits[3])
180+
181+
file1 = next(iter(content1.keys()))
182+
183+
# Construct content4 from content3
184+
del content3[file1]
185+
186+
return content3 == content4
187+
188+
def _test5(self):
189+
# File 2 was moved in commit 5
190+
file_operator = operations.get_operator()
191+
192+
commits = file_operator.get_commits()
193+
194+
if len(commits) < 5:
195+
return None
196+
197+
content4 = file_operator.get_commit_content(commits[3])
198+
content5 = file_operator.get_commit_content(commits[4])
199+
200+
if len(content5) != 1:
201+
return False
202+
203+
filename2_orig = next(iter(content4.keys()))
204+
filename2_new = next(iter(content5.keys()))
205+
206+
if filename2_orig in content5:
207+
return False
208+
209+
if content4[filename2_orig] != content5[filename2_new]:
210+
return False
211+
212+
return True
213+
214+
def _test(self):
215+
file_operator = operations.get_operator()
216+
217+
if file_operator.branch_has_merges():
218+
return False
219+
220+
if not self._test1():
221+
return False
222+
if not self._test2():
223+
return False
224+
if not self._test3():
225+
return False
226+
if not self._test4():
227+
return False
228+
if not self._test5():
229+
return False
230+
231+
return True
232+
233+
76234
skill = Skill(
77235
'New Basics',
78236
'newbasics',
79237
[
80238
FirstCommit('First Commit', 'firstcommit', __name__),
81-
TwoCommits('Two Commits', 'two', __name__)
239+
TwoCommits('Two Commits', 'two', __name__),
240+
FiveCommits('Five Commits', 'five', __name__)
82241
]
83242
)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
The important thing to remember in this level is to commit your changes as you make them.
2+
3+
In general with Git, things go kinda like this:
4+
1. Make changes
5+
2. Tell Git about those changes
6+
3. Commit those changes
7+
4. Push your changes to a remote branch
8+
9+
Git Gud hasn't covered remote branches yet, but they're how most people share their code with other people.
10+
11+
>>>
12+
13+
This makes sense if you think about it backwards.
14+
4. When sharing your code, you may only want to share some of the files you're working on
15+
3. You need some way to store a version of your code - that's what a commit is
16+
2. For Git to know which version of the code to track, you need to tell it
17+
1. Before Git can track any changes, you obviously need to make the changes
18+
19+
>>>
20+
21+
To help understand this, let's break down each step of the process:
22+
1. Add a file <-- Let's break the first two down first
23+
2. Add another file <-- Let's break the first two down first
24+
3. Modify both files
25+
4. Remove the first file
26+
5. Move the second file
27+
28+
>>>
29+
30+
The first two steps are pretty simple. They're just the first two levels in this skill that you've already completed.
31+
32+
Recall back to what you did:
33+
1. You created a file
34+
2. You "git add"-ed the file
35+
3. You "git commit"-ed the file
36+
37+
You did this twice. In the end, you created two files and ended up with two commits.
38+
39+
>>>
40+
41+
If you were paying attention to "git gud status", you might have noticed something:
42+
The fist commit only knew about the first file, but the second commit knew about both files.
43+
44+
If you were also paying attention to "git status", you might have noticed something else:
45+
The "staging area", which is shown when running "git status", only showed you the newly created file.
46+
47+
Why is that?
48+
49+
>>>
50+
51+
As soon as you make a commit, Git is ready to start tracking another commit. Git knows that in a code base with multiple files, most of the time you'll only be changing a few of them at a time.
52+
53+
Whenever you're looking at "git status", you're looking at the changes you've made. Git still knows about all the other files and will help you figure out what you want to include the next time you commit.
54+
55+
>>>
56+
57+
So, looking back, when you first created a file, it was the only file in the working directory, and it showed up when you ran "git status". You added the file, and it still showed up when you ran "git status", but after you committed it, the file no longer appeared when you ran "git status".
58+
59+
When you created the second file, it showed up when you ran "git status" too, and then you added it and committed it, but that time, the first file was still in the working directory. The first file doesn't show up when you run "git status", but Git still knows about it.
60+
61+
>>>
62+
63+
Now, let's look at the rest of the steps:
64+
1. Add a file
65+
2. Add another file
66+
3. Modify both files <-- Let's look at these
67+
4. Remove the first file <-- Let's look at these
68+
5. Move the second file <-- Let's look at these
69+
70+
You're still making changes, but this time, instead of creating a new file, you're doing all the other things you can do with files - Updating, deleting and removing
71+
72+
>>>
73+
74+
So now, we can learn about a few more commands
75+
You can use "git add" when you want to tell Git to "add" new changes to existing files
76+
You can use "git rm" when you want to tell Git to "remove" files
77+
You can use "git mv" when you want to tell Git to "move" or rename files
78+
79+
Finally, Git only stores versions of a repo. It doesn't actually store changes, but Git can tell if two files contents are the same. In Git's view, removing a file and then adding a file with the same contents is the same thing as moving it or renaming the file.
80+
81+
>>>
82+
83+
To summarize,
84+
85+
- Git tracks all files
86+
- You have to tell Git when things have changed
87+
88+
89+
Use the following commands to complete the level
90+
- git add
91+
- git rm
92+
- git mv
93+
- git commit
94+
95+
Use "git gud status" to check on your progress
96+
97+
Good luck!
98+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
In a series of commits, make the following changes
2+
1. Add a file
3+
2. Add another file
4+
3. Modify both files
5+
4. Remove the first file
6+
5. Move the second file
7+
8+
Use "git gud status" to check on your progress
9+
Use "git gud explain" to learn about the relevant git commands
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
master
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Examples, change to solution for your level
2+
echo "Hello world" >> sahan.txt
3+
git add sahan.txt
4+
git commit -m "Added Sahan"
5+
6+
echo "Wave my hands" >> ben.txt
7+
git add ben.txt
8+
git commit -m "Added Ben"
9+
10+
echo "Hola mundo" > sahan.txt
11+
echo "Wiggle my toes" > ben.txt
12+
git add sahan.txt
13+
git add ben.txt
14+
git commit -m "Changed file content"
15+
16+
git rm sahan.txt
17+
git commit -m "Bye Sahan"
18+
19+
git mv ben.txt gud.txt
20+
git commit -m "Renamed Ben"

gitgud/util/operations.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def normalize_state(self):
225225
self.repo.index.commit(
226226
"Placeholder commit\n\n"
227227
"This commit is used when initializing levels."
228-
"Something must have gone wrong",
228+
"If you see this, something must have gone wrong",
229229
parent_commits=[],
230230
skip_hooks=True)
231231
# Detach HEAD so we can delete branches
@@ -553,6 +553,34 @@ def get_all_commits(self, sort_commits=True):
553553
all_commits.sort(key=lambda commit: commit.committed_date)
554554
return all_commits
555555

556+
def get_commits(self):
557+
try:
558+
return list(self.repo.iter_commits('HEAD', reverse=True))
559+
except GitCommandError:
560+
return []
561+
562+
def branch_has_merges(self, branch=None):
563+
try:
564+
if branch is None:
565+
commit = self.repo.head.commit
566+
elif isinstance(branch, str):
567+
commit = self.repo.commit(branch)
568+
else:
569+
commit = branch.commit
570+
except ValueError:
571+
# Orphan branch
572+
return False
573+
574+
while commit:
575+
if len(commit.parents) == 1:
576+
commit = commit.parents[0]
577+
elif len(commit.parents) == 0:
578+
commit = None
579+
else:
580+
return True
581+
582+
return False
583+
556584

557585
def get_operator():
558586
for path in (Path.cwd() / "_").parents:

gitgud/util/testing.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ def simulate(gg, level, commands, run_pretest=True):
1212
level._setup()
1313

1414
for command in commands:
15+
command = command.strip()
16+
if len(command) == 0 or command[0] == '#':
17+
continue
18+
# Only test if there are commands which change state.
19+
if run_pretest:
20+
assert not level._test()
21+
22+
print(f'Calling command: {command}')
1523
if command.startswith('{create}'):
1624
filename = command[len('{create} '):].strip()
1725
write_file(filename)
1826
elif '^' in command and os.name == 'nt':
1927
command = command.replace('^', '^^')
20-
# Only test if there are commands which change state.
21-
if run_pretest:
22-
assert not level._test()
2328
subprocess.call(command, shell=True)
2429

2530
assert level._test()

0 commit comments

Comments
 (0)