Git命令是一些命令行工具的集合,它可以用来跟踪,记录文件的变动。比如你可以进行保存、比对、分析、合并等。Git是分布式的,这意味着它并不依赖于中心服务器,任何一台机器都可以有一个本地版本的控制系统,我们称之为仓库。如果是多人协作的话,你需要一个线上仓库,用来同步信息。这就是GitHub, BitBucket的工作。
1.安装Git
Linux(Ubuntu):
$ sudo apt-get install git-all
Windows:
推荐使用git for windows(无法下载点击这里-国内站点速度快),它包括了图形工具以及命令行模拟器。
OS X:
$ brew install git
2.配置Git
安装完git,首要任务是配置我们的信息,最重要的是用户名及邮箱,打开终端,执行以下命令。
$ git config --global user.name "myName"
$ git config --global user.email "[email protected]"
3.创建一个新仓库 - git init
git 会把所有文件以及历史记录保存在你的项目中,创建一个新的仓库,首先要去到项目路径,执行 git init。然后git会创建一个隐藏的文件 .git,所有的信息都储存在其中。
在Documents创建一个联系文件夹 GitDemo, 新建一个 demo.c 文件,打开终端:
$ cd Documents/
~/Documents$ mkdir GitDemo
~/Documents$ git init
Initialized empty Git repository in /home/hongwei/Documents/GitDemo/.git/ #(提示多了一个.git文件)
~/Documents$ cd GitDemo/
~/Documents/GitDemo$ vim demo.c
#include
int main()
{
printf("Hello World!\n");
return 0;
}
Esc,shift+:wq保存退出4.检查状态 - git status
git status 会告诉我们创库的当前状态:是否为最新代码,有什么更新等
执行git status
~/Documents/GitDemo$ git status
On branch master
Initial commit
Untracked files:
(use "git add ..." to include in what will be committed)
demo.c
nothing added to commit but untracked files present (use "git add" to track)
git 告诉我们,demo.c尚未跟踪,这是因为这个文件是新的,git不知道是应该跟踪它的变动呢,还是直接忽略不管呢。为了跟踪我们的新文件,我们需要暂存它。
5.暂存 - git add
git 有个概念叫 暂存区,可以包含所有你可能会提交的变动。它一开始为空,你可以通过 git add 命令添加内容,并使用 git commit 提交。
这个例子中只有一个文件:
$ git add demo.c
如果需要提交目录下的所有内容,执行指令:
$ git add-A
再次执行Git status查看:
~/Documents/GitDemo$ git add demo.c
~/Documents/GitDemo$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached ..." to unstage)
new file: demo.c
我们的文件已经提交了。状态信息还会告诉我们暂存区文件发生了什么变动,不过这里我们提交的是一个全新文件。
6.提交 - git commit
创建提交,需要我们提交东西到暂存区(git add),然后:
~/Documents/GitDemo$ git commit -m "First Commit"
[master (root-commit) 08ac0ca] First Commit
1 file changed, 6 insertions(+)
create mode 100644 demo.c
远端仓库
到目前为止,我们的操作都是在本地的,它存在于.git文件中。为了能够协同开发,我们需要把代码发布到远端仓库上。
1.创建远端仓库
登录Github账户,点击上方导航栏的+按钮,选择“New repository”
进入到创建界面,填写Repository name,Description等信息,最后Create Repository
点击CreateRepository后,查看远端仓库的地址
2.链接远端仓库 - git remote add
添加测试用的远端仓库:
$ git remote add origin https://github.com/Grand2015/GithubTest.git
3.上传到服务器 - git push
每次我们要提交代码到服务器上时,都会使用到git push。
git push命令会有两个参数,远端仓库的名字,以及分支的名字:
~/Documents/GitDemo/GithubTest$ git push origin master
Username for 'https://github.com': Grand2015
Password for 'https://[email protected]':
Counting objects: 4, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 338 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/Grand2015/GithubTest.git
cea07c5..6a143dc master -> master
取决于你使用的服务器,push过程你可能需要验证身份。如果没有出差错,现在使用浏览器去你的远端分支上看,demo.c已经在那里等着你了。
4.克隆仓库 - git clone
放在Github上的开源项目,人们可以看到你的代码。可以使用 git clone进行下载到本地。
$ git clone https://github.com/Grand2015/GithubTest.git
Cloning into 'GithubTest'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
Checking connectivity... done.
5.从服务器上拉取代码 - git pull
如果你更新了代码到仓库上,其他人可以通过git pull命令拉取你的变动:
$ git pull origin master
From https://github.com/Grand2015/GithubTest
* branch master -> FETCH_HEAD
Already up-to-date.
因为暂时没有其他人提交,所有没有任何变动
分支
branchs
当你在做一个新功能的时候,最好是在一个独立的区域上开发,通常称之为分支。分支之间相互独立,并且拥有自己的历史记录。这样做的原因是:
稳定版本的代码不会被破坏
不同的功能可以由不同开发者同时开发。
开发者可以专注于自己的分支,不用担心被其他人破坏了环境
在不确定之前,同一个特性可以拥有几个版本,便于比较
1.创建新分支 - git branch
每一个仓库的默认分支都叫master, 创建新分支可以这样:
~/Documents/GithubTest$ git branch NewBranch
2.切换分支 - git checkout
使用git branch,可以查看分支状态:
~/Documents/GithubTest$ git branch
NewBranch
* master
~/Documents/GithubTest$ git checkout NewBranch
Switched to branch 'NewBranch'
3.合并分支 - git merge
我们的 NewBranch 分支的任务是增加一个新分支加入的显示打印任务。我们编辑,添加到暂存区,提交。
代码变成如下状态:
$ cat -n demo.c
1 #include
2 int main()
3 {
4 printf("Hello World\n");
5 printf("A NewBranch was added!");
6 return 0;
7 }
~/Documents/GithubTest$ git diff --cached
~/Documents/GithubTest$ git diff
diff --git a/demo.c b/demo.c
index 36f7b59..a4ddd4e 100644
--- a/demo.c
+++ b/demo.c
@@ -2,5 +2,6 @@
int main()
{
printf("Hello World\n");
+ printf("A NewBranch was added!");
return 0;
}
git diff --cached是产看两次代码的改变情况,git diff 输出 改变情况。
(git diff --cached比较git add和git commit之间的区别,而git diff是比较暂存区的文件和暂存区之间的区别,灵活运用)
紧接着add和commit,中间可以使用git status指令来查看文件提交的状态:
~/Documents/GithubTest$ git status
On branch NewBranch
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: demo.c
no changes added to commit (use "git add" and/or "git commit -a")
~/Documents/GithubTest$ git add demo.c
~/Documents/GithubTest$ git status
On branch NewBranch
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: demo.c
~/Documents/GithubTest$ git commit -m "New Branch"
[NewBranch a1a7828] New Branch
1 file changed, 1 insertion(+)
新分支任务完成了,回到master分支
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
现在去查看代码
~/Documents/GithubTest$ cat -n demo.c
1 #include
2 int main()
3 {
4 printf("Hello World\n");
5 return 0;
6 }
细心的朋友看到,我们刚才加入的显示加入新的分支的打印指令并没有。对的,没有就是对的,这就是分支branch的独立开发,虽然在分支上做了改变,如果我们没有执行master和branch融合指令之前,master上的代码还是原来的代码。
下面是不是要融合了呢?
不,如果就这么简单的融合了,那就太便宜这个例子了,我们下面在对master的代码在做一点改变,添加一个版本号的打印指令:
~/Documents/GithubTest$ git diff
diff --git a/demo.c b/demo.c
index 36f7b59..6d05ca1 100644
--- a/demo.c
+++ b/demo.c
@@ -2,5 +2,6 @@
int main()
{
printf("Hello World\n");
+ printf("Version:1.0");
return 0;
}
~/Documents/GithubTest$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: demo.c
no changes added to commit (use "git add" and/or "git commit -a")
~/Documents/GithubTest$ git add demo.c
~/Documents/GithubTest$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: demo.c
~/Documents/GithubTest$ git commit -m "Add Version"
[master 3b480dd] Add Version
1 file changed, 1 insertion(+)
好了,现在branch和master都作了修改,现在开始融合。
~/Documents/GithubTest$ git merge NewBranch
Auto-merging demo.c
CONFLICT (content): Merge conflict in demo.c
Automatic merge failed; fix conflicts and then commit the result.
你会发现有融合失败的提示automatic merge failed并且还有conflicts,ok,这就是我们要解决的另一个问题,代码融合时出现冲突怎么办?
执行指令cat demo.c查看问题
~/Documents/GithubTest$ cat demo.c
#include
int main()
{
printf("Hello World\n");
<<<<<<< HEAD
printf("Version:1.0");
=======
printf("A NewBranch was added!");
>>>>>>> NewBranch
return 0;
}
<<<<<<<表示master上改变的地方
>>>>>>>表示branch上改变的地方
=======表示master和branch的分割线
那面就进入代码中修改好了,想要的保留,不想要的删掉
$ cat demo.c
#include
int main()
{
printf("Hello World\n");
printf("Version:1.0");
printf("A NewBranch was added!");
return 0;
}
好的,接下来我们再提交一下
~/Documents/GithubTest$ git add demo.c
~/Documents/GithubTest$ git commit -m "Merge confilcts"
[master 3e508c3] Merge confilcts
ok! 然后再把NewBranch分支删掉吧。
~/Documents/GithubTest$ git branch -d NewBranch
Deleted branch NewBranch (was a1a7828).
高级
这篇文章的最后一节,我们来说些比较高级并且使用的技巧。
1.比对两个不同提交之间的差别
每次提交都有一个唯一id,查看所有提交和他们的id,可以使用 git log:
~/Documents/GithubTest$ git log
commit 3e508c3bff0ce6dd79d360f68bbb2dbfc3e4df7b
Merge: 3b480dd a1a7828
Author: Grand2015 <[email protected]>
Date: Wed Jul 20 19:19:27 2016 +0800
Merge confilcts
commit 3b480ddb802c4eaf86cf6252be1774b507859846
Author: Grand2015 <[email protected]>
Date: Wed Jul 20 18:57:29 2016 +0800
Add Version
commit a1a782894b7f3c944ffa21f34bbb54f723ac3097
Author: Grand2015 <[email protected]>
Date: Wed Jul 20 18:39:26 2016 +0800
New Branch
commit 6a143dcf25c67ca7d2c4609ef7745c178ed11133
Author: Grand2015 <[email protected]>
Date: Tue Jul 19 02:32:13 2016 -0700
First Commit
commit cea07c59d127590dee621b695c7dd169523b3bed
Author: Grand Li <[email protected]>
Date: Tue Jul 19 17:44:04 2016 +0800
Delete hello.txt
commit 7627f852cf143e49414067df499aa780d0bb78ff
Author: Grand2015 <[email protected]>
Date: Sun Jul 17 22:33:03 2016 +0800
new document
commit 3fa2685cefadd18fda59971fa9f5c30d157d66c5
Author: Grand Li <[email protected]>
Date: Sun Jul 17 21:49:12 2016 +0800
Initial commit
id 很长,但是你并不需要复制整个字符串,前一小部分就够了。
查看某一次提交更新了什么,使用 git show:
$ git show 3e508c3bff0ce6dd79d360f68bbb2dbfc3e4df7b
commit 3e508c3bff0ce6dd79d360f68bbb2dbfc3e4df7b
Merge: 3b480dd a1a7828
Author: Grand2015 <[email protected]>
Date: Wed Jul 20 19:19:27 2016 +0800
Merge confilcts
diff --cc demo.c
index 6d05ca1,a4ddd4e..eaf69b0
--- a/demo.c
+++ b/demo.c
@@@ -2,6 -2,6 +2,7 @@@
int main()
{
printf("Hello World\n");
+ printf("Version:1.0");
+ printf("A NewBranch was added!");
return 0;
}
查看两次提交的不同,可以使用git diff [commit-from]..[commit-to] 语法:
2.回滚某个文件到之前的版本
git 允许我们将某个特定的文件回滚到特定的提交,使用的也是 git checkout。
下面的例子,我们将demo.c回滚到最初的状态,需要指定回滚到哪个提交,以及文件的全路径。
$ git checkout 3e508c3bff0ce6dd79d360f68bbb2dbfc3e4df7b demo.c
3.回滚提交
如果你发现最新的一次提交完了加某个文件,你可以通过 git commit —amend来修复,它会把最新的提交打回暂存区,并尝试重新提交。
如果是更复杂的情况,比如不是最新的提交了。那你可以使用git revert。
最新的一次提交别名也叫HEAD。
$ git revert HEAD
其他提交可以使用id:
$ git revert 3e508c3bff0ce6dd79d360f68bbb2dbfc3e4df7b
混滚提交时,发生冲突是非常频繁的。当文件被后面的提交修改了以后,git不能正确回滚。
4.配置 .gitignore
大部分项目中,会有写文件,文件夹是我们不想提交的。为了防止一不小心提交,我们需要gitignore文件:
在项目根目录创建.gitignore文件
在文件中列出不需要提交的文件名,文件夹名,每个一行
.gitignore文件需要提交,就像普通文件一样
通常会被ignore的文件有:
log文件
task runner builds
node_modules等文件夹
IDEs生成的文件
个人笔记