天天看点

Git学习笔记

Git学习笔记

​​ Remote:远程仓库 Repository:本地仓库

​​ Workspace: 工作区 Index: 暂存区

安装Git

Windows

​ 在官网

下载安装程序

, 然后按默认选项安装即可。

Git学习笔记

​ 安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!

Git学习笔记

Linux

​ 系统版本:CentOS 7.3,x86_64 , root用户

Git学习笔记

​ 查看系统是否已安装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.

  1. 卸载已经安装的低版本的git:

    yum remove git

  2. 安装git依赖包
sudo yum groupinstall "Development Tools" 
sudo yum install -y curl-devel expat-devel gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel
           
  1. 依赖包安装完成后,需要找出并 下载最新版本的git ,,位于列表顶部的是最新版本,注意不要选择带有-rc的版本,因为它代表了一个候选发布版本。
    Git学习笔记
    选择最新的版本 ,使用wget下载:
wget https://github.com/git/git/archive/v2.15.1.tar.gz
           
  1. 安装git
#解压
tar -zxvf git.tar.gz 
#编译
cd git*   #进入git解压目录
make configure
./configure   --prefix=/usr/local/
make prefix=/usr/local/ all
make install
           
  1. 查看版本

    git --version

    , 如果显示的git版本还是v1.8或提示找不到git目录,执行命令:

    cp /usr/local/bin/git* /usr/bin/

    ,就可以了。
    Git学习笔记

设置Git

​ 设置你的一些个人信息,如你提交的姓名和电子邮件:

$ git config --global user.name 'shijianzhihu'
$ git config --global user.email '[email protected]'

#查看所有已配置的全局信息
$ 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

用来切换分支或恢复工作树文件。

<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之前多次执行。

Git学习笔记

git add file

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学习笔记

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学习笔记

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 <[email protected]>
Date:   Tue Feb 6 14:14:06 2018 +0800
    Revert "test"
    This reverts commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459.
commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459
Author: xxxxx <[email protected]>
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 <[email protected]>
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%)
           

参考文档

  1. Git 教程 ,廖雪峰
  2. Git远程操作详解 ,阮一峰
  3. Git忽略规则.gitignore梳理 ,散尽浮华
  4. git的reset和checkout的区别 ,chanjarster
  5. git add -A 和 git add . 的区别 ,PajamaCat
  6. git branch用法总结 ,KKK_Kevin
  7. Git自学之路(四) - gitbranch 分支 ,JunkChen-程开均
  8. Git中的upstream和downstream概述 ,易生一世
  9. “git rm” 和“rm”的区别 ,jfkidear
  10. git commit -m与git commit -am的区别
  11. Git的撤消操作 - 重置, 签出 和 撤消