手写一下git的一些命令
git作为企业开发中比不可以少的一部分,可以说和我们以后的代码生活息息相关。
git add fileRoute // 添加指定文件到暂存区
git commit -m "又要提交什么东东" //添加指定目录到暂存区,包括子目录
git push origin master // 上传至远程云端
git log --oneline // 查看提交记录
git checkout -b "branchname" // 创建分支和切换分支。
git merge "branchname" // 合并分支
复制代码
前三行命令几乎每天都需要敲上几次,可以说都是朋友了,但这个朋友具体是怎么做的呢,今天就来研究一下,有点简陋,敬请谅解。
开搞准备
需要下载git软件,这样才可以使用命令。(使用命令的目的是和手写的做对比)
需要下载node.js软件,这样才可以在命令行运行js文件。
开始咯
- 先初始化git, 使用git init –这样在目录下回出现.git文件夹(这是我们本地仓库哦)
- 创建一个js文件,所有代码都在这里面,使用原型链的方式实现
Git类
创建一个Git函数,代表一个仓库类,我们可以通过new关键字来创建仓库。
类中有仓库名、版本id(使用变量自增保证不重复)、分支数组、主分支实例…
function Git(name) {
// 仓库名
this.name = name;
// 版本id
this.lastCommitId = -1;
// 分支数组
this.branches = [];
// 默认是master(主分支)
this.master = new Branch('master', null);
this.branches.push(this.master);
// 头指针
this.HEAD = this.master;
}
//创建test仓库,将其赋值给repo变量
var repo = new Git("test");
复制代码
Branch类
分支类,可以创建多个分支,因为master为主分支,不可以随意修改,所以我们需要创建分支来修改和测试。
function Branch(name, commit) {
// 分支名
this.name = name;
this.commit = commit
}
复制代码
Commit类
创建Commit类,类中有当前当前版本id、前一个版本parent(版本id)、提交说明
function Commit(id, parent, message) {
this.id = id;
this.parent = parent;
this.message = message;
}
复制代码
使用原型的方式,使得每一个仓库都可以拥有commit提交功能。
Git.prototype.commit = function (message) {
var commit = new Commit(++this.lastCommitId, this.HEAD.commit, message)
// 头指针指向当前新创建的commit类节点
this.HEAD.commit = commit;
return commit;
}
repo.commit("hello1")// 需要打印的话使用console.log(repo.commit("hello1"))
复制代码
这样提交功能就实现了咯
git log –oneline
同样是原型的用法,使得每一个仓库都可以拥有log查看历史提交记录功能。
这里采用了类似链表的操作,一步一步查找上一个版本
Git.prototype.log = function () {
var commit = this.HEAD.commit,
history = [];
while (commit) {
history.push(commit);
commit = commit.parent
}
return history
}
// 多添加几个记录
repo.commit("hello2")
repo.commit("hello3")
console.log(repo.log());
复制代码
上图返回的是每个提交记录的所有内容,我们正常使用git log –oneline不需要
所以我们可以创建一个函数来使得他只返回版本id
repo.commit("change1")
repo.commit("change2")
repo.commit("change3")
function historyToIdMapper(history) {
var ids = history.map(commit => commit.id)
return ids.join("-")
}
console.log(historyToIdMapper(repo.log()));
复制代码
创建分支
同样是原型的用法,使得每一个仓库都可以拥有其他分支,确保master分支不会改变。
我们可以使用git checkout -b “branchname” 命令创建一个新的分支,在checkout函数中,我们手写的过程需要判断一下分支名称是否存在,存在就将头指针指向该分支。使用git checkout “branchname” 可以创建一个新的分支,并且将头指针 移动到当前分支的头部。
Git.prototype.checkout = function (branchName) {
for (var i = this.branches.length; i--;) {
if (this.branches[i].name == branchName) {
console.log('Switched to existing branch: ' + branchName);
this.HEAD = this.branches[i];
return this;
}
}
var newBranch = new Branch(branchName, this.HEAD.commit);
this.branches.push(newBranch);
this.HEAD = newBranch;
console.log(`Switched to new branch: ` + branchName);
// 返回当前分支
return this;
}
console.log(historyToIdMapper(repo.log()));
repo.checkout("testing")
repo.commit("change4")
console.log(historyToIdMapper(repo.log()));
repo.checkout("master")
console.log(historyToIdMapper(repo.log()));
复制代码
下图是:在创建分支后提交一次,分别查看记录,然后选择master分支,查看master分支是否受新分支的影响
合并分支
只写了合并master和一个分支
Git.prototype.Merge = function (branchName){
for (var i = this.branches.length; i--;) {
if (this.branches[i].name == branchName) {
var merge = [], commit = this.branches[i].commit,temp
while (commit != this.master.commit) {
merge.unshift(commit)
commit = commit.parent
}
merge.forEach(val =>{
temp = this.master.commit
this.master.commit = val
this.master.commit.parent =temp
})
return this
}
}
console.log(branchName +" branch is not find");
}
//测试
console.log(historyToIdMapper(repo.log()));
repo.checkout("testing")
repo.commit("change4")
console.log(historyToIdMapper(repo.log()));
repo.checkout("master")
console.log(historyToIdMapper(repo.log()));
repo.Merge("testing")
console.log(historyToIdMapper(repo.log()));
复制代码
测试是在创建了新的分支testing后,然后转到master分支,再调用Merge合并函数,在进行打印结果
结语
手写不易,请大家给文章点一个赞,谢谢。笔者在这提前祝大家中秋快乐。