Git学习笔记
Remote:远程仓库 Repository:本地仓库
Workspace: 工作区 Index: 暂存区
安装Git
Windows
在官网下载安装程序, 然后按默认选项安装即可。
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
Linux
系统版本:CentOS 7.3,x86_64 , root用户
查看系统是否已安装git :git --version
, 如果提示bash: /usr/bin/git: No such file or directory
,则说明系统中还没有安装git; 如果显示了git 版本号,则证明系统中已经安装了git。
Redhat系的Linux发行版,安装git最便捷的方法是直接使用yum 安装:yum install git
, 但是经过测试,CentOS 7.3 通过yum 安装的Git 版本默认为v1.8.3 , 而目前git最新版本为v2.16.0,低版本的git存在安全漏洞,所以不建议使用yum安装,推荐使用源码安装git.
-
卸载已经安装的低版本的git:
yum remove git
-
安装git依赖包
sudo yum groupinstall "Development Tools"
sudo yum install -y curl-devel expat-devel gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel
-
依赖包安装完成后,需要找出并 下载最新版本的git,,位于列表顶部的是最新版本,注意不要选择带有-rc的版本,因为它代表了一个候选发布版本。
选择最新的版本 ,使用wget下载:
wget https://github.com/git/git/archive/v2.15.1.tar.gz
- 安装git
#解压
tar -zxvf git.tar.gz
#编译
cd git* #进入git解压目录
make configure
./configure --prefix=/usr/local/
make prefix=/usr/local/ all
make install
-
查看版本
git --version
, 如果显示的git版本还是v1.8或提示找不到git目录,执行命令:cp /usr/local/bin/git* /usr/bin/
,就可以了。
设置Git
设置你的一些个人信息,如你提交的姓名和电子邮件:
$ git config --global user.name 'shijianzhihu'
$ git config --global user.email 'shijianzhihu@foxmail.com'
#查看所有已配置的全局信息
$ git config --list
Git 常用命令
以下所有的命令说明都基于Git v2.13.0,不同版本的Git ,命令可能会有所区别!
$ git --version #查看git 版本
$ git [command] --help #查看command用户手册
git clone
git clone
用来从从远程主机克隆一个版本库,语法为:git clone <版本库地址>
,该命令会在本地主机生成一个与远程主机版本库同名的目录,如果要指定不同的目录名,可以将目录名作为git clone
命令的第二个参数:
git clone <版本库的网址> <本地目录名>
git remote
Git要求每个远程主机都必须指定一个主机名。git remote
命令就用于管理主机名.
#查看所有远程主机名
$ git remote
origin
#查看远程主机地址
$ git remote -v
origin https://github.com/naver/ngrinder.git (fetch)
origin https://github.com/naver/ngrinder.git (push)
git fetch
一旦远程主机的版本库有了更新,需要将这些更新取回本地,这时就要用到git fetch
命令.
#将远程主机的所有分支的更新取回本地
$ git fetch <远程主机名>
如:git fetch origin
#取回指定分支的更新
$ git fetch <远程主机名> <分支名>
如:git fetch origin dev
git branch
git branch
用来显示、创建或删除分支。
OPTIONS
# 不带参数时,会列出所有本地分支,并且在当前分支前加"*";
$ git branch
dev
master
* test
<newBranch>
#新建本地分支,但不会自动切换到该分支
$ git branch bug-fixed
<-r, --remotes>
#列出所有远程分支
$ git branch -r
origin/bug-fixed
origin/b2b
origin/beta
origin/collections
origin/chart
<-a --all>
#列出所有本地分支和远程分支
$ git branch -a
<-m ,--move | -M>
#移动/重命名一个分支和相应的历史信息
#<-M>:强制move/rename
$ git branch -m bug-fixed bug-fixed2
<-d, --delete | -D>
#删除本地分支,不能删除当前checkout的分支;
#如果要删除的分支有未合并的内容,则会报错:'the branch XXX is not fully merged',解决办法:使用'-D' 强制删除;
$ git branch -D 'bug-fixed'
#补充:利用shell管道命令实现批量删除分支
$ git branch | grep 'branchName' | xargs branch -D
<--set-upstream-to origin/branchname localBranchname>
注意,<–set-upstream-to> 在已经替代了 <–set-upstream>,二者跟随的参数需要对调一下位置;
#设置本地分支与远程分支关联,如果没有关联的情况下,git pull 会提示如下信息:
$ git push origin test
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> test
设置远程关联分支的方法,如下
$ git branch --set-upstream-to origin/test test
Branch test set up to track remote branch test from origin.
$ git pull
Already up-to-date.
<-v, --verbose | -vv>
#<-v>:查看本地分支最后的修改信息,当前分支名称前会带有'*'
$ git branch -av
bug-fixed3 fdcbdf7 add bug -fixed2
dev 1599863 test
* master 9faecaf [ahead 1] update test.txt #[ahead 1]表示本地分支比远程分支领先一个commit
test 1599863 test
remotes/origin/HEAD -> origin/master
remotes/origin/bug-fixed3 fdcbdf7 add bug -fixed2
#<-vv>:在git branch -v的基础上,显示本地分支的远程关联分支(upstream branch);
#查看远程关联分支,可以使用git config --list命令
$ git branch -vv
bug-fixed3 fdcbdf7 add bug -fixed2
dev 1599863 test
* master 9faecaf [origin/master: ahead 1] update test.txt
test 1599863 test
git checkout
git checkout
用来切换分支或恢复工作树文件。
OPTIONS
<branch>
#切换当前分支到本地已有分支
$ git checkout dev
Switched to branch 'dev'
#新建本地分支,并切换到该分支
$ git checkout -b five
Switched to a new branch 'five'
#新建本地分支,并切换到该分支,而且关联远程分支
$ git checkout -b six --track origin/dev
Switched to a new branch 'six'
Branch six set up to track remote branch dev from origin.
第三条命令相当于以下命令的合集:
$ git branch
$ git checkout six
$ git branch --set-upstream-to origin/dev six
<-- fileNmae> #'--' 和'fileName'之间有空格!
#将指定文件在工作区的修改撤销到最近一次git add 或git commit时的内容(只对tracked file有效)
比如下面的两个例子:
$ cat test.txt
one
$ git add . -v
add 'test.txt'
$ git commit -m 'update test.txt'
[test a2d987d] update test.txt
1 file changed, 1 insertion(+)
$ vim test.txt
$ cat test.txt
one
two
$ git checkout -- test.txt #注意空格,否则报错
$ cat test.txt
one
$ git status
nothing to commit, working tree clean
****************************************
$ cat test.txt
one
two
$ vim test.txt
$ cat test.txt
one
two
three
$ vim test.txt
$ cat test.txt
one
two
three
four
$ git checkout -- test.txt
$ cat test.txt
one
two
补充:
$ git checkout -- stu.txt test.txt
$ git checkout -- *
$ git checkout -- *.txt
# git checkout -- 不加文件名来查看当前工作区修改了哪些文件
$ git checkout --
M blog.txt
D start.txt
Your branch is up-to-date with 'origin/sprider'.
# 取文件在commit_id时的版本
$ git checkout 1599863 fileName
git status
git status
用来显示工作树状态, git会非常友好的提示用户下一步的操作,请看下面的例子:
$ git status
On branch test
Your branch is up-to-date with 'origin/test'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
blog.txt
nothing added to commit but untracked files present (use "git add" to track)
$ git add blog.txt
$ git status
#
On branch test
Your branch is up-to-date with 'origin/test'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: blog.txt
$ git commit -m 'add blog.txt'
$ git status
On branch test
Your branch is ahead of 'origin/test' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
git add
git add
命令主要用于把我们要提交的文件的信息添加到索引库(Index)中。当我们使用git commit
时,git将依据索引库中的内容来进行文件的提交。git add
命令可以在commit之前多次执行。
COMMON OPTIONS
<pathspec>
#可以使用'*'模糊匹配路径
$ git add *.c
# 路径可以到目录层级
$ git add test/
<-v,--verbose>
#显示本次added的文件名
$ git add -v file3.txt
add 'file3.txt'
$ git add -v study/
add 'study/study.txt'
<-f, --force>
#允许添加被忽略的文件
#关于git忽略文件的介绍,见下一小节
$ git add -f commonVars.pyc
<-u, --update>
#add被修改(modified)和被删除(deleted)文件,不包含新文件(new,untracked file)
$ git add -uv
<-A, --all>
#add所有变化,包括被修改(modified)、被删除(deleted)文件和包括新文件(new)
$ git add -Afv
git add -A | git add -u |git add .
-
git add
.:他会监控工作区的状态树,使用它会把工作时的所有变化提交到暂存区,包括modified、new和deleted ; -
git add -u
:他仅监控已经被add的文件(即tracked file),他会将被修改的文件提交到暂存区。add -u 不会提交new(untracked file); -
git add -A
:等同于 git add .;
注意,在Git v1.x.x版本,git add . 不能添加deleted文件
git 特殊文件
有些时候,我们必须或被必须把某些文件放到Git的工作目录中,但是又不能提交它们。这就导致每次git status
都会显示Untracked files ... 。为了解决这个文件,可以在Git工作区的根目录下创建一个特殊的.gitignore文件,这个文件的作用就是告诉Git哪些文件不需要添加到版本管理中。实际项目中,很多文件都是不需要版本管理的,比如Python的.pyc文件和一些包含密码的配置文件等等。这个文件的内容是一些规则,Git会根据这些规则来判断是否将文件添加到版本控制中。
Git bash创建".gitignore" : vim .gitignore
, GitHub中已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
常用的规则有:
1. /mtk/ #过滤整个文件夹
2. *.zip #过滤所有.zip文件
3. /mtk/do.c #过滤某个具体文件
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
git commit
git commit
记录对存储库的更改信息,此命令默认提交的是暂存区的内容,也就是 Changes to be committed 中的文件,最常用的参数是<-m>,用来添加本次提交的相关信息,如:git commit -m 'update file'
如果使用了<-a>参数,则除了将暂存区里的文件提交外,还提交 Changes but not updated 中的文件。通常我们提交git的时候都是通过以下三大步:
git add .
git commit -m "some str"
git push
实际上,你只需要两条命令就够了,除非有新的文件(untracked file)要被添加进去。
git commit -am "some str"
git push
git pull
git pull命令的作用是,取回远程主机指定分支的更新,再与本地的指定分支合并。实质上等同于先做git fetch,再做git merge.
#完整格式
$ git pull <远程主机名> <远程分支名>:<本地分支名>
#比如:取回origin主机的bugifx分支与本地的bugfix2分支合并,需要写成下面这样
git pull origin bugfix:bugfix2
#如果远程分支是与当前分支合并,则本地分支名可以省略
$ git pull origin dev
#如果当前分支与远程分支存在关联关系,远程分支名也可以省略
$ git pull origin
#如果当前分支只有一个追踪分支,则远程主机名也可以省略
$ git pull
#上面命令表示为:当前分支自动与唯一一个追踪分支进行合并
**********************************************************
#如果合并需要使用rebase模式,可以加上'-- rebase'选项
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>
**********************************************************
#如果远程主机删除了某个分支,默认情况下,git pull 不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致git pull不知不觉删除了本地分支。但是,你可以改变这个行为,加上参数 -p 就会在本地删除远程已经删除的分支。
$ git pull -p
# 等同于下面的命令
$ git fetch --prune origin
$ git fetch -p
git:查看追踪分支
#这个信息实际是存在config 文件中的,可以用下面的命令来查看xxx分支的信息
$ git config -l |grep 'branch.xxx'
# git v2.15+版本,可以使用以下命令查看追踪分支信息
$ git branch -vv
git:手动设置追踪分支
#方法一
$ git branch --set-upsteam XXX origin/xxxx
#方法二
#删掉本地分支,然后重新创建此分支,并且指定其 track 信息
$ git checkout -b XXX --track origin/xxxx
git push
git push
命令用于将本地分支的更新,推送到远程主机。它的命令格式与git pull命令相仿但不要搞混了,其实很容易理解区分的.
#完整格式
$ git push <远程主机名> <本地分支名>:<远程分支名>
#如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名)
#如果该远程分支不存在,则会被新建。
$ git push origin dev
#如果省略本地分支名,则表示删除指定的远程分支,因为这表示推送一个空的本地分支到远程分支。
$ git push origin :dev
#注意origin 和冒号之间需要有空格
#如果当前分支与远程分支存在关联关系,远程分支名也可以省略
$ git push origin
如果当前分支与远程分支没有追踪关系,则会报错:
fatal: The current branch bug-fixed2 has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin bug-fixed2
#如果当前分支只有一个追踪分支,则远程主机名也可以省略
$ git push
git log | git reflog
git log 用来查看当前分支的提交历史,不包含已经被撤销的commit:
$ git log
commit 150089329868f665cfd6a1f1ac301d31ff232c75 (HEAD -> sprider)
Author: xxxxx <shijianzhihu@foxmail.com>
Date: Tue Feb 6 14:14:06 2018 +0800
Revert "test"
This reverts commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459.
commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459
Author: xxxxx <shijianzhihu@foxmail.com>
Date: Tue Feb 6 14:13:54 2018 +0800
test
如果嫌输出信息太多,以试试加上--oneline参数:
$ git log --oneline
1500893 (HEAD -> sprider) Revert "test"
5e2d6fc test
a0eb8b5 update blog.txt
ec9734c Revert "start test"
1616640 Revert "blog"
显示每次提交的内容差异可以使用< -p> 参数,<-n>则为仅显示最近的n次历史:
$ git log -p -1
commit 150089329868f665cfd6a1f1ac301d31ff232c75 (HEAD -> sprider)
Author: xxxxx <shijianzhihu@foxmail.com>
Date: Tue Feb 6 14:14:06 2018 +0800
Revert "test"
This reverts commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459.
diff --git a/blog b/blog
index 40a3b4a..9daeafb 100644
--- a/blog
+++ b/blog
@@ -1 +1 @@
-test111
+test
git reflog 用来显示整个本地仓储的commit, 包括所有branch的commit, 甚至包括已经撤销的commit, 只要HEAD发生了变化(如checkout branch, pull, commit等), 就会在reflog里面看得到。
$ git reflog
1500893 (HEAD -> sprider) HEAD@{0}: checkout: moving from six to sprider
02cffe0 (six) HEAD@{1}: commit: branch six
1599863 (origin/dev, five) HEAD@{2}: checkout: moving from sprider to six
1500893 (HEAD -> sprider) HEAD@{3}: revert: Revert "test"
5e2d6fc HEAD@{4}: commit: test
git revert | git reset
git revert
用来回滚一些现有的提交, 但并不是从项目历史中移除这个commit,旧的commit还是保留在历史项目里面的,而git reset 则会删除旧的commit, 这样做的好处是防止了项目丢失历史。
用法: git revert <commit-id>
$ git log --oneline | head -n 1
a0eb8b5 update blog.txt
$ git revert HEAD
[sprider 60d4654] Revert "update blog.txt"
1 file changed, 1 insertion(+), 2 deletions(-)
$ git log --oneline | head -n 2
60d4654 Revert "update blog.txt"
a0eb8b5 update blog.txt
git reset <--hard|soft|mixed|merge|keep> commit 也是常用的版本回滚命令,其中比较重要的参数是mode,也就是 --hard、--soft、--mixed。。。比较常见的是--hard和--soft;
--hard是指完全重设,会把回退到某版本之后的修改全部删除,
--soft这是个回退解体,让版本库回退到某个版本,这个版本之后的修改全部存在缓存区,这个时候在commit的话,又会把会退的部分重新加载到最新版本中;
git diff
git diff
用于比较两次修改之间的差异。
- 比较工作区与暂存区
git diff 不加参数即默认比较工作区与暂存区
$ git diff
diff --git a/b2.txt b/b2.txt
index be738a5..2ffe5d8 100644
--- a/b2.txt
+++ b/b2.txt
@@ -1,2 +1,2 @@
test1
-test222
+22dsada2
- 比较暂存区与最新本地版本库
git diff --cached
- 比较工作区与最新本地版本库
git diff HEAD
- 比较工作区与指定commit-id的差异
git diff commit-id
- 比较暂存区与指定commit-id的差异
git diff --cached commit-id
- 比较两个commit-id之间的差异
git diff commit-id commit-id
git stash
git stash 用来备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。
git stash list 显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。
git stash clear 清空Git栈.
git stash pop 从Git栈中读取最近一次stash的内容,恢复工作区的相关内容。
两种恢复方法:
- 用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
- 用git stash pop,恢复的同时把stash内容也删了;
可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
git stash apply stash@{0}
git rm
git rm
用于从从工作树和暂存区中删除文件,他作用的对象只能是tracked files .
它的作用和git add
类似,可以理解为一个是添加一个是修改。git rm
要和git commit
配合使用,才真正能起到删除的作用。
$ git rm test.txt stu.txt
rm 'stu.txt'
rm 'test.txt'
$ git status
On branch test
Your branch is up-to-date with 'origin/test'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: stu.txt
deleted: test.txt
$ git commit -m 'delete two files'
[test ccd7143] delete two files
2 files changed, 4 deletions(-)
delete mode 100644 stu.txt
delete mode 100644 test.txt
$ git status
On branch test
Your branch is ahead of 'origin/test' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
#删除文件夹,-r表示递归删除,-f表示强制删除
$ git rm -rf qt/
rm 'qt/file.txt'
$ git rm -f rainbow.txt #不能对untracked file使用
fatal: pathspec 'rainbow.txt' did not match any files
git rm 和 rm 的区别
通过上面简单的介绍,我们发现git rm
和 shell 命令rm
非常相似,我们是否可以不使用git rm
,而是直接rm
后,然后再git add/commit
,这样是否可以呢? 答案当然是可以的。
使用git rm
来删除文件,git同时会将操作日历记录下来,git log
就可以看到;而使用rm
来删除文件,git并不会记录,这也是十分易于理解的。直观的来讲,git rm
删除过的文件,执行 git commit -m "abc"
提交时,会自动将删除该文件的操作提交上去;而对于用 rm
命令直接删除的文件,执行 git commit -m "abc"
提交时,则不会将删除该文件的操作提交上去。不过不要紧,即使你已经通过 rm 将某个文件删除掉了,也可以再通过 git rm
命令重新将该文件从 git 的记录中删除掉,这样的话,在执行 git commit -am "abc"
后,也能将这个删除操作提交上去。(git commit -am
写成git commit -ma
会报错)
一般说来,在git目录下删除文件时,可以选择以下两种方式:
- git rm + git commit -m 'text'
- rm + git commit -am 'text'
git mv
git mv
用来移动或重命名文件、目录或符号链接。
$ git mv b1.txt b2.txt
$ git mv rainbow.txt sprider/
$ git status
On branch sprider
Your branch is ahead of 'origin/sprider' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: b1.txt -> b2.txt
renamed: rainbow.txt -> sprider/rainbow.txt
$ git commit -m 'rename and move'
[sprider b08e44d] rename and move
2 files changed, 0 insertions(+), 0 deletions(-)
rename b1.txt => b2.txt (100%)
rename rainbow.txt => sprider/rainbow.txt (100%)
参考文档
-
Git 教程,廖雪峰
-
Git远程操作详解,阮一峰
-
Git忽略规则.gitignore梳理 ,散尽浮华
-
git的reset和checkout的区别,chanjarster
-
git add -A 和 git add . 的区别 ,PajamaCat
-
git branch用法总结 ,KKK_Kevin
-
Git自学之路(四) - gitbranch 分支,JunkChen-程开均
-
“git rm” 和“rm”的区别,jfkidear