git简介

一:Git是什么?

Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 工作原理 / 流程:

image-20201021180535292

Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remote:远程仓库

二:SVN与Git的最主要的区别?

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。 Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

三:初始化设置

1. 设置用户名及邮箱信息

  • 全局设置

    git config --global user.name "Name"
    git config --global user.email "Email"
    
  • 针对项目设置

    git config user.name "Name"
    git config user.email "Email"
    

2. 设置换行符自动转换

git config --global core.autocrlf  [true | input | false]  # 全局设置
git config --local core.autocrlf  [true | input | false] # 针对本项目设置
  • true 提交时转换为LF,检出时转换为CRLF
  • input 提交时转换为LF,检出时不转换
  • false 提交与检出的代码都保持文件原有的换行符不变(不转换)

推荐设置:

  • windows
git config --global core.autocrlf true
  • other OS
git config --global core.autocrlf input

初始化仓库

版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

git init
git add 初始化.md
git commit Or git commit -m<message>

版本管理

一、版本回退

1). 获取仓库当前log列表

  1. 使用 git log命令查看

    $ git log
    commit 310f02083e0bfd1762ddbd33664d01881cef8fd3 (HEAD -> master)
    Author: Pota <[email protected]>
    Date:   Wed Oct 21 17:57:12 2020 +0800
    
        feat: 第三次改动
    
    commit ff1eb142c143b9498d57ad3c8218bd62019d3f18
    Author: Pota <951549518[email protected]>
    Date:   Wed Oct 21 17:56:53 2020 +0800
    
        feat: 第二次改动
    
    commit 62ea36c7ed237ec92d333a4fc5a5d2f7f929665e
    Author: Pota <[email protected]>
    Date:   Wed Oct 21 17:56:24 2020 +0800
    
        feat: 第一次改动
    
    commit 25bae0398fc1fe2fb10add954fba4202f8142f32
    Author: Pota <[email protected]>
    Date:   Wed Oct 21 17:55:13 2020 +0800
    
        feat: 首次提交
    

    git log命令显示从最近到最远的提交日志,我们可以看到4次提交,如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

    git log --pretty=oneline
    310f02083e0bfd1762ddbd33664d01881cef8fd3 (HEAD -> master) feat: 第三次改动
    ff1eb142c143b9498d57ad3c8218bd62019d3f18 feat: 第二次改动
    62ea36c7ed237ec92d333a4fc5a5d2f7f929665e feat: 第一次改动
    25bae0398fc1fe2fb10add954fba4202f8142f32 feat: 首次提交
    
  2. 使用 IDE或图形化工具查看

    image-20201021181624441

2). 版本回退

版本回退仅限本地仓库中使用,若提交已push至远程仓库,则无法回退远程仓库内容

  1. 命令
git reset –-[soft | hard | mixed] commit_id
  • --soft--mixed--hard是三个恢复等级:

    --soft仅将头指针HEAD恢复,已经add的缓存以及工作空间的所有东西都不变;暂存区和工作区不会被切换;保留源码,只回退到commit 信息到某个版本.不涉及index的回退,如果还需要提交,直接commit即可。

    --mixed将头HEAD恢复掉,已经add的缓存也会丢失掉,工作空间的代码之类的不变;暂存区会更新至指定的commit,工作区不会受影响;会保留源码,只是将git commit和index 信息回退到了某个版本。

    --hard将一切全都恢复,头HEAD改变,add的缓存消失,代码等也恢复到以前状态;暂存区和工作区同时更新到指定的commit;源码也会回退到某个版本,commit和index 都回回退到某个版本.

  1. 注意事项

    reset --hard操作会导致当前缓存区和工作区的改动重置

    reset --mixed操作会导致当前缓存区的改动重置

分支管理

一、创建与合并分支

git 初始化后会默认创建master分支 开发过程中一般会采用多分支进行项目管理

创建分支

git branch <branch name>      # 基于当前HEAD指向分支创建新分支
git checkout -b <branch name> # 基于当前HEAD指向分支创建新分支并切换到该分支
git switch -c <barnch name>   # 基于当前HEAD指向分支创建新分支并切换到该分支

切换分支

git checkout <branch name>
git switch <branch name>

合并分支

git merge <branch name> # 合并指定分支改动到当前分支

删除分支

git branch -d <branch name>  # 删除本地分支
git push origin -d <branch name>  # 删除远程分支

合并模式

合并分支是默认使用Fast forward模式合并,合并后会丢失分支信息 使用--no-ff参数禁用Fast forward模式后合并会保留分支信息

image-20201022164115495

二、解决冲突

两个分支同一个文件都进行了提交导致节点无法连续后 合并会导致冲突

冲突产生后 **必须 ** 解决冲突后再次提交

$ git merge develop
Auto-merging readme.md
CONFLICT (content): Merge conflict in readme.md
Automatic merge failed; fix conflicts and then commit the result.

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   readme.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   "\346\225\231\347\250\213.md"

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

查看readme.md文件后会发现git将冲突内容依据HEAD和冲突分支形式列出

$ cat readme.md
第一次改动内容

第二次改动内容

第三次改动内容

<<<<<<< HEAD
master:第四次改动内容
=======
develop 第四次改动内容
>>>>>>> develop

此时需要将冲突文件修改为合并后内容后再次添加到缓存区并提交

$ cat readme.md
第一次改动内容

第二次改动内容

第三次改动内容

master:第四次改动内容

$ git add readme.md
$ git commit -m"第四次提交"

此时git 主分支线路应该如下

$ git log --graph --pretty=oneline --abbrev-commit
*   c6fba0d (HEAD -> master) 第四次提交
|\
| * 63fcc15 (develop) feat: 第四次改动
| * 55c58f4 feat: 第四次改动
* | 9de4e23 feat: 第四次改动
* | e2a6980 feat: 第四次改动
|/
* 983093c feat: 分支前教程
* 310f020 feat: 第三次改动
* ff1eb14 feat: 第二次改动
* 62ea36c feat: 第一次改动
* 25bae03 feat: 首次提交

三、rebase

命令说明

$ git rebase -i HEAD~4

pick 55c58f4 feat: 第四次改动
pick 63fcc15 feat: 第四次改动
pick 2f5f83d 第五次提交
pick 5abf70e 第六次提交
pick 5e96e00 feat: rebase前提交

# Rebase 9de4e23..5e96e00 onto 5abf70e (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
  • pick

    pick 只表示包含提交。 在变基进行时重新排列 pick 命令的顺序会更改提交的顺序。 如果选择不包含提交,应删除整行。

  • reword

    reword 命令类似于 pick,但在使用后,变基过程就会暂停,让您有机会改变提交消息。 提交所做的任何更改都不受影响。

  • edit

    如果选择 edit 提交,您将有机会修订提交,也就是说,可以完全添加或更改提交。 您也可以创建更多提交后再继续变基。 这样您可以将大提交拆分为小提交,或者删除在提交中执行错误更改。

  • squash

    此命令可用于将两个或以上的提交合并为一个。 下面的提交压缩到其上面的提交。 Git 让您有机会编写描述两次更改的新提交消息。

  • fixup

    这类似于 squash,但要合并的提交丢弃了其消息。 提交只是合并到其上面的提交,之前提交的消息用于描述两次更改。

  • exec

    这可让您对提交运行任意 shell 命令。

示例

假设当前git提交历史如下

$ git log --pretty=oneline
e85216ae5739c9eb1835a913b2c9449abd45ed74 这个提交移动到B文件提交前
046dfd07a3fc537871e837a8e5209a12ab37eaca 这个commit写错了
c50bd16a3ad4ef8b9cfc4ab5a7ee465609c1c976 文件A追加
de5cd71b26e94f137c7b202db0c4bee5600b2442 文件B修复
1bbbc6c8efa86e60aee2916dc46c173d1fea4f1d 文件B提交
8dbb92ae88b9d868a4817d8f25537bb83bf6c20c 文件A提交

$ git rebase -i HEAD~6
pick 8dbb92a 文件A提交
pick 1bbbc6c 文件B提交
pick de5cd71 文件B修复
pick c50bd16 文件A追加
pick 046dfd0 这个commit写错了
pick e85216a 这个提交移动到B文件提交前

# Rebase 412c835..e85216a onto c50bd16 (6 commands)

准备进行以下变更:

  • c50bd16 压缩到8dbb92a
  • 将最后一个提交(e85216a)向上移动到文件B提交提交(1bbbc6c)之前,并保留为pick
  • 文件B修复提交(de5cd71)合并到文件B提交提交(1bbbc6c)中,并忽略提交消息
  • 使用 reword 修复拼写错误的提交 (046dfd0) 的提交消息

将编辑器中文件修改为以下内容:

pick 8dbb92a 文件A提交
squash c50bd16 文件A追加
pick e85216a 这个提交移动到B文件提交前
pick 1bbbc6c 文件B提交
fixup de5cd71 文件B修复
reword 046dfd0 这个commit写错了

保存并关闭编辑器,开始交互式rebase

  1. pick 8dbb92a命令因无内容改动被跳过

  2. squash c50bd16命令因合并提交需手动修改 会打开默认编辑器进行改动如下:

    # This is a combination of 2 commits.
    # This is the 1st commit message:
    
    文件A提交
    
    # This is the commit message #2:
    
    文件A追加
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    #
    # Date:      Tue Oct16:07:46+0800
    #
    # interactive rebase in progress; onto 412c835
    # Last commands done (2 commands done):
    #    pick 8dbb92a 文件A提交
    #    squash c50bd16 文件A追加
    # Next commands to do (4 remaining commands):
    #    pick e85216a 这个提交移动到B文件提交前
    #    pick 1bbbc6c 文件B提交
    # You are currently rebasing branch 'master' on '412c835'.
    #
    # Changes to be committed:
    #▸      modified:   a
    #
    

    修改内容为想要的提交信息后保存文件

    # This is a combination of 2 commits.
    # This is the 1st commit message:
    文件A提交
    # This is the commit message #2:
    #文件A追加
    
  3. pick e85216apick 1bbbc6cfixup de5cd71因无需干预会自动进行,其中fixup de5cd71会将de5cd71提交合并到1bbbc6c中并舍弃commit信息

  4. reword 046dfd0 会再次打开编辑器并显示一下信息:

    这个commit写错了
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    #
    # Date:      Tue Oct 27 16:08:56 2020 +0800
    #
    # interactive rebase in progress; onto 412c835
    # Last commands done (6 commands done):
    #    fixup de5cd71 文件B修复
    #    reword 046dfd0 这个commit写错了
    # No commands remaining.
    # You are currently editing a commit while rebasing branch 'master' on '412c    835'.
    #
    # Changes to be committed:
    #▸      modified:   c
    #
    

    将内容改为想要的commit后保存 并完成此次rebase

    [detached HEAD 5a30ce2] 文件A提交
     Date: Tue Oct 27 16:07:46 2020 +0800
     1 file changed, 2 insertions(+)
    [detached HEAD 46eb136] 这个commit写错了 现在修复了
     Date: Tue Oct 27 16:08:56 2020 +0800
     1 file changed, 1 insertion(+)
    Successfully rebased and updated refs/heads/master.
    

在完成rebase后查看git历史

$ git log --pretty=oneline

46eb136e6d0f70536069aa27dd603a27c8ceb4a1 这个commit写错了 现在修复了
0b17895ec112456d4e337f678bf1c2c95a85cd03 文件B提交
40b2e81db35a3e66fa4d57911df8a52dd5ff3c7b 这个提交移动到B文件提交前
5a30ce23ef594f73429ef7c77ffc0f09ceac01bf 文件A提交
412c83521248caafcfe89c1afeffb6de3551dc43 init

冲突解决

在rebase过程中如果遇到冲突 按照正常冲突解决过程一样 修改完成后使用命令

$ git add <file>
$ git rebase --continue

四、stash

当在某个分支正在进行某项修改时,此时出现了一个bug必须优先解决,这个时候需要切换到hot-fix分支进行bug媳妇,此时进行到一半的工作也不能提交,这个时候就需要将当前未完成的修改存储起来,等bug修改完成以后再继续进行修改

储藏你的工作

为了演示这一功能,你可以进入你的项目,在一些文件上进行工作,有可能还暂存其中一个变更。如果你运行 git status,你可以看到你的中间状态:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   d.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   a

现在你想切换分支,但是你还不想提交你正在进行中的工作;所以你储藏这些变更。为了往堆栈推送一个新的储藏,只要运行 git stash

$ git stash
Saved working directory and index state WIP on master: 46eb136 这个commit写错了 现在修复了

你的工作目录就干净了:

$ git status
On branch master
nothing to commit, working tree clean

这时,你可以方便地切换到其他分支工作;你的变更都保存在栈上。要查看现有的储藏,你可以使用 git stash list

$ git stash list
[email protected]{0}: WIP on master: 46eb136 这个commit写错了 现在修复了

使用储藏

当bug修复完成后回到develop分支想要继续之前的工作,此时使用 git stash apply即可将之前储藏的改动重新应用,默认情况下如果有多个储藏内容时git stash apply会默认使用最新的一条。如果想用更早的储藏,可以使用名字指定git stash apply [email protected]{0}

$ git stash apply
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   d.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   a

apply 选项只尝试应用储藏的工作——储藏的内容仍然在栈上。要移除它,你可以运行 git stash drop,加上你希望移除的储藏的名字:

$ git stash list
[email protected]{0}: WIP on master: 46eb136 这个commit写错了 现在修复了
$ git stash drop [email protected]{0}
Dropped [email protected]{0} (2def785d0c921b679077086faefc40804212e732)

你也可以运行 git stash pop 来重新应用储藏,同时立刻将其从堆栈中移走。

从储藏中创建分支

如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。

$ git stash branch testchanges
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   d.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   a

Dropped refs/[email protected]{0} (5945c48cdc350188c675eb2f78c8dcdae72a5870)