0%

Git使用小结

Git -- The stupid content tracker. Linus Torvalds

使用git已经有一段时间了,从刚开始的陌生到慢慢熟悉

掌握基本的用法之后,会让人对开发、尤其是多人合作开发有了新的理解……甚至于平时写文档的时候都想用了

脑海中出现这么个画面

毕业论文.doc
毕业论文修改版.doc
毕业论文完结版.doc
毕业论文最终版.doc
毕业论文再也不改了版.doc

这时候要是有git在,一个文件就足够了,多次保存之后commit好即可

把平时常用的一些操作做一下整理。

开始一个项目

一般开始项目有2种情况:复制一个现成的git项目或者创建新项目

复制:

1
$ git clone [source] [destination]

[source]里面是项目的位置,可以是本地/服务器上的某个目录,也可以是远程库(例如github)中项目的地址(HTTPS或者SSH地址)

[destination]是拷到本地存放的位置,不加就是默认当前目录下

事实上……这个命令就是复制粘贴,尤其是如果是从本地clone到本地的时候。当然,只有git项目可以clone,对一个普通的文件夹调用clone命令还是不行的

创建:

1
$ git init [name]

[name]是项目的名字,不加就是把当前目录初始化成git库

初始化之后,目录下面会多出一个隐藏的.git文件夹,里面保存了git库需要的各种信息文件

示例

就拿一开始的论文脑洞来举例吧,我这里是装好git之后,配好运行环境,然后就可以在cmd里面操作git了

命令行到桌面,然后:

1
2
C:\Users\lenovo\Desktop>git init test
Initialized empty Git repository in C:/Users/lenovo/Desktop/test/.git/

clone一下试试

1
2
3
4
C:\Users\lenovo\Desktop>git clone test lunwen
Cloning into 'lunwen'...
warning: You appear to have cloned an empty repository.
done.

然后就可以开始工作啦,接下来的操作都会在这个名字叫做lunwen的目录(库)下面完成

开始工作

1
$ git status

这条命令是显示当前库中(其实就是当前目录中)需要被跟踪的文件的状态。

文件的状态有三种,一开始新文件的状态是“Untracked”或者“Changes not staged for commit”,表示是刚创建的新文件还没有被git所追踪,或者是库中原本已有的文件发生了修改还没有被git所追踪,添加跟踪需要用到下面的这条add指令:

1
2
$ git add [file]
$ git add -A

-A 是默认把当前目录下所有需要追踪的文件都添加追踪,或者手动输入文件名进行各个文件的单独追踪

1
$ git reset [file]

什么参数都不带表示把刚刚add上去的文件取消追踪,或者手动输入文件名进行各个文件的单独取消

1
$ git diff

对库中原本已有的修改文件进行新旧版本对比,显示文件的区别

1
$ git diff --staged

跟上一条指令类似,区别是这个是对已add进库中的文件进行新旧版本对比

1
$ git commit -m "[descriptive message]"

当把所有文件都add进来之后,文件的状态变成了“Changes to be committed”,表示所有修改都已经被追踪,等待提交

然后就需要上面这条命令,descriptive message是对本次提交的描述,如果不加-m和描述,git会打开一个编辑器要求输入描述

示例

现在库里面是空的,新建个文本文档lunwen.txt,里面写上test1,然后查看一下状态:

lunwen.txt

1
test1
1
2
3
4
5
6
7
8
9
10
11
C:\Users\lenovo\Desktop\lunwen>git status
On branch master

Initial commit

Untracked files:
(use "git add <file>..." to include in what will be committed)

lunwen.txt

nothing added to commit but untracked files present (use "git add" to track)

显示新的文件还没有被追踪过,先提交一下第一个版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
C:\Users\lenovo\Desktop\lunwen>git add -A

C:\Users\lenovo\Desktop\lunwen>git status
On branch master

Initial commit

Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: lunwen.txt


C:\Users\lenovo\Desktop\lunwen>git commit -m "first"
[master (root-commit) 2561997] first
1 file changed, 1 insertion(+)
create mode 100644 lunwen.txt

C:\Users\lenovo\Desktop\lunwen>git status
On branch master
nothing to commit, working directory clean

提交完成,接下来对lunwen.txt稍微做点修改,然后再创建个新的文件test.txt:

lunwen.txt

1
2
test2
test3

test.txt

1
2
test2
test3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
C:\Users\lenovo\Desktop\lunwen>git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: lunwen.txt

Untracked files:
(use "git add <file>..." to include in what will be committed)

test.txt

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

status里面清楚地显示了库中文件的改变情况即:lunwen.txt是已被追踪但是修改了的,test.txt是还没有被追踪的,接下来试一下diff这个命令:

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
C:\Users\lenovo\Desktop\lunwen>git diff
diff --git a/lunwen.txt b/lunwen.txt
index f079749..66bb064 100644
--- a/lunwen.txt
+++ b/lunwen.txt
@@ -1 +1,2 @@
-test1
\ No newline at end of file
+test2
+test3
\ No newline at end of file

C:\Users\lenovo\Desktop\lunwen>git add -A

C:\Users\lenovo\Desktop\lunwen>git diff --staged
diff --git a/lunwen.txt b/lunwen.txt
index f079749..66bb064 100644
--- a/lunwen.txt
+++ b/lunwen.txt
@@ -1 +1,2 @@
-test1
\ No newline at end of file
+test2
+test3
\ No newline at end of file
diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..66bb064
--- /dev/null
+++ b/test.txt
@@ -0,0 +1,2 @@
+test2
+test3
\ No newline at end of file

C:\Users\lenovo\Desktop\lunwen>git commit -m "second"
[master 50e143b] second
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 test.txt

C:\Users\lenovo\Desktop\lunwen>git status
On branch master
nothing to commit, working directory clean

diff显示的只有lunwen.txt这个文件的变化,因为这个文件本来就在库里面,也是一直都被追踪着的。a/显示的是旧版本,b/显示的是新版本

diff –staged显示的则是所有被add过的文件的差异,test.txt由于是新创建的,所有没有旧版本

删除文件

1
$ git rm [file]

删除文件以及所有信息

1
$ git rm --cached [file]

删除文件的追踪信息,但是文件仍然保留

1
$ git mv [file-original] [file-renamed]

重命名文件

版本保存和恢复

1
$ git log

显示所有commit的记录

重点来了,git保存了库中所有文件完整的演变过程,以每一次commit作为一个保存点,如果发生问题,可以直接回滚到之前的任何一个版本,而需要的指令则是上面用过的这一条:

1
$ git reset

reset的作用是使目录会退到上一次的状态,在前面用来取消掉add,其实它的完整用法是这样的:

1
$ git reset [--hard|soft|mixed|merge|keep] [<commit>或HEAD]

reset这个命令比较复杂,可以戳这个了解更详细的实例


先整体明确一下整个git的结构:

首先是当前正在操作的内容,就是现在正在修改/编辑的文件,这一块叫做“Working Directory

通过add之后,追踪的内容被保存到了“Git Index”里面,这一块可以看成是当前目录和版本库之间的暂存区

最后再用commit写上标注,把index里面更新的内容修改到“GIT Directory”即版本库里面


好,那么回到reset

commit字段用于选择哪一个版本,如果不加,则默认为HEAD,代表离当前最近的一个版本,也就是上一次最近的commit

简单地说一下常用的几个:

–hard 是强制将当前所做的所有修改都清除掉,HEAD、index和working directory全部恢复到目标commit

–mixed 是不加参数时的默认选择,将HEAD和index都恢复到目标commit,但是保留目录下面修改了的文件。即此时只要add一下,再commit一下就能把当前修改的版本保存为下一个版本

–soft 程度更弱,只将HEAD指向commit,index和当前的工作文件都保持不变,因此自目标commit以来的所有改变都会显示为“Changes to be committed”。此时只要commit一下,就能将当前修改的版本保存为下一个版本

版本暂存

这个功能用来遇到突发状况需要对最后一次的commit进行操作,然后又不想提交当前修改的时候用

1
$ git stash

将当前工作文件保存进栈,然后把工作区恢复到上一次的commit

然后这样的操作还可以多次进行,每次的暂存就都会被压进栈

1
$ git stash list

显示栈中保存的所有暂存信息

1
$ git stash pop

弹出栈顶的保存信息,就是把栈顶的保存信息恢复到工作区

1
$ git stash drop

不恢复,直接删除栈顶的保存信息

1
$ git stash clean

清除栈中的所有信息

远程操作

刚刚的都是针对本地库的操作,如果不需要上传到他地方,这些内容就足够了,而git的一大强大之处就是能方便多人协作,因此远程功能是少不了的

1
$ git remote [-v]

不带选项时,remote命令会列出所有远程主机的名字

-v 则会列出远程主机的地址

1
$ git remote add <name><url>

用于添加一台主机

1
$ git remote rm <name>

用于删除一台主机

1
$ git remote <old-name><new-name>

重命名一台主机

示例

一开始我创建的lunwen库是从test库clone过来的,所以查看lunwen库的远程主机情况就是这样的:

1
2
3
4
5
6
C:\Users\lenovo\Desktop\lunwen>git remote
origin

C:\Users\lenovo\Desktop\lunwen>git remote -v
origin C:/Users/lenovo/Desktop/test (fetch)
origin C:/Users/lenovo/Desktop/test (push)

默认clone过来的主机名是origin

分支控制

这个也是git中相当重要的一个内容

一个库中可以有多个分支,可以用来更方便地管理整个版本信息

1
$ git branch [-a|r]

不加参数时,默认列出本地库中所有的分支信息,并在当前分支前面加*号

-r 是列出远程库

-a 列出本地和远程库

1
$ git branch [branch-name]

创建一个新的分支

1
$ git checkout [branch-name]

切换到某个分支上,如果分支不存在,则会首先创建新分支再切换过去

切换到分支上时,当前工作目录下面的所有文件都会直接变掉(第一次用的时候觉得这个很神奇)

1
$ git merge [branch]

将目标分支合并到当前分支里面来

1
$ git branch -m [oldname] [newname]

分支重命名

1
$ git branch -d [branch-name]

删除某一个特定的分支

1
$ git fetch <name>

从某一台远程主机上获取所有的更新

远程分支操作

如果 fork 了一个别人的项目,然后对方更新了库,想要保持自己的库跟对方一直,则需要先把源库 fetch 下来,跟自己的 merge 之后,再 push 回自己的库上。

1
$ git remote add upstream xxx.git

添加 upstream 的远程库信息。

1
$ git fetch upstream

fetch upstream 源的新版本到本地

1
$ git merge upstream/master

将 upstream 库的 master 分支跟当前分支合并。

之后再 push 回去就行了。