Add assignment1 draft
This commit is contained in:
parent
b6d70bc6b6
commit
f8046ed758
14
.clang-format
Normal file
14
.clang-format
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
ColumnLimit: 120
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
...
|
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@ -0,0 +1,17 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{hpp,cpp,h,c}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
184
assignment1/README.md
Normal file
184
assignment1/README.md
Normal file
@ -0,0 +1,184 @@
|
||||
# Assignment 1 (draft)
|
||||
|
||||
*due on 18 November 2020*
|
||||
|
||||
In this first assignment you are tasked to create a very basic version control system (VCS) similar to [Git](https://git-scm.com/) or [Mercurial](https://www.mercurial-scm.org/).
|
||||
|
||||
For this assignment you are *not* allowed to work in teams.
|
||||
You are not allowed to use code from other people participating in this course.
|
||||
Always state the origin of non-original code and ideas.
|
||||
|
||||
It is recommend to be familiar Git to understand the intensions behind the following commands.
|
||||
|
||||
## `lit`
|
||||
|
||||
All functionality of your VCS is bundled into one executable named `lit`.
|
||||
Similar to `git`, it provides multiple *sub-commands* like `checkout` and `status`.
|
||||
These sub-commands are always provided as first argument to `lit` and explained below.
|
||||
|
||||
### `lit help`
|
||||
|
||||
Displays a concise usage information.
|
||||
Each sub-command is listed and described briefly.
|
||||
|
||||
### `lit init`
|
||||
|
||||
To initialize a repository run `lit init` inside some directory.
|
||||
This directory is now the root of the repository.
|
||||
Additionally, the VCS creates a new folder `.lit` containing all internal data.
|
||||
|
||||
All files of the directory are tracked.
|
||||
There is no need to explicitly add them as you'd do with Git.
|
||||
|
||||
### `lit status`
|
||||
|
||||
Lists all files that have been added, removed, or modified, with respect to the currently checked out commit.
|
||||
|
||||
Keep the output concise, similar to `git status --short`.
|
||||
|
||||
### `lit commit`
|
||||
|
||||
Creates a new commit containing *all* changes.
|
||||
In contrast to Git, there is no staging area.
|
||||
|
||||
A commit is comprised of a unique identifier, the identifier of the previous commit, a timestamp, a message, and the recorded changes.
|
||||
The message is provided to the `commit` sub-command as additional argument.
|
||||
|
||||
As unique identifier use a counter (starting from 0) and prefix the value with `r` (for revision).
|
||||
|
||||
```
|
||||
$ lit commit 'Commit message goes here'
|
||||
Commit: r42
|
||||
Date: Mon Sep 28 23:27:53 CEST 2020
|
||||
```
|
||||
|
||||
### `lit show`
|
||||
|
||||
This sub-command is used to inspect the given commit.
|
||||
If no commit is specified, display the currently checked out one.
|
||||
|
||||
```
|
||||
$ lit show r42
|
||||
Commit: r42
|
||||
Date: Mon Sep 28 23:27:53 CEST 2020
|
||||
|
||||
Commit message goes here
|
||||
|
||||
--- a/Assets/Generic/Logic/Utils/Math.cs
|
||||
+++ b/Assets/Generic/Logic/Utils/Math.cs
|
||||
@@ -1,5 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
+static class Vector2Extensions
|
||||
+{
|
||||
+ public static Vector3 AsVector3(this Vector2 v) => new Vector3(v.x, v.y);
|
||||
+}
|
||||
+
|
||||
static class Vector3Extensions
|
||||
{
|
||||
public static Vector2 AsVector2(this Vector3 v) => new Vector2(v.x, v.y);
|
||||
```
|
||||
|
||||
### `lit checkout`
|
||||
|
||||
This resets the state of all files to the given commit's state.
|
||||
All un-commited changes are dropped upon checkout.
|
||||
|
||||
If no commit is specified, reset the current state to the currently checked out commit.
|
||||
|
||||
You can add new branches by first checking out a previous commit, and then creating a new commit.
|
||||
|
||||
### `lit merge`
|
||||
|
||||
This command initiates a merge with the currently checked out commit and the specified commit.
|
||||
A merge is only initiated if there are no un-commited changes.
|
||||
|
||||
Auto-merging files that have been touched in both branches is not supported.
|
||||
If a file has been modified in both branches, the whole file is treated as a conflict.
|
||||
|
||||
If a conflict is encountered, stop the merge process and provide the respective files of the other branch as well as the common base.
|
||||
|
||||
```
|
||||
$ lit merge r1
|
||||
Merge conflict(s) detected:
|
||||
- robot.c
|
||||
|
||||
$ ls
|
||||
robot.c # currently checked out version.
|
||||
robot.c.r1 # version of the other branch
|
||||
robot.c.r0 # common base of both branches
|
||||
|
||||
# Manually resolving the merge conflict:
|
||||
$ vimdiff robot.c robot.c.r1 robot.c.r0
|
||||
|
||||
# Cleanup
|
||||
$ rm robot.c.r1 robot.c.r0
|
||||
|
||||
$ lit commit
|
||||
```
|
||||
|
||||
To complete the merge after manually resolving a conflict, invoke the `commit` sub-command.
|
||||
To abort the merge, use `checkout`.
|
||||
|
||||
### `lit log`
|
||||
|
||||
Displays a graph of all commits, one line per commit.
|
||||
The currently checked out commit is highlighted.
|
||||
|
||||
You don't have to follow the exact format of this example:
|
||||
|
||||
```
|
||||
$ lit log
|
||||
o─┐ < r3 "Merge r2 with r1"
|
||||
│ o r2 "Add chocolate egg dispenser"
|
||||
o │ r1 "Add coin operated self destruct feature"
|
||||
o─┘ r0 "First Commit"
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
You are only allowed to use:
|
||||
- C++ standard library (C++17 standard)
|
||||
- C standard library (as fallback)
|
||||
- POSIX standard library
|
||||
- `diff` / `patch` command
|
||||
|
||||
You must use CMake as build system.
|
||||
|
||||
Use [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) to automatically format your code using the provided `.clang-format` configuration.
|
||||
There is probably a plugin for your text editor / IDE to automate this process.
|
||||
|
||||
Your VCS must store the differences (as reported by `diff -u`).
|
||||
Storing a full copy of the repository's files for each commit is not allowed.
|
||||
You don't need to track empty folders, yet files located in sub-directories.
|
||||
|
||||
You may assume that only one instance of your VCS operators on a repository at any point in time.
|
||||
Hence, you don't need to add some form of locking mechanism to prevent concurrent access.
|
||||
|
||||
The executable does not depend on any additional resources (except for `diff` and `patch`).
|
||||
You may assume that `diff` and `patch` are present and available via `PATH`.
|
||||
|
||||
**Hint:** It may be a good idea to create a dedicated class for invoking shell commands like `diff` and `patch`.
|
||||
Simply using `system(3)` may not give you enough control over the process as you also need to interactive with `stdin` / `stdout`.
|
||||
Consider using `popen(3)` and getting some inspiration from [Go's `exec` package](https://golang.org/pkg/os/exec/) or [Python's `subprocess` module](https://docs.python.org/3/library/subprocess.html).
|
||||
|
||||
## Testing
|
||||
|
||||
Along with this specification a rudimentary test script [`lit-test`](lit-test) is provided, have a look at it.
|
||||
It assumes that the `lit` executable is in your path.
|
||||
Remember that you can use `bash -x` to debug the test script.
|
||||
|
||||
You are encouraged to setup some more test cases for your implementation.
|
||||
|
||||
## Evaluation (9 points)
|
||||
|
||||
- (3) Can create new commits and checkout old ones (no branches)
|
||||
- (2) Can create new branches and switch between branches
|
||||
- (1) Can inspect a commit using `lit show`
|
||||
- (1) Can merge two branches (no conflict)
|
||||
- (1) Can merge two branches (with conflict)
|
||||
- (1) Can display a graph with all commits and their relationships
|
||||
|
||||
## Submission
|
||||
|
||||
TBD
|
181
assignment1/lit-test
Executable file
181
assignment1/lit-test
Executable file
@ -0,0 +1,181 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
readonly TEST_DIR=$(mktemp --tmpdir --directory lit-test.XXXXXX)
|
||||
|
||||
echo "== Using $TEST_DIR"
|
||||
pushd "$TEST_DIR"
|
||||
|
||||
echo "== Initializing repository"
|
||||
lit init
|
||||
|
||||
echo "== Creating the first commit"
|
||||
cat >file1 <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
EOF
|
||||
|
||||
# Let's check the status. Should look something like this:
|
||||
# Changes:
|
||||
# Add file1
|
||||
lit status
|
||||
|
||||
# We expect the first commit to be identified as r0.
|
||||
lit commit "Add file1"
|
||||
|
||||
echo "== Creating more commits"
|
||||
echo >>file1 "A third line is added to the first file."
|
||||
|
||||
# Let's check the status again, just to be sure.
|
||||
lit status
|
||||
|
||||
# This one would be r1.
|
||||
lit commit "Extend file1"
|
||||
|
||||
echo >>file1 "A forth line is added."
|
||||
|
||||
# This should be r2.
|
||||
lit commit "Extend file1 even further"
|
||||
|
||||
echo "== Displaying graph"
|
||||
# o < r2 Extend file1 even further
|
||||
# o r1 Extend file1
|
||||
# o r0 Add file1
|
||||
lit log
|
||||
|
||||
echo "== Switching to r0"
|
||||
lit checkout r0
|
||||
|
||||
# Checking the file content.
|
||||
diff -s file1 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
EOF
|
||||
|
||||
echo "== Switching back to r2"
|
||||
lit checkout r2
|
||||
|
||||
# Checking the file content again.
|
||||
diff -s file1 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
A third line is added to the first file.
|
||||
A forth line is added.
|
||||
EOF
|
||||
|
||||
echo "== Adding and discarding changes"
|
||||
echo >>file1 "This fifth line should be gone in an instant."
|
||||
lit checkout
|
||||
|
||||
# Let's confirm.
|
||||
diff -s file1 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
A third line is added to the first file.
|
||||
A forth line is added.
|
||||
EOF
|
||||
|
||||
echo "== Creating another branch"
|
||||
lit checkout r0
|
||||
mkdir subfolder
|
||||
cat >subfolder/file2 <<-EOF
|
||||
This is the first line of the second file.
|
||||
And another line in the second file.
|
||||
EOF
|
||||
|
||||
# This should be r3.
|
||||
lit commit "Add file2"
|
||||
|
||||
# o < r3 Add file2
|
||||
# │ o r2 Extend file1 even further
|
||||
# │ o r1 Extend file1
|
||||
# o─┘ r0 Add file1
|
||||
lit log
|
||||
|
||||
echo "== Going back"
|
||||
lit checkout r2
|
||||
|
||||
# file2 should be gone.
|
||||
test ! -f subfolder/file2
|
||||
|
||||
echo "== Merging (no conflict)"
|
||||
|
||||
# This creates a merge commit r4.
|
||||
lit merge r3
|
||||
|
||||
# file2 should now be present.
|
||||
diff -s subfolder/file2 <<-EOF
|
||||
This is the first line of the second file.
|
||||
And another line in the second file.
|
||||
EOF
|
||||
|
||||
# o─┐ < r4 Merge r3 into r2
|
||||
# │ o r3 Add file2
|
||||
# o │ r2 Extend file1 even further
|
||||
# o │ r1 Extend file1
|
||||
# o─┘ r0 Add file1
|
||||
lit log
|
||||
|
||||
echo "== Setting up a conflict"
|
||||
echo >>file1 "Fifth line ontop of r4."
|
||||
lit commit "Extend file1 one way" # r5
|
||||
|
||||
lit checkout r3
|
||||
echo >>file1 "Third line ontop of r3."
|
||||
lit commit "Extend file1 another way" # r6
|
||||
|
||||
# o < r6 Extend file1 another way
|
||||
# o │ r5 Extend file1 one way
|
||||
# o─┤ r4 Merge r3 into r2
|
||||
# │ o r3 Add file2
|
||||
# o │ r2 Extend file1 even further
|
||||
# o │ r1 Extend file1
|
||||
# o─┘ r0 Add file1
|
||||
lit log
|
||||
|
||||
# Going back and merging.
|
||||
lit checkout r5
|
||||
lit merge r6 || true
|
||||
|
||||
# Let's check all file versions:
|
||||
# Current commit
|
||||
diff -s file1 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
A third line is added to the first file.
|
||||
A forth line is added.
|
||||
Fifth line ontop of r4.
|
||||
EOF
|
||||
|
||||
# other breanch
|
||||
diff -s file1.r6 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
Third line ontop of r3.
|
||||
EOF
|
||||
|
||||
# common base
|
||||
diff -s file1.r3 - <<-EOF
|
||||
This is the first line of the first file. 🚀
|
||||
This is the second line of the first file.
|
||||
EOF
|
||||
|
||||
# To resolve the conflict, we simply take the version of the current commit.
|
||||
rm file1.r6 file1.r3
|
||||
|
||||
lit commit # r7
|
||||
|
||||
# o─┐ < r7 Merge r6 into r5
|
||||
# │ o r6 Extend file1 another way
|
||||
# o │ r5 Extend file1 one way
|
||||
# o─┤ r4 Merge r3 into r2
|
||||
# │ o r3 Add file2
|
||||
# o │ r2 Extend file1 even further
|
||||
# o │ r1 Extend file1
|
||||
# o─┘ r0 Add file1
|
||||
lit log
|
||||
|
||||
echo "== Cleanup"
|
||||
popd
|
||||
rm -r "$TEST_DIR"
|
Loading…
Reference in New Issue
Block a user