CS61B项目笔记(八)-ProJ2-complish
【超干货】CS61B 2021sp全攻略(上)|一亩三分地公开课版 (1point3acres.com)的建议:
我做proj2花了大概10天代码大概一共800行推荐到springbreak的时候做这个项目写之前要把lab6复习一遍再把Lecture12看完然后推荐先把spec读一遍再看intro视频磨刀不误砍柴这个时候终于对要写几个对象、分别实现什么功能有点概念了然后再读一遍spec对着指令一条一条实现缺少一个整体设计概念的话不建议着急写代码否则你debug40多条指令的时间会远远高于这些思考的时间我感觉merge是最复杂的可以先看助教的视频他给你总结好了7种情况分类讨论下来有点心累但提交autograde看到1600满分的时候爽爆了
Lec12:
- cs61b 2021 lec12 command line programming, data structures preview - Google 幻灯片
- Spring 2021: Live Lecture 12 (youtube.com)
Lec12
命令行的介绍
版本控制
Approach Number | Information to use as file version number | Downside |
---|---|---|
1, 2, and 3 | Commit ID (that goes up by 1) that includes the file. | No central server to decide which commit is “next” if people are working offline. |
4 | Date and time of file. | Awkward to deal with simultaneous file changes. Not as elegant as SHA1-hash. |
5 | git-SHA1 hash of file. | ??? |
Approach 1-3
Approach 4
Approach 5
commit后会出现3个文件夹:
- 其中一个是以hash码前两位为名称,hash码文件的
- 其中一个是存储了commit消息的
- 另一个是读取文件的
序列化和储存
分支合并
这里没看懂…
Lab6
CS61B项目笔记(四)-Lab6-文件序列化 | bai的小窝 (bailog.top)
Git Intro
视频主要介绍了git init
、git add x
、git commit
、git checkout
这四个命令
git init
创造两个区域,一个存储区域和确认区域
git add
git commit
清空储存区,提交确认
git checkout
checkout的时候要保证status树是干净的
Gitlet Intro
Gitlet设计文档
类以及数据结构
Commit
1 | private String message; |
CommitTree
1 | public static Commit HEAD; |
Blob
1 | String fileName; |
StagingArea
1 | private static final File CWD = Repository.CWD; |
算法
对于复杂的任务,比如确定合并冲突,我们建议您将任务分解成几个部分。在单独的部分中描述每个部分的算法。从最简单的组件开始,一次构建设计的每一部分。例如,您的合并冲突的算法部分可以有以下部分:
- 检查是否需要合并。
- 确定哪些文件(如果有)存在冲突。
- 在文件中表示冲突。 尽量清晰地使用空格或其他符号标记类的标题或名称。
Gitlet编写思路
前序工作
可以把文件类比成Lab6里的Dog
整体逻辑框架
init做了什么?
init创建了.gitlet文件,我们可以参考下git的:
如图所示:
- HEAD指针指向的是一个文件,文件里存储了当前指向的文件码
- objects文件夹存储的应该是blobs里的文件,而他使用的是Hash表
整理下全部过程
首先add的时候文件序列化后存储在了我的index文件夹,然后commit的时候,commit节点是包含着Blobs节点的。这里就有个需要解决的地方:
- commit如何指向?
- 初步想法是commit的时候,在commitTree添加节点,然后每个节点有个列表,列表里包含了文件的sha1值
- 如何通过sha1值找到指向的值?
- 我的StagingArea应该会有一个方法,通过指定的sha1值找到其文件。
Blob
Blob 是 Git 中用来存储文件内容的基本单位。它可以是文本文件、图像、音频或任何其他类型的文件,Git 对它们都一视同仁。每个 Blob 对象都会被分配一个唯一的 SHA-1 哈希值,该哈希值是根据 Blob 对象的内容计算得出的。
当你向 Git 添加文件时,Git 会将文件内容存储为 Blob 对象。在 Git 内部,Blob 对象被保存在 .git/objects
目录下,并以其哈希值命名的文件中。这样,Git 就能够非常高效地存储和检索文件内容。
SHA1值前两位为文件名,后38位为文件名
add
- 首先找到CWD中的文件
- 将文件存为Blob
- 将Blob存入Hash表[SHA1-Blob]
- 将Blob序列化存入.index文件中
- 将文件对应的Blob存入additon中
commit
- 根据传入的message new 一个 commit
- commit的parent来自HEAD
- 复制文件表中的Blob
- 序列化?
rm
- 如果文件已经被add, 那么从add区删除
- 如果文件已经被commit, 则标记为删除
- 从工作列表中删除文件
checkout
- status得干净
做题思路
重要的一点
为了保证程序的持续性,我们执行命令前需要读取被存储的文件,如HEAD
、AdditonStage
等
init
- 描述:在当前目录中创建一个新的 Gitlet 版本控制系统。该系统将自动开始一个提交:一个不包含文件且具有提交消息
initial commit
(就是这样,没有标点符号)。它将有一个单一分支:master
,最初指向此初始提交,并且master
将是当前分支。此初始提交的时间戳将为 00:00:00 UTC,Thursday, 1 January 1970,以您选择的日期格式(这被称为“Unix 纪元”,内部由时间 0 表示)。由于由 Gitlet 创建的所有存储库中的初始提交都具有完全相同的内容,因此所有存储库将自动共享此提交(它们将具有相同的 UID),并且所有存储库中的所有提交都将追溯到它。 - 失败情况:如果当前目录中已经存在 Gitlet 版本控制系统,则应中止。不应使用新系统覆盖现有系统。应打印错误消息
A Gitlet version-control system already exists in the current directory.
。
明确一下我们要做什么:
- 首先创建一个
.gitlit
的文件夹 - 然后自动提交一个初始
commit
- 设置
master
和HEAD
指针 - 初始化
StagingArea
目录 - 初始化
CommitTree
初始化后目录:
1 | .gitlet |
add
描述:将文件的当前副本添加到暂存区(参见
commit
命令的描述)。因此,添加文件也称为为添加而暂存文件。将已经暂存的文件暂存会使用新内容覆盖暂存区中的先前条目。暂存区应该位于.gitlet
的某个地方。如果文件的当前工作版本与当前提交中的版本相同,则不要将其暂存以添加,并且如果已经存在(当文件更改、添加,然后更改回其原始版本时可能会发生)的情况下,从暂存区删除它。文件将不再被暂存以删除(请参见gitlet rm
),如果在命令时处于该状态。失败情况:如果文件不存在,则打印错误消息
File does not exist.
并且退出而不更改任何内容。思路
首先读取
addtionStage
、removalStage
和HEAD
找到需要add的文件
为该文件创建blob快照
将blob存储到object文件夹
上级文件夹名为Sha1的前两位,文件名为Sha1的后38位
特殊情况判断
将该blob添加到
addtionStage
特殊情况判断:
- 如果removalStage中有该版本,清空rS,不添加到aS
- 如果Head指向的commit已经包含了该版本,忽略这次提交
commit
描述: 在当前提交和暂存区保存已跟踪文件的快照,以便稍后可以恢复,创建一个新的提交。该提交被称为跟踪保存的文件。默认情况下,每个提交的文件快照将与其父提交的文件快照完全相同;它将保留文件的版本完全不变,不会更新它们。提交仅会更新在提交时已标记为要添加的文件的内容,在这种情况下,提交现在将包含已标记为要添加的文件的版本,而不是从其父提交中获取的版本。提交将保存并开始跟踪任何已标记为要添加但父提交未跟踪的文件。最后,由于被
rm
命令(下面)标记为要删除,当前提交中跟踪的文件可能会在新提交中被取消跟踪。失败情况: 如果没有文件被暂存,则中止。打印消息
No changes added to the commit.
。每个提交必须有一个非空消息。如果没有,则打印错误消息Please enter a commit message.
。对于已跟踪文件在工作目录中缺失或更改的情况不算是失败。完全忽略.gitlet
目录外的所有内容。思路:分两种情况,第一种是init时提交的初始commit,另一种就是正常commit的
读取
HEAD
、curBranch
、rS
、aS
、CList
- 首先新建commit
- 将该commit提交到commitTree:
检查是否为初始提交,若是:
- 将该commit直接写入HEAD,curBranch(master)指针中去
- 存储到object文件夹中,存储方式同blobs
- 将该commit的ShaName添加到CList列表中保存文件CList
若非:
- 将该commit的Parent设置为HEAD指向的commit的ShaName
- 拷贝父提交的version哈希表
- 更新version哈希表
- 清空所有Stage
- 将该commit写入HEAD,curBranch指针中去
- 存储到object文件夹中,存储方式同blobs
- 将该commit的ShaName添加到CList列表中并保存文件Clist
记住,清空Stage的时候需要保存两个Stage
rm
描述: 如果文件当前已暂存以添加,则取消暂存该文件。如果文件在当前提交中被跟踪,则将其标记为删除,并从工作目录中删除该文件(除非用户已经这样做,否则不要删除它)。
失败情况: 如果文件既没有被暂存也没有被当前提交跟踪,则打印错误消息
No reason to remove the file.
。思路
首先读取需要用到的
如果add了,那就取消add
如果当前提交有追踪当前文件,将该文件添加到rA并删除CWD中该文件。
log
描述: 从当前头提交开始,沿着提交树向后显示每个提交的信息,直到初始提交,跟随第一个父提交链接,忽略合并提交中找到的任何第二父提交(在常规Git中,这就是使用
git log --first-parent
得到的)。这组提交节点称为提交的历史记录。对于历史记录中的每个节点,应显示的信息是提交ID、提交时间和提交消息。以下是应遵循的确切格式示例:思路
1 | === |
- 读取需要的东西
- 根据实例,为commit覆写toString方法
- 利用StringBulider来存储信息
- 利用递归来添加commit的信息
global-log
描述: 类似于日志,但显示有关已经进行的所有提交的信息。提交的顺序并不重要。提示:在
gitlet.Utils
中有一个有用的方法,可以帮助您遍历目录中的文件。思路
读取需要的东西
也是用StringBuilder来存储信息
重要的一点是获得所有Commit的列表,我们可以直接读取我们的CList文件来获取
另一个想法: 可以创建一个log文件,每次addCommit的时候就append
find
- 描述: 打印出具有给定提交消息的所有提交的ID,每行一个。如果有多个这样的提交,它会将ID分别打印在不同的行上。提交消息是一个单独的操作数;要指示多个单词的消息,请将操作数放在引号中,如下所示的
commit
命令。提示:此命令的提示与global-log
的提示相同。 - 失败情况: 如果不存在这样的提交,则打印错误消息
Found no commit with that message.
。
类似golbal-log,复用其代码即可
status
描述: 显示当前存在的分支,并用
*
标记当前分支。还显示哪些文件已经被标记为添加或删除。它应该遵循的确切格式示例如下。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20PLAINTEXT
=== 分支 ===
*master
other-branch
=== 暂存的文件 ===
wug.txt
wug2.txt
=== 已删除的文件 ===
goodbye.txt
=== 未暂存的修改 ===
junk.txt (deleted)
wug3.txt (modified)
=== 未跟踪的文件 ===
random.stuff
思路
最后两个我没有实现
- 这个重点考察了持续性的使用,只要正确读取就不难
checkout
检出是一种通用命令,可以根据其参数执行几种不同的操作。下面有3种可能的用法。在每个部分下面,您会看到3个编号的点。每个对应于相应的检出用法。
- 用法
java gitlet.Main checkout -- [文件名]
java gitlet.Main checkout [提交ID] -- [文件名]
java gitlet.Main checkout [分支名]
- 描述
- 获取文件在当前分支的最新提交中的版本,并将其放入工作目录中,如果已经存在同名文件,则覆盖它。新版本的文件不会被暂存。
- 获取文件在具有给定ID的提交中的版本,并将其放入工作目录中,如果已经存在同名文件,则覆盖它。新版本的文件不会被暂存。
- 获取给定分支头部的提交中的所有文件,并将它们放入工作目录中,如果已经存在同名文件,则覆盖它们。此外,在执行此命令结束时,给定分支将被视为当前分支(HEAD)。任何在当前分支中被跟踪但在检出分支中不存在的文件将被删除。暂存区将被清空,除非检出的分支是当前分支(参见失败情况下面)。
- 失败情况
- 如果文件在上一个提交中不存在,则中止操作,并打印错误消息
File does not exist in that commit.
不要更改当前工作目录。 - 如果不存在具有给定ID的提交,则打印
No commit with that id exists.
。否则,如果文件在给定提交中不存在,则打印与失败情况1相同的消息。不要更改当前工作目录。 - 如果不存在具有该名称的分支,则打印
No such branch exists.
如果该分支是当前分支,则打印No need to checkout the current branch.
如果当前分支中有一个工作文件在检出时将被覆盖,则打印There is an untracked file in the way; delete it, or add and commit it first.
并退出;在执行任何其他操作之前执行此检查。不要更改当前工作目录。
- 如果文件在上一个提交中不存在,则中止操作,并打印错误消息
checkout(String branch)
前两个比较容易就不讨论了
这个切换分支分为三个情况
文件名既被
branch
追踪的文件,也被head
追踪,那么对于相同文件名但blobID
不同(也就是内容不同),则用branch
中的文件来替代原来的文件;相同文件名并且blobID
相同,不进行任何操作。文件名不被
branch
追踪的文件,而仅被head
追踪,那么直接删除这些文件。文件名仅被
branch
追踪的文件,而不被head
追踪,那么直接将这些文件写入到工作目录。这里有个例外,即对于第三种情况,将要直接写入的时候如果有同名文件(例如
1.txt
)已经在工作目录中了,说明工作目录中在执行checkout
前增加了新的1.txt
文件而没有commit
,这时候gitlet不知道是应该保存用户新添加进来的1.txt
还是把branch中的1.txt
拿过来overwrite掉,为了避免出现信息丢失,gitlet就会报错,输出There is an untracked file in the way; delete it, or add and commit it first.
我的做法:
对于第一种情况
- 首先得到一个包含在branchVersion和headVersion文件名的列表(遍历headVersion的keySet)
- 遍历该列表
- 删除CWD中包含在该列表的文件
- 写入branchVersion版本的该文件到CWD中
对于第二种情况
- 首先得到一个不包含在branchVersion但包含在headVersion文件名的列表(遍历headVersion的keySet)
- 遍历该列表
- 删除CWD中包含在该列表的文件
对于第三种情况
- 首先得到一个包含在branchVersion但不包含在headVersion文件名的列表(遍历headVersion的keySet)
- 遍历该列表
- 检查特殊情况
- 直接写入branchVersion版本的该文件到CWD中
不要忘记保存curBranch
branch
- 描述: 创建一个具有给定名称的新分支,并将其指向当前的头部提交。分支只是对提交节点的引用(一个SHA-1标识符)的名称。该命令不会立即切换到新创建的分支(就像真实的Git一样)。在调用分支之前,您的代码应该使用一个名为“master”的默认分支运行。
增加一个Branch,即在heads
文件夹中添加一个新的名为branchname的文件,内容为当前的commitID。此操作不改变HEAD
指向,只是单纯增加一个Branch。改变分支依然是通过checkout
命令来改变。
失败的情况:无
rm-branch
- 描述: 删除具有给定名称的分支。这只是删除与分支关联的指针;不意味着删除在该分支下创建的所有提交,或者类似的操作。
- 失败情况: 如果具有给定名称的分支不存在,则中止。打印错误消息
A branch with that name does not exist.
如果尝试删除当前正在使用的分支,则中止,打印错误消息Cannot remove the current branch.
。
merge
- 用法:
java gitlet.Main merge [分支名称]
- 描述: 将给定分支的文件合并到当前分支。这个方法有点复杂,所以这里有一个更详细的描述:
- 首先考虑当前分支和给定分支的 分割点。例如,如果
master
是当前分支,branch
是给定分支: 分割点是当前分支和给定分支头部的最新共同祖先:- 共同祖先 是一个提交,从两个分支头部都有一条路径(0个或多个父指针)。- 最新 的共同祖先是一个不是其他任何共同祖先的共同祖先。例如,尽管上图中最左边的提交是master
和branch
的共同祖先,但它也是其右边紧邻的提交的祖先,因此它不是最新的共同祖先。如果分割点 是 与给定分支相同的提交,则我们不执行任何操作;合并已完成,并以消息Given branch is an ancestor of the current branch.。
结束操作。如果分割点是当前分支,则效果是检出给定分支,并在打印消息Current branch fast-forwarded.
后结束。否则,我们继续以下步骤:
- 首先考虑当前分支和给定分支的 分割点。例如,如果
失败案例:
- 如果存在已暂存的添加或删除,则打印错误消息
You have uncommitted changes.
并退出。 - 如果给定名称的分支不存在,则打印错误消息
A branch with that name does not exist.
- 如果尝试将分支与自身合并,则打印错误消息
Cannot merge a branch with itself.
- 如果合并会生成错误,因为所做的提交中没有更改,请让此错误的常规提交消息继续进行。
- 如果当前提交中的一个未跟踪文件将被合并覆盖或删除,请打印
There is an untracked file in the way; delete it, or add and commit it first.
并退出;在执行任何其他操作之前执行此检查。
- 如果存在已暂存的添加或删除,则打印错误消息
思路
错误检测
- 检查Stage是否为空
- 检查给定分支是否存在
- 检查合并的是否为头指针
- 第四没看懂
- 同checkout中的思路
特殊情况分析
- 如果分割点是给定分支,不操作
- 如果分支完成,输出······
- 如果分割点是头指针,checkout给定分支并输出······
正常情况分析
- (
x
,y
为分支,s
为分裂点) - 如果文件在
x
被修改,但在y
没有修改 -> 版本为x
的- 若
x
为 给定分支指针, CWD改变
- 若
- 如果文件在
x
,s
不存在,在y
中 -> 版本为y
的- 若
y
为 给定分支指针, CWD改变
- 若
- 如果文件在
x
中不存在,但没被y
修改 -> 删掉- 若
x
为 给定分支指针, CWD改变 - 在分割点处存在但在当前分支中未被修改并且在给定分支中不存在的任何文件都应该被移除(并且未被跟踪)。
- 若
- 如果文件同时在
x, y
中被修改且版本相等,随便了 - 如果文件同时在
x, y
中被修改但版本不一样 -> 引发冲突- 在当前分支和给定分支中以不同方式被修改的任何文件都会冲突。“以不同方式被修改”可以意味着两者的内容都发生了变化且不同,或者一个文件的内容发生了变化而另一个文件被删除,或者文件在分割点处不存在,并且在给定分支和当前分支中具有不同的内容。
- (
方法编写
- 找出分裂点
- 找出改变的文件集 和 未改变的文件集
1. 可以用HashMap来构建
- 根据修改
、未修改
、存在
和不存在
四个标签来标记文件
2. 可以用Set,利用Set的相加减 - 分为五个方法
- 一改一不变情况的方法
- 一存在两不存在的方法
- 一不存在一未修改的方法
- 两改一同的方法
- 两改不同的方法
细节分析
首先读取需要的文件
先错误检测
特殊情况两个if语句
开始正常情况编写
设计一个算法找到分裂点
找出用于五个方法的文件集
- 遍历分割点的文件同两个分支文件比较
- 按
修改
、未修改
、存在
和不存在
四个标签来标记文件
- 按
- 有Set的加减
- 思考中
- 用集合减分裂点
- 集合减分支 + 直接查
- 思考中
- Set和遍历结合
- 对于存在和不存在,用Set
- 对于有无修改,用遍历加标签
- 遍历分割点的文件同两个分支文件比较
对应方法进行操作:
- 对于文件集,若给定分支的提交文件修改了,当前分支的未修改,删除CWD文件,写入给定分支的版本
- 对于文件集,若当前分支的提交文件不存在,给定分支的文件存在,写入给定分支的版本
- 对于文件集,如果在分割点处存在的文件在其中一个分支不存在,另一个分支未修改,直接删掉
- 对于文件集,如果文件均被修改且版本相等,随便搞
- 对于文件集,如果文件均被修改但版本不一样,引发冲突
- 两者的内容都发生了变化且不同,或者一个文件的内容发生了变化而另一个文件被删除,或者文件在分割点处不存在,并且在给定分支和当前分支中具有不同的内容
最后创建合并提交,注意:其第一个父提交为当前头指针
骨架代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// error check
mergeErrCheck(branch);
Commit branchCommit = readBranch(branch);
HashMap<String, Integer> branchAncestors = new HashMap<>();
HashMap<String, Integer> masterAncestors = new HashMap<>();
CommitTree.readHEAD();
findAncestors(branchCommit, branchAncestors, 0);
findAncestors(HEAD, masterAncestors, 0);
// get splitPoint
Commit splitPoint = findSplitPoint(masterAncestors, branchAncestors);
Set<String> splitSet = splitPoint.getVersion().keySet();
HashMap<String, String> curVersion = HEAD.getVersion();
// specialSituation check
specialSituation(splitPoint, branchCommit, branch);
// get changSet
Set<String> changeFileSetOfBranch = getChangeSet(branchCommit, splitPoint);
Set<String> noChangeFileSetOfBranch = opposeSet(changeFileSetOfBranch, branchCommit);
Set<String> changeFileSetOfCurBranch = getChangeSet(HEAD, splitPoint);
Set<String> noChangeFileSetOfCurBranch = opposeSet(changeFileSetOfCurBranch, HEAD);
// get existSet
Set<String> existFileSetOfBranch = getCompareFile(branchCommit, splitPoint, DELETE);
Set<String> noExistFileSetOfBranch = noExistSet(splitSet, HEAD.getVersion().keySet(), branchCommit.getVersion().keySet());
Set<String> existFileSetOfCurBranch = getCompareFile(HEAD, splitPoint, DELETE);
Set<String> noExistFileSetOfCurBranch = noExistSet(splitSet, branchCommit.getVersion().keySet(), HEAD.getVersion().keySet());
// normal situation
branchChangeHeadKeep(branchCommit, noChangeFileSetOfCurBranch, changeFileSetOfBranch, curVersion);
branchExistOthersNot(branchCommit, existFileSetOfBranch, existFileSetOfCurBranch, curVersion);
OneNotExistOneKeep(splitSet, noExistFileSetOfBranch, noChangeFileSetOfCurBranch, curVersion);
checkTwoChangeIfSame(branchCommit, splitSet, changeFileSetOfBranch, noExistFileSetOfBranch, changeFileSetOfCurBranch, noExistFileSetOfCurBranch,curVersion);
String message = "Merged " + branch + " into " + curBranchName + ".";
creatMergeCommmit(message, curVersion, HEAD.getShaName(), branchCommit.getShaName());
收获
对文件的持续性操作有了更深的理解
对文件的写入和读取有了实际操作体验
String readContent = new String(byte[] fileByte);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
- 对函数式编程操作有了体会,面对工程量大的项目应该细化分开
github仓库: [xxbaizero0/CS61B-Tutorial (github.com)](https://github.com/xxbaizero0/CS61B-Tutorial)
# 有用的merge测试
```java
package gitlet;
import static org.junit.Assert.*;
import org.junit.Test;
import java.io.File;
import java.util.HashMap;
import java.util.Set;
public class Text {
static String[] init = new String[]{"init"};
static String[] add = new String[]{"add", "hello.txt"};
static String[] commit = new String[]{"commit", "hello"};
static String[] log = new String[]{"log"};
static String[] rm = new String[]{"rm", "hello.txt"};
static String[] check = new String[]{"checkout", "--", "hello.txt"};
String[] global_log = new String[]{"global-log"};
static String[] status = new String[]{"status"};
private static void creatNewFile(String name) {
File file = Repository.CWD;
File newFile = Utils.join(file, name);
if (!newFile.exists()) {
try {
newFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void branch(String name) {
String[] branch = new String[]{"branch", name};
Main.main(branch);
}
private static void add(String name) {
Main.main(new String[]{"add", name});
}
private static void log() {
Main.main(new String[]{"log"});
}
private static void glog() {
Main.main(new String[]{"global-log"});
}
private static void rm(String name) {
Main.main(new String[]{"rm", name});
}
private static void commit(String name) {
Main.main(new String[]{"commit", name});
}
private static void find(String name) {
Main.main(new String[]{"find", name});
}
private static void check(String checkBranch) {
Main.main(new String[]{"checkout", checkBranch});
}
private static void merge(String checkBranch) {
Main.main(new String[]{"merge", checkBranch});
}
private static void status() {
Main.main(new String[]{"status"});
}
private static void global_log() {
Main.main(new String[]{"global-log"});
}
static String g = "g.txt";
static String f = "f.txt";
static String h = "h.txt";
static String k = "k.txt";
@Test
public void setup() {
File rep = Repository.GITLET_DIR;
if (rep.exists()) {
deleteFolder(rep);
}
creatNewFile(g);
creatNewFile(f);
creatNewFile(h);
creatNewFile(k);
Main.main(init);
}
@Test
public void test2() {
setup();
HashMap<String, Integer> masterAncestors = new HashMap<>();
masterAncestors.put("1", 4);
masterAncestors.put("2", 3);
masterAncestors.put("3", 2);
masterAncestors.put("4", 1);
masterAncestors.put("5", 0);
HashMap<String, Integer> branchAncestors = new HashMap<>();
branchAncestors.put("1", 5);
branchAncestors.put("22", 4);
branchAncestors.put("33", 3);
branchAncestors.put("44", 2);
branchAncestors.put("55", 1);
branchAncestors.put("66", 0);
String split = findSplitPoint(masterAncestors, branchAncestors);
assertEquals(split, "1");
}
@Test
public void test() {
setup();
add(g);
add(f);
commit("1");
branch("other");
add(h);
rm(g);
commit("add h, rm g");
check("other");
rm(f);
add(k);
commit("rm f, add k");
check("master");
global_log();
merge("other");
log();
}
@Test
public void test4() {
add(g);
add(f);
commit("2");
branch("other");
add(h);
rm(g);
commit("a h r g");
check("other");
merge("other");
}
private void reset2() {
add(g);
add(f);
commit("2");
}
@Test
public void test5() {
setup();
reset2();
branch("b1");
add(h);
commit("add h");
branch("b2");
rm(f);
commit("rm f");
//merge("b1");
check("b2");
merge("master");
}
private static void test3() {
String branch = "new";
branch(branch);
add("hello.txt");
add("hello2.txt");
commit("2");
check(branch);
creatNewFile("hello2.txt");
add("hello2.txt");
commit("3");
check("master");
}
public static void deleteFolder(File folder) {
if (folder.isDirectory()) {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
deleteFolder(file);
}
}
}
folder.delete();
}
}