一、git init搭建仓库

通过git init命令把这个目录变成Git可以管理的仓库

这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

二、git add添加

所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等。

把一个文件放到Git仓库只需要两步。

第一步,用命令git add告诉Git,把文件添加到仓库:

1
$ git add readme.txt

三、git commit提交

第二步,用命令git commit告诉Git,把文件提交到仓库:

1
$ git commit -m "wrote a readme file"

git commit命令执行成功后会告诉你:

1 file changed:1个文件被改动(我们新添加的readme.txt文件);

2 insertions:插入了两行内容(readme.txt有两行内容)。

添加文件到Git仓库,分两步:

  1. 使用命令git add ,注意,可反复多次使用,添加多个文件;
  2. 使用命令git commit -m ,完成。

四、git status查看状态

1
2
3
4
5
6
7
8
9
$ git status
On branch 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: readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

git status命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,readme.txt被修改过了,但还没有准备提交的修改。

五、git diff查看文件具体修改内容

查看某文件修改的具体内容

1
2
3
4
5
6
7
8
9
$ git diff readme.txt 
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
Git is free software.
  • 要随时掌握工作区的状态,使用git status命令。
  • 如果git status告诉你有文件被修改过,用git diff可以查看修改内容。

六、git log查看日志,历史版本

查看修改历史

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Liao
Date: Fri May 18 21:06:15 2018 +0800

append GPL //修改名

commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao
Date: Fri May 18 21:03:36 2018 +0800

add distributed //修改名

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao
Date: Fri May 18 20:59:18 2018 +0800

wrote a readme file //修改名

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

1
2
3
4
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file

1094adb7b9b3807259d8cb349e7df1d4d6477073commit id()版本号,通过SHA1计算。

七、git reset 回退版本

1
2
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed

git log 查看版本库的现在状态,发现最新版已经看不到了,已经回退

如果想回到原来的最新版,办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个append GPLcommit id1094adb...,于是就可以指定回到未来的某个版本:

1
2
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL

1
2
3
4
5
6
7
8
9
┌────┐
│HEAD│
└────┘

└──> ○ append GPL

○ add distributed

○ wrote a readme file

改为指向add distributed

1
2
3
4
5
6
7
8
9
┌────┐
│HEAD│
└────┘

│ ○ append GPL
│ │
└──> ○ add distributed

○ wrote a readme file

然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

八、git reflog记录每次命令

可以通过这个命令查看历史操作,可以查看commit id,方便

1
2
3
4
5
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file

九、工作区与暂存区

工作区(Working Directory):当前电脑创建的git管理的仓库。

版本区(Repository):

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

分支和HEAD的概念我们以后再讲。

前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改

修改文件,并add添加到暂存区后,状态变为

git-stage
git-stage

commit后,版本库变为下面图,暂存区没有任何内容。

git-stage-after-commit
git-stage-after-commit

十、git checkout丢弃工作区的修改

1
$ git checkout -- readme.txt

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:

  • 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

  • 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态

总之,就是让这个文件回到最近一次git commitgit add时的状态。

git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令

十一、git reset HEAD 撤销暂存区的内容,重新放回到工作区

1
2
3
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt

git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

再用git status查看一下,现在暂存区是干净的,工作区有修改:

1
2
3
4
5
$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

小结

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD ,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,git reset xxxx,不过前提是没有推送到远程库。

十二、删除文件的解决办法。

如果先添加一个文件,并提交,然后把该文件给删了。

1
2
3
$ git add test.txt
$ git commit -m "add test.txt"
$ rm test.txt

这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

1
2
3
4
5
6
7
8
9
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

deleted: test.txt

no changes added to commit (use "git add" and/or "git commit -a")

现在你有两个选择,1、一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit

1
2
$ git rm test.txt
$ git commit -m "remove test.txt"

现在,文件就从版本库中被删除了。

2、另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

1
$ git checkout -- test.txt

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

小结

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

十三、设置SSH Key

第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

1
$ ssh-keygen -t rsa -C "youremail@example.com"

你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可

如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:

然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

点“Add Key”,你就应该看到已经添加的Key:

十四、添加远程库

现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。

首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:

目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:

1
$ git remote add origin git@github.com:xifujiang/learngit.git

请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

下一步,就可以把本地库的所有内容推送到远程库上:

1
$ git push -u origin master

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令

从现在起,只要本地作了提交,就可以通过命令:

1
$ git push origin master

把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!

小结

要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git

关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改。

十五、克隆地址

1
git clone 地址

小结

要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。

Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。

分支管理

Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch

切换分支:git checkout 或者git switch

创建+切换分支:git checkout -b 或者git switch -c

合并某分支到当前分支:git merge

删除分支:git branch -d

解决冲突

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

git log --graph命令可以看到分支合并图。

推送分支

推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:

1
$ git push origin master

如果要推送其他分支,比如dev,就改成:

1
$ git push origin dev

抓取分支

多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin 推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

小结

  • 查看远程库信息,使用git remote -v
  • 本地新建的分支如果不推送到远程,对其他人就是不可见的;
  • 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
  • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
  • 建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
  • 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。