0%

git

1. Git是什么

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。Git原来是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

1.1 Git 与 SVN 区别

Git 不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等。如果你是一个具有使用 SVN 背景的人,你需要做一定的思想转换,来适应 Git 提供的一些概念和特征。

GitSVN区别点:

  • 1、Git是分布式的,SVN不是:这是Git和其它非分布式的版本控制系统,

  • 2、Git把内容按元数据方式存储,而SVN是按文件:所有的资源控制系统都是把文件的元信息隐藏在一个类似 .svn、.cvs等的文件夹里。

  • 3、Git分支和SVN的分支不同:分支在 SVN中一点都不特别,其实它就是版本库中的另外一个目录。

  • 4、Git没有一个全局的版本号,而SVN有:目前为止这是跟SVN相比Git缺少的最大的一个特征。

  • 5、Git的内容完整性要优于SVNGit的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

2. Git安装

2.1 Linux下的Git

Git 的工作需要调用curl,zlib,openssl,expat,libiconv等库的代码,所以需要先安装这些依赖工具。 在有yum的系统上centOS或者有apt-get的系统上(比如 Debian 体系),可以用下面的命令安装:

2.1.1 ubuntu安装
1
2
3
4
5
6
7
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
libz-dev libssl-dev

$ apt-get install git

$ git --version
git version 1.8.1.2
2.1.2 centOS安装
1
2
3
4
5
6
7
$ yum install curl-devel expat-devel gettext-devel \
openssl-devel zlib-devel

$ yum -y install git-core

$ git --version
git version 1.7.1

2.2 windows下的Git

在 Windows平台上安装 Git同样轻松,找到官网下载链接,点击下一步直接安装即可。

2.3 Git配置

Git 提供了一个叫做git config的工具,专门用来配置或读取相应的工作环境变量。这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:

  • /etc/gitconfig文件:系统中对所有用户都普遍适用的配置。若使用git config时用 --system选项,读写的就是这个文件。
  • ~/.gitconfig文件:用户目录下的配置文件只适用于该用户。若使用git config时用 --global选项,读写的就是这个文件。
  • 当前项目的Git目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config里的配置会覆盖 /etc/gitconfig中的同名变量。

在 Windows 系统上,Git 会找寻用户主目录下的 .git/config文件。主目录即 $HOME 变量指定的目录,一般都是 C:\Documents and Settings\$USER。

此外,Git 还会尝试找寻 /etc/gitconfig文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。

2.3.1 用户信息

为了方便后续Git能跟踪到谁做了修改,我们需要设置对应的用户名与邮箱地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ git config --global user.name "wuwenjie"
$ git config --global user.email 1229413537@qq.com

$ git config --list
diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
http.sslbackend=openssl
http.sslcainfo=D:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
core.autocrlf=true
core.fscache=true
core.symlinks=false
pull.rebase=false
credential.helper=manager-core
credential.https://dev.azure.com.usehttppath=true
init.defaultbranch=master
user.email=1229413537@qq.com
user.name=wuwenjie

git config 命令的 --global 参数,表示使用的这台机器上所有的 Git 仓库都会使用这个配置

2.3.2 git配置ssh

git是现在代码管理的一个常用工具,采用两种传输方式 httpsshSSH 比较安全可靠,也不需要每次都输入账号密码,所以我们在使用git时一般采用ssh。

windows版本:

  • windows打开Gitbash(linux打开终端)输入
    1
    $ ls -al ~/.ssh
    如果你看到一下输出,那么说明你已经有ssh秘钥 (以.pub结尾的文件)
    1
    2
    3
    4
    5
    6
    total 24
    drwxr-xr-x 1 Administrator 197121 0 Sep 23 15:25 .
    drwxr-xr-x 1 Administrator 197121 0 Sep 23 15:07 ..
    -rw-r--r-- 1 Administrator 197121 3389 Sep 23 15:07 id_rsa
    -rw-r--r-- 1 Administrator 197121 750 Sep 23 15:07 id_rsa.pub
    -rw-r--r-- 1 Administrator 197121 1458 Sep 23 15:25 ssh.ppk
  • 如果你不想用原来的秘钥或者没有秘钥的话,直接进行下一步生成ssh公钥秘钥

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ssh-keygen -t rsa -C 邮箱
    //如下:
    trluper@trluper-virtual-machine:~$ ssh-keygen -t rsa -C "1229413537@qq.com"
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/trluper/.ssh/id_rsa):
    Created directory '/home/trluper/.ssh'.
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/trluper/.ssh/id_rsa
    Your public key has been saved in /home/trluper/.ssh/id_rsa.pub
    The key fingerprint is:
    SHA256:1Cj60kKeZzc8eMn1G09kN65qxVQ4FhyiKwumBElPf6I 1229413537@qq.com
    The key's randomart image is:
    +---[RSA 3072]----+
    | . . ..o+ |
    |. + . o. .= . |
    | o . o..o.. . o |
    | . ..oo . . |
    | Eoo .S.. o o..|
    | .oo+.+oo . =...|
    | .= *.O + .. |
    | = o o . =. |
    | ..o.. |
    +----[SHA256]-----+

  • 将公钥复制到github上,使用ssh -T git@github.com验证是否成功,成功会出现以下语句

    1
    2
    trluper@trluper-virtual-machine:~$ ssh -T git@github.com
    Hi trluper! You've successfully authenticated, but GitHub does not provide shell access.

附加:如果上面的ssh -T git@github.com验证成功,但是git clone时出现错误:

1
2
3
trluper@trluper-virtual-machine:/home/CPP_project$ git clone git@github.com:qinguoyi/TinyWebServer.git
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
则说明本节git仓库没有没有和这个ssh key关联,则依次执行:
1
2
3
//查看密钥运行
root@trluper-virtual-machine:/home/trluper/.ssh# eval
root@trluper-virtual-machine:/home/trluper/.ssh# ssh-agent -s
输出:
1
2
3
SSH_AUTH_SOCK=/tmp/ssh-XXXXXX8U3b13/agent.259910; export SSH_AUTH_SOCK;
SSH_AGENT_PID=259911; export SSH_AGENT_PID;
echo Agent pid 259911;
//把ssh添加到你的账号
1
2
root@trluper-virtual-machine:/home/trluper/.ssh# ssh-agent bash
root@trluper-virtual-machine:/home/trluper/.ssh# ssh-add /home/trluper/.ssh/id_rsa
输出下述语句则说明添加成功
1
Identity added: /home/trluper/.ssh/id_rsa (1229413537@qq.com)

3. git工作流程

git一般工作流程如下:

  • 克隆 Git 资源作为工作目录。
  • 在克隆的资源上添加或修改文件。
  • 如果其他人修改了,你可以更新资源。
  • 在提交前查看修改。
  • 提交修改。
  • 在修改完成后,如果发现错误,可以撤回提交并再次修改并提交。

4. git三个区和三个状态

我们先来理解下 Git 工作区、暂存区和版本库概念:

  • 工作区:就是你在电脑里能看到的目录。
  • 暂存区:英文叫stageindex。一般存放在.git目录下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。存储着所有提交的版本快照,并由当前分支引用的指针HEAD指向该分支最新一条提交

  • 图中左侧为工作区,右侧为版本库。在版本库中标记为 index的区域是暂存区stage/index,标记为 master的是master分支所代表的目录树。
  • 图中我们可以看出此时HEAD实际是指向master分支的一个游标。所以图示的命令中出现HEAD的地方可以用master来替换。
  • 图中的objects标识的区域为Git的对象库,实际位于.git/objects目录下,里面包含了创建的各种对象及内容。
  • 当对工作区修改(或新增)的文件执行git add命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
  • 当执行提交操作git commit时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master指向的目录树就是提交时暂存区的目录树。
  • 当执行git reset HEAD命令时,暂存区的目录树会被重写,被 master分支指向的目录树所替换,但是工作区不受影响。
  • 当执行 git rm --cached <file>命令时,会直接从暂存区删除文件,工作区则不做出改变。
  • 当执行 git checkout . 或者 git checkout -- <file>命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。
  • 当执行 git checkout HEAD . 或者 git checkout HEAD <file>命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

5. Git创建仓库

可以使用一个已经存在的目录作为Git仓库。Git使用git init命令来初始化一个Git仓库,Git的很多命令都需要在Git的仓库中运行,所以git init是使用Git的第一个命令。

在执行完成git init命令后,Git 仓库会生成一个.git目录,该目录包含了资源的所有元数据,其他的项目目录保持不变

  • 当前目录即为仓库:使用当前目录作为 Git 仓库,我们只需使它初始化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    git init
    //示例
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest
    $ git init
    Initialized empty Git repository in C:/Users/Trluper/Desktop/gitTest/.git/
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ ls -al
    total 8
    drwxr-xr-x 1 Trluper 197121 0 Mar 13 12:43 ./
    drwxr-xr-x 1 Trluper 197121 0 Mar 13 12:42 ../
    drwxr-xr-x 1 Trluper 197121 0 Mar 13 12:43 .git/
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ cd .git/
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest/.git (GIT_DIR!)
    $ ls
    HEAD config description hooks/ info/ objects/ refs/
    该命令执行完后会在当前目录生成一个 .git 目录,内部含有的内容如上所示,没有index是因为我们还没用到暂存区,如果git add filename则就会创建一个index目录。

  • 使用我们指定目录作为Git仓库。

    1
    git init newrepo
    初始化后,会在newrepo目录下会出现一个名为 .git的目录,所有Git需要的数据和资源都存放在这个目录中。

如果当前目录下有几个文件想要纳入版本控制,需要先用git add命令告诉Git开始对这些文件进行跟踪,然后提交:

1
2
3
4
//以下命令将目录下以 .c 结尾及 README 文件提交到仓库中。
$ git add *.c
$ git add README
$ git commit -m '初始化项目版本'
> 注: 在 Linux 系统中,commit 信息使用单引号 ',Windows 系统,commit 信息使用双引号"。 >所以在 git bash 中git commit -m '提交说明'这样是可以的,在 Windows 命令行中就要使用双引号 >git commit -m "提交说明"

6. Git的基本操作

Git 的工作就是创建和保存你项目的快照及与之后的快照进行对比。Git 常用的是以下 6 个命令:git clone、git push、git add 、git commit、git checkout、git pull,后面我们会详细介绍。

  • workspace:工作区
  • staging area:暂存区/缓存区
  • local repository:版本库或本地仓库
  • remote repository:远程仓库

6.1 git clone

我们使用git clone从现有Git仓库中拷贝项目(类似svn checkout).克隆仓库的命令格式为:git clone <repo>

要克隆Ruby语言的Git代码仓库Grit,可以用下面的命令:

1
$ git clone git://github.com/schacon/grit.git

6.2 本地仓库操作

下表列出了有关创建与提交你的项目的快照的命令:

命令 说明
git add 添加文件到暂存区
git status 查看仓库当前的状态,显示有变更的文件。
git diff 比较文件的不同,即暂存区和工作区的差异。
git commit 提交暂存区到本地仓库。
git reset 回退版本。
git rm 将文件从暂存区和工作区中删除。
git mv 移动或重命名工作区文件。
6.2.1 git add命令

git add命令可将该文件添加到暂存区,其形式可为:

1
2
3
4
5
6
#添加一个或多个文件到暂存区:
git add [file1] [file2] ...
#添加指定目录到暂存区,包括子目录:
git add [dir]
#添加当前目录下的所有文件到暂存区:
git add .
示例:
1
2
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git add test1

6.2.2 git status命令

git status 命令用于查看在你上次提交之后是否有对文件进行再次修改。

1
2
3
4
5
6
7
8
9
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git status
On branch master

No commits yet

Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: test1/test1.txt
通常我们使用 -s 参数来获得简短的输出结果:
1
2
3
4
5
6
7
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ echo "trluper" > test1/test1.txt

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git status -s
AM test1/test1.txt
?? test1.txt
- M:表示这个文件在我们将它添加到缓存之后又有改动。 - ??:表示改文件未添加到缓存区

6.2.3 git diff命令

git diff 命令显示已写入暂存区和已经被修改但尚未写入暂存区文件的区别。git diff 有两个主要的应用场景:

  • 尚未缓存的改动:git diff
  • 查看已缓存的改动: git diff --cached
  • 查看已缓存的与未缓存的所有改动:git diff HEAD
  • 显示摘要而非整个 diff:git diff --stat
1
2
3
4
5
6
7
8
9
10
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git diff
warning: LF will be replaced by CRLF in test1/test1.txt.
The file will have its original line endings in your working directory
diff --git a/test1/test1.txt b/test1/test1.txt
index e69de29..6b69dda 100644
--- a/test1/test1.txt
+++ b/test1/test1.txt
@@ -0,0 +1 @@
+trluper
6.2.4 git commit命令

git commit 命令将暂存区内容添加到本地仓库中。

1
2
3
4
5
6
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git commit -m "commit test 2"
[master (root-commit) b795d59] commit test 2
2 files changed, 2 insertions(+)
create mode 100644 test1.txt
create mode 100644 test1/test1.txt

  • -mmmessage的缩写,表示为后面要接的提交描述,如果没有加-m描述,则git会打开一个Vim编辑器让你填写提交信息
  • -a:如果你觉的不要填写提交信息,那么-a选项跳过这一步
6.2.5 git reset命令

git reset 命令用于回退版本,可以指定退回某一次提交的版本。语法格式如下:

1
2
3
git reset [--soft | --mixed | --hard] [HEAD/commit_id]
//回退指定版本号
git reset -hard (版本号) //版本号没必要写全,前几位就可以了,Git会自动去找,版本号通过git log --pretty=oneline获取

  • --hard:工作区、暂存区、本地仓库都会回滚到对应commit-id上

  • –-mixed为默认的,可以不用带该参数。使用该参数工作区代码不会受到影响,但是暂存区、本地仓库区的代码已经回滚到了YY对应的commit-id上。

  • --soft:工作区和暂存区的代码不会受到影响,但是本地仓库的代码会回滚到YY对应的commit-id上

示例:

1
2
3
4
5
6
7
8
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git log --pretty=oneline
450f4d7914f2db54bdab2eea422119e1fea7fafa (HEAD -> master) 第二次commit
b795d59de32dd11f307ecefa32b51c7dd8b901af commit test 2

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git reset --hard HEAD^
HEAD is now at b795d59 commit test 2

注意:谨慎使用 –-hard 参数,它会删除回退点之前的所有日志提交记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest ((8692a93...))
$ git log --pretty=oneline
8692a9397fb6fd23a262eb8f38997b549064a017 (HEAD) fix conflict
0bd22ddc1e7387bd4e97effa0a463056ce7be0dd master修改

//--hard回退到master修改
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest ((8692a93...))
$ git reset --hard 0bd22ddc1e7387bd4e97effa0a463056ce7be0dd
HEAD is now at 0bd22dd master修改

//再次查看日志:fix conflict记录已经没有了
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest ((0bd22dd...))
$ git log --pretty=oneline
0bd22ddc1e7387bd4e97effa0a463056ce7be0dd (HEAD) master修改


HEAD说明

1
2
3
4
5
HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^ 上上一个版本
HEAD^^^ 上上上一个版本
以此类推...
也可以~数字表示
1
2
3
4
5
HEAD~0 表示当前版本
HEAD~1 上一个版本
HEAD~2 上上一个版本
HEAD~3 上上上一个版本
以此类推...

6.2.6 git revert命令

上面的git reset [commit_id]--hard参数太极端直接清除了[commit_id]之前的提交记录,而对应参数--mixed --soft虽然不会清除记录,但没有更改版本库的内容,即你还得修改后手动commit一次。

revert命令不这样做,他不会清除之前的提交日志记录,而是自动的commit一次最新的提交

6.2.7 git rm命令

git rm 命令用于删除文件。

如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 Changes not staged for commit 的提示。

git rm 删除文件有以下几种形式:

  • 将文件从暂存区和工作区中删除:
    • 如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f。
      1
      git rm -f <file>
    • 如果想把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 --cached 选项即可:
      1
      git rm --cached <file>
6.2.8 git mv命令

git mv命令用于移动或重命名一个文件、目录或软连接。

1
git mv [file] [newfile]
示例:
1
2
3
4
5
6
7
8
9
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git mv -f README.txt README.md

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: README.txt -> README.md
- -f:若新文件名已经存在,但还是要重命名它,可以使用 -f 参数

6.3 提交日志

命令 说明
git log 查看历史提交记录
git blame <file> 以列表形式查看指定文件的历史修改记录
6.3.1 git log命令

在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git log --oneline
21ab31a (HEAD -> master) 第三次提交
b795d59 commit test 2

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git log --pretty=online
fatal: invalid --pretty format: online

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git log --pretty=oneline
21ab31a605efea7f4b3f8ebb47aecee82311a534 (HEAD -> master) 第三次提交
b795d59de32dd11f307ecefa32b51c7dd8b901af commit test 2

  • 使用--pretty=oneline或者--oneline来查看历史记录的简洁的版本,含有commit提交id,哈希生成
  • --graph 选项,查看历史中什么时候出现了分支、合并
  • 可以用--reverse 参数来逆向显示所有日志
6.3.2 git blame命令

如果要查看指定文件的修改记录可以使用 git blame 命令,格式如下:

1
git blame <file>
示例:
1
2
3
4
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git blame README.md
88c273c5 README.md (wuwenjie 2023-03-13 18:55:00 +0800 1) 后缀名改了,为.md
21ab31a6 README.txt (wuwenjie 2023-03-13 18:42:25 +0800 2) 这是README文件,后缀还没改,为.txt

6.4 远程操作

命令 说明
git remote 远程仓库操作
git fetch 从远程获取代码库
git pull 下载远程代码并合并
git push 上传远程代码并合并
6.4.1 git remote命令

git remote 命令用于在远程仓库的操作,其有如下操作:

  • git remote add [shortname] [url]:添加远程版本库,其中[shortname]为别名,后续对改远程仓库的操作可以通过别名来使用

    1
    2
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git remote add trluperLearnGit https://github.com/trluper/Trluper_LearnGit.git

  • -v:显示当前所有的远程仓库git remote -v

    1
    2
    3
    4
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git remote -v
    trluperLearnGit https://github.com/trluper/Trluper_LearnGit.git (fetch)
    trluperLearnGit https://github.com/trluper/Trluper_LearnGit.git (push)

  • git remote show:显示某个远程仓库的信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git remote show
    trluperLearnGit

    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git remote show trluperLearnGit
    * remote trluperLearnGit
    Fetch URL: https://github.com/trluper/Trluper_LearnGit.git
    Push URL: https://github.com/trluper/Trluper_LearnGit.git
    HEAD branch: (unknown)

  • git remote rm name :删除远程仓库
  • git remote rename old_name new_name : 修改远程仓库名

6.4.3 git push 命令

git push 命令用于从将本地的分支版本上传到远程并合并。命令格式如下

1
2
3
git push <远程主机名> <本地分支名>:<远程分支名>
//如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程主机名> <本地分支名>

示例:

1
2
3
4
5
6
7
8
9
10
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git push trluperLearnGit master:master
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (10/10), 920 bytes | 460.00 KiB/s, done.
Total 10 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/trluper/Trluper_LearnGit.git
* [new branch] master -> master
- --force:本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数:
1
git push --force trluperLearnGit master:trluper

  • --delete:删除主机的分支可以使用 --delete 参数(一般不使用)

注意:一般来说在实际开发中,我们总会在远程仓库建立自己的分支,而不是直接push到master分支,这样push到自己分支,管理者看完修改对比并同意后才合并到master分支,这才是正确的做法

6.4.2 git fetch 命令

git fetch 命令用于从远程获取代码库。因为git fetch不会改变本地仓库的状态,该命令执行完后需要执行 git merge 远程分支到你本地仓库所在的分支。命令格式

git fetch 实际所做的工作是将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态

1
2
git fetch shortname
git merge shortname/branch
  • git fetch:改命令告诉 Git 去远程仓库获取它有你没有的数据。,下面的88c273c..54788d2 master -> trluperLearnGit/master表示确实有新数据可获取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git fetch trluperLearnGit
    remote: Enumerating objects: 5, done.
    remote: Counting objects: 100% (5/5), done.
    remote: Compressing objects: 100% (3/3), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), 766 bytes | 40.00 KiB/s, done.
    From https://github.com/trluper/Trluper_LearnGit
    88c273c..54788d2 master -> trluperLearnGit/master

  • git merge trluperLearnGit/master然后执行与本地指定分支合并

    1
    2
    3
    4
    5
    6
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git merge trluperLearnGit/master
    Updating 88c273c..54788d2
    Fast-forward
    README.md | 2 ++
    1 file changed, 2 insertions(+)
    查看一下是否更改了工作区的:
    1
    2
    3
    4
    5
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ cat README.md
    后缀名改了,为.md
    这是README文件,后缀还没改,为.txt
    我在github上修改,测试git fetch

6.4.3 git pull命令

git pull 命令用于从远程获取代码并合并本地的版本。就是将上面的git fetchgit merge合并·到了一起。一般来说使用pull较多

  • git pull [shortname] [远程仓库分支]:[本地仓库分支]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git pull trluperLearnGit trluper:master
    remote: Enumerating objects: 5, done.
    remote: Counting objects: 100% (5/5), done.
    remote: Compressing objects: 100% (3/3), done.
    remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), 687 bytes | 42.00 KiB/s, done.
    From https://github.com/trluper/Trluper_LearnGit
    54788d2..20be99d trluper -> master
    * [new branch] trluper -> trluperLearnGit/trluper
    warning: fetch updated the current branch head.
    fast-forwarding your working tree from
    commit 54788d2727502d34e5e214c2ce08853ac628a6f5.
    Already up to date.

7. Git的分支管理

几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。Git分支实际上是指向更改快照的指针。有人把Git的分支模型称为必杀技特性,而正是因为它,将Git从版本控制系统家族里区分出来。

在 Git 里,master 分支叫主分支。HEAD严格来说不是指向提交,而是指向 mastermaster 才是指向提交的,所以,HEAD 指向的就是当前分支。

7.1 git branch创建分支

1
git branch (branchname)

没有参数时,git branch会列出你在本地的分支。当你执行git init的时候,默认情况下Git就会为你创建master主分支。如果我们要手动创建一个分支。执行git branch (branchname)即可。

1
2
3
4
$ git branch testing
$ git branch
* master
testing

7.2 git checkout切换分支

格式:

1
git checkout [commit_id/分支名称]
在git中,每个commit提交都会生成哈希索引,默认HEAD指向最新的提交记录,checkout其实就是改变HEAD的指向,从而达到改变切换分支的目的。但他不仅仅只有改变分支的作用,只要你想切换到任一提交记录都可以:
1
2
3
4
5
6
7
8
9
10
11
12
13
Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git log --pretty=oneline
65eb23309a8650f462f61f14ec661219072f2a8f (HEAD -> master) checkout
8692a9397fb6fd23a262eb8f38997b549064a017 fix conflict
0bd22ddc1e7387bd4e97effa0a463056ce7be0dd master修改

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
$ git checkout 8692a9397fb6fd23a262eb8f38997b549064a017
Note: switching to '8692a9397fb6fd23a262eb8f38997b549064a017'.

Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest ((8692a93...))
$

  • git checkout (branch)切换到我们要修改的分支,checkout的工作原理就只是修改HEAD指针的指向。

  • 每个提交记录是独立的,其工作区间、暂存区和版本库的内容不与其他记录共享,即当切换到一个提交记录时,就会显示改记录的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ls
README
$ echo 'runoob.com' > test.txt
$ git add .
$ git commit -m 'add test.txt'
[master 3e92c19] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ ls
README test.txt
$ git checkout testing
Switched to branch 'testing'
$ ls
README
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt

当我们切换到testing分支的时候,我们添加的新文件 test.txt被移除了。切换回master分支的时候,它们又重新出现了。

7.4 合并分支

一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。 你可以使用以下命令将任何分支合并到当前分支中去:git merge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git branch
* master
newtest
$ ls
README test.txt
$ git merge newtest
Updating 3e92c19..c1501a2
Fast-forward
runoob.php | 0
test.txt | 1 -
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
以上实例中我们将newtest分支合并到主分支去,那么test.txt文件被删除,runoob.php被添加到主分支

7.5 删除分支

删除分支只需加个-d即可:git branch -d (branchname)

1
2
3
4
5
6
7
$ git branch
* master
testing
$ git branch -d testing
Deleted branch testing (was 85fc7e7).
$ git branch
* master

7.6 详解分支管理

假如你有两个分支masterdev:

  • 1、当你只是checkout切换一个分支,而对两个分支都没修改(在切换分支时一旦在工作区修改git会要求你在切换前commit),那么各分支状态如下:

  • 2、现在你切换到了dev,并修改了三次,commit了三次,那么在本地仓库(版本库)会生成三次的哈希索引,且其分支记录指针图示如下:

  • 3、现在有另一种情况,你在dev修改,另一位同事对master分支做出修改,这时候就可能出现潜在问题,出现合并冲突:
    • 如果你们的修改没有出现合并冲突,那么很好,你们可以愉快的执行git merge dev操作
    • 但如果你能出现冲突了(比如说修改了同一份文件、master创建一份新的代码文价),你必须手动解决冲突,再去合并,非常好的一点是,git会提示冲突出现的位置
  • 举例有一个test.txt文件,在mater添加了master:修改,在test分支添加test:修改,都各自commit,在执行合并操作时出现合并冲突:

    1
    2
    3
    4
    5
    Trluper@DESKTOP-67ADUGH MINGW64 ~/Desktop/gitTest (master)
    $ git merge test
    Auto-merging test.txt
    CONFLICT (content): Merge conflict in test.txt
    Automatic merge failed; fix conflicts and then commit the result.

合并冲突:冲突的产生是因为在合并的时候,不同分支修改了相同的位置。所以在合并的时候git不知道哪个到底是你想保留的,所以就提出疑问(冲突提醒)让你自己手动选择想要保留的内容,从而解决冲突。 解决冲突:

  • (一股脑)使用merge命令合并分支,解决完冲突,执行git add .和git commit -m'fix conflict'。这个时候会产生一个commit。
  • (交互式)使用rebase命令合并分支,解决完冲突,执行git add .和git rebase --continue,不会产生额外的commit。这样的好处是,‘干净’,分支上不会有无意义的解决分支的commit;坏处,如果合并的分支中存在多个commit,需要重复处理多次冲突。

8 git回滚一次错误合并

在git种支持回滚的操作主要有三个checkout、reset、revert

  • 三个回滚操作在我们错误提交还未push时具有重要作用,支持我们回滚版本、版本管理强。
  • 三个操作的具体见上面章节。

9 git的merge和rebase区别

mergerebase都是用来合并分支的。

  • 1.采用mergerebase后,git log的区别:
    • 执行merge命令的分支会生成merge的提交记录,
    • rebase不会生成merge记录,但会保留所有的commit记录,话句话说就是将另一个分支作为当前分支的基线。(即rebase: 合体 merge: 脚手相连,肚皮是独立的
  • mergerebase应用场景:
    • merge一般用在master这种公共分支上。在多人开发同一个项目时,如果多人的开发分支有一定的命名规范,比如需求的版本号,那么在排查问题或者追溯需求时,会很方便;保存的日志记录轨迹清晰,回滚方便
    • 一般rebase基本法则是只对自己的的分支做,在自己的分支上若有多次提交,可以合并为一次提交,并强推上去,这样的话将自己的分支合入公共分支master的时候,分支树也很简明
1
2
3
在dev分支执行下面语句的意思:
git merge master:将master代码合并至dev
git rebase master:意思就是将master作为dev的新基线,换句话意思就是将master合并到dev

扩展:当你本地仓库落后于远程仓库进行commit ,然后pull, 那会多生成一条merge记录, 这是非常错误的:

  • 情况1:如果 remote 分支超前于本地分支,并且本地分支没有任何 commit 的,直接从 remote 进行 pull 操作,默认会采用 fast-forward 模式,这种模式下,并不会产生合并节点,也就是说不会产生多余的记录
  • 情况2:如果,本地先 commit 后再去 pull,那么此时,remote 分支和本地会分支会出现分叉,这个时候使用 pull 操作拉取更新时,就会进行分支合并,产生合并节点和 log 记录

关键是看自己本地有没有commit,因为commit已经进入了本地仓库了,是会被检测到,并记录的

应该要解决第二种情况:使用git pull --rebase ,使用rebase合并,避免产生记录

因此一个合作项目的提交一般是这样的:(假设本地dev,远程自己的分支也是dev,远程主分支是master)

  • 从远程master拉取:git pull --reabse [shortname] master
  • 本地commit:git add . ;git commit -m "dev"
  • 看是否有冲突,有冲突解决冲突
  • push到远程dev分支:git push Trluper dev
  • 在远程仓库请求合并

文章来源:菜鸟教程