Assignment 1: Tigger
Introduction
Your task in this assignment is to implement Tigger, a subset of the version control system Git.
Git is a very complex program that has many individual commands. You will implement only a few of the most important commands. You will also be given a number of simplifying assumptions, which make your task easier.
Tigger is a much-loved children's book character known for getting Git commands backwards.
You must implement Tigger in Shell.
Interestingly, early versions of Git made heavy use of Shell and Perl.
Reference implementation
Many aspects of this assignment are not fully specified in this document; instead, you must match the behaviour of a reference implementation.
For example, your script tigger-add should match the behaviour of 2041 tigger-add exactly, including producing the same error messages.
Provision of a reference implementation is a common method to provide or define an operational specification, and it's something you will likely need to do after you leave UNSW.
Discovering and matching the reference implementation's behaviour is deliberately part of the assignment.
While the code in the reference implementation is fairly straightforward, reverse-engineering its behaviour is obviously not so simple, and is a nice example of how coming to grips with the precise semantics of an apparently obvious task can still be challenging.
If you discover what you believe to be a bug in the reference implementation, report it in the class forum. We may fix the bug, or indicate that you do not need to match the reference implementation's behaviour in this case.
Tigger Commands
Subset 0
Subset 0 commands must be implemented in POSIX-compatible Shell. See the Permitted Languages section for more information.
tigger-init
The tigger-init command creates an empty Tigger repository.
tigger-init should create a directory named .tigger, which it will use to store the repository. It should produce an error message if this directory already exists.
You should match this, and other error messages exactly. For example:
ls -d .tigger
ls: cannot access .tigger: No such file or directory
./tigger-init
Initialized empty tigger repository in .tigger
ls -d .tigger
.tigger
./tigger-init
./tigger-init: error: .tigger already exists
tigger-init may create initial files or directories inside .tigger.
You do not have to use a particular representation to store the repository.
You do not have to create the same files or directories inside .tigger as the reference implementation. You can create whatever files or directories inside .tigger you wish.
Do not store information outside .tigger
tigger-add filenames...
The tigger-add command adds the contents of one or more files to the index.
Files are added to the repository in a two-step process. The first step is adding them to the index.
You will need to store files in the index somehow in the .tigger sub-directory. For example, you might choose store them in a sub-directory of .tigger.
Only ordinary files in the current directory can be added. You can assume filenames start with an alphanumeric character ([a-zA-Z0-9]) and will only contain alpha-numeric characters, plus '.', '-' and '_' characters.
The tigger-add command, and other Tigger commands, will not be given pathnames with slashes.
tigger-commit -m message
The tigger-commit command saves a copy of all files in the index to the repository.
A message describing the commit must be included as part of the commit command.
Tigger commits are numbered sequentially: they are not hashes, like Git. You must match the numbering scheme.
You can assume the commit message is ASCII, does not contain new-line characters, and does not start with a '-' character.
tigger-log
The tigger-log command prints a line for every commit made to the repository: each line should contain the commit number and the commit message.
tigger-show [commit]:filename
The tigger-show should print the contents of the specified filename as of the specified commit. If commit is omitted, the contents of the file in the index should be printed.
You can assume the commit if specified will be a non-negative integer.
For example:
./tigger-init
Initialized empty tigger repository in .tigger
echo line 1 > a
echo hello world >b
./tigger-add a b
./tigger-commit -m 'first commit'
Committed as commit 0
echo line 2 >>a
./tigger-add a
./tigger-commit -m 'second commit'
Committed as commit 1
./tigger-log
1 second commit
0 first commit
echo line 3 >>a
Subset 1
Subset 1 is more difficult. You will need to spend some time understanding the semantics (meaning) of these operations, by running the reference implementation, or researching the equivalent Git operations.
Note the assessment scheme recognises this difficulty.
Subset 1 commands must be implemented in POSIX-compatible Shell. See the Permitted Languages section for more information.
tigger-commit [-a] -m message
tigger-commit can have a -a option, which causes all files already in the index to have their contents from the current directory added to the index before the commit.
tigger-rm [--force] [--cached] filenames...
tigger-rm removes a file from the index, or from the current directory and the index.
If the --cached option is specified, the file is removed only from the index, and not from the current directory.
tigger-rm, like git rm, should stop the user accidentally losing work, and should give an error message instead if the removal would cause the user to lose work. You will need to experiment with the reference implementation to discover these error messages. Researching git rm's behaviour may also help.
The --force option overrides this, and will carry out the removal even if the user will lose work.
tigger-status
tigger-status shows the status of files in the current directory, the index, and the repository.
./tigger-init
Initialized empty tigger repository in .tigger
touch a b c d e f g h
./tigger-add a b c d e f
./tigger-commit -m 'first commit'
Committed as commit 0
echo hello >a
echo hello >b
echo hello >c
./tigger-add a b
echo world >a
rm d
Subset 2
Subset 2 is extremely difficult. You will need to spend considerable time understanding the semantics of these operations, by running the reference implementation, and/or researching the equivalent Git operations.
Note the assessment scheme recognises this difficulty.
Subset 2 commands must be implemented in POSIX-compatible Shell. See the Permitted Languages section for more information.
tigger-branch [-d] [branch-name]
tigger-branch either creates a branch, deletes a branch, or lists current branch names.
tigger-checkout branch-name
tigger-checkout switches branches.
Note that, unlike Git, you can not specify a commit or a file: you can only specify a branch.
tigger-merge (branch-name|commit) -m message
tigger-merge adds the changes that have been made to the specified branch or commit to the index, and commits them.
./tigger-init
Initialized empty tigger repository in .tigger
seq 1 7 >7.txt
./tigger-add 7.txt
./tigger-commit -m commit-1
Committed as commit 0
./tigger-branch b1
./tigger-checkout b1
Switched to branch 'b1'
perl -pi -e 's/2/42/' 7.txt
cat 7.txt
1
42
3
4
5
6
7
If a file has been changed in both branches tigger-merge produces an error message.
Note: if a file has been changed in both branches git examines which lines have been changed and combines the changes if possible. Tigger doe not do this, for example:
./tigger-init
Initialized empty tigger repository in .tigger
seq 1 7 >7.txt
./tigger-add 7.txt
./tigger-commit -m commit-1
Committed as commit 0
./tigger-branch b1
./tigger-checkout b1
Switched to branch 'b1'
perl -pi -e 's/2/42/' 7.txt
cat 7.txt
1
42
3
4
5
6
7
./tigger-commit -a -m commit-2
Committed as commit 1
Testing
Autotests
As usual, some autotests will be available:
2041 autotest tigger tigger-*
...
You can also run only tests for a particular subset or an individual test:
2041 autotest tigger subset1 tigger-*
...
2041 autotest tigger subset1_13 tigger-*
...
If you are using extra Shell files, include them on the autotest command line.
Autotest and automarking will run your scripts with a current working directory different to the directory containing the script. The directory containing your submission will be in $PATH.
You will need to do most of the testing yourself.