Git 操作指南

发布于 2022-02-08  829 次阅读


IDEA中如何使用Git

一、 在Idea中配置Git

安装好IntelliJ IDEA后,如果Git 安装在默认路径下,那么idea会自动找到git的位置,如果更改了Git 的安装位置则需要手动配置下Git 的路径。

选择File→Settings打开设置窗口,找到Version Control下的git选项

选择git的安装目录后可以点击“Test”按钮测试是否正确配置。

至此,Git 已经集成到IDEA当中,下一步我们需要配置Git 账号信息

在IDEA中设置Git Hub,File–>Setting->Version Control–>GibHub

可以使用账号密码,或者Token(Token需要在你的Git Hub网站生成)

img

img

二、 从远程Git Lab下拉取项目代码

1.cmd操作

在你存放代码的目录下,通过cmd命令克隆代码

git clone + 项目URL

2.使用IDEA的Git 操作

选择File→New→Project from Version Control

填写要拉取的远程项目的URL,点击Clone

注意,能够拉取该项目的前提是你具有对应的权限

三、导入拉取的工程

此时项目工程已经拉取到了你的电脑上,但此时观察IDEA里面的工程列表,并没有新增工程

这样的场景常会出现,比如你负责的开发任务,刚开始只涉及一个工程,而后涉及到其他工程,你满怀期待的将其他工程拉取下来,本地有了代码,却没有同时出现在IDEA的Project列表

对应的解决办法就是,将新拉取的工程加入到当前的项目模块组中

选择File→New→Project Structure→Modules→"+"→Import Module

选择你代码所在的文件夹,以Maven类型导入即可

如果你需要移除工程,将上述操作的“+”换成“-”即可

四、将修改保存到暂存区

Git 和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。

先来看名词解释。

工作区(Working Directory)

就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区:

版本库(Repository)

工作区有一个隐藏目录.git,这个不算工作区,而是Git 的版本库。

Git 的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git 为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

分支和HEAD的概念我们以后再讲。

前面讲了我们把文件往Git 版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

在IDEA中将文件修改添加到暂存区

修改文件,这里理解为进行开发即可,比如我新增一个字段,一个接口

右键工程→Git →Add

当然,在工作中涉及到改动多个文件,我们可以同时全部Add,也可以先Add一部分,再Add一部分

你可以把它想象成往盒子里面放物品,你可以一下子全部放进去,也可以一部分一部分的放入,同时,你不用担心先放进去的部分会遗漏(盒子就是暂存区,Add即将改动放进暂存区,commit则是将暂存区的内容放进版本库)

如果改动的文件很多,我们就很难记住哪些文件被修改,同样的,即使改动的地方很少,我们也希望改动被记录下来,我们需要查看时,就会一目了然

1.使用Git Status命令对比分支

点击IDEA下方的Terminal→输入Git status(Git status用于查看当前所有的Git 状态,包括未Add,已Add未Commit等)

对于热衷于敲命令的同学来说,这是一件好事,但它无法显示文件具体的改动,我们来看看方式二

如果你需要使用Git 命令,那么就在此处畅所欲敲吧

2.使用IDAE的Git 操作对比分支

右键改动所在的工程→Git →Compare with Branch→选择你需要进行对比的分支(一般和master分支对比)

可以看到修改的文件,点击查看具体的修改内容,这实在是太酷了

在与master(或你选择的分支)对比的情况下,我们更容易发现自己改动是否有误,同时我们可以在此处直接修改,文件会实时生效,不用再Add

五、将暂存区中的改动提交到版本库的分支中

复习一下工作区,版本库,暂存区,分支的概念

工作区 git add →暂存区 git commit →本地分支,需要注意的是本地分支和暂存区stage都存在于版本库中(可回看【四、将修改保存到暂存区】)

右键改动所在的工程→Git →Commit Changes

现在,你的改动已经被提交到本地分支

一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

Git  status查看工作区状态

你可以以此判断你是否漏掉了需要Commit的内容

工作区 git add →暂存区 git commit →本地分支 此时我们处于这条链路的最后一点【本地分支】

六、查看分支级别的改动信息

当你需要查看分支改动的时候,你可以使用 show history 查看当前分支的改动

右键工程→Git →show history,此时你会发现左下角的Git 面板被弹出

分支级别的信息,在这里都可以找到 你可以根据分支名/用户/日期/路径等对Git log 进行筛选

这些信息对于你后期避免分支冲突,查看分支改动有莫大的帮助

七、查看工作区,暂存区和版本库里面最新版本的区别

右键工程→Git →Compare with Revision

同样的,你也可以选择与其他版本进行比较

诶,你可能会说我们在前文提到了一种比较方法 使用IDEA的Git 操作对比改动 ,当时用的是 Compare with Branch,那现在为什么还要 Compare with Rivison 呢?

注意,这二者可是不一样的,Compare with Branch 是将你当前的工作区,暂存区,本地分支与远程分支进行对比,你可以理解为工程维度,尽管你可能会回滚;

而Compare with Rivision则是将你当前的工作区,暂存区与本地分支里的版本进行对比(每一次Commit都会创建一个版本)

八、回滚改动

1.你的改动还没Add到暂存区,只在工作区

这种情况直接改就可以了,工作区无所畏惧

2.你的改动已经Add到暂存区,但未Commit到本地分支

此时,你可以先使用 Git status 查看目前的Git 状态,它提示我们ApollConfigUtil文件的改动已经Add(绿色表示已经Add)

此时进行RollBack会回滚到未Add的状态

右键工程→Git →RollBack→选择你需要回滚的文件

使用 Git status 查看状态,红色表示已经Add,等待Commit,如果你有其他的未Add的改动,也会以绿色的形式显示在下面

右键工程→Git →RollBack→选择你需要回滚的文件

此时可以看到,你Add的改动,Commit的改动均消失不见了

3.你的改动已Commit到本地分支

此时你会发现RollBack无法点击,当你在工作区进行改动之后,它又可以点击了

总之,RollBack会让【未Add / 已Add但未Commit】的所有改动消失

九、从版本库删除文件

如果你需要删除一个文件,很简单,右键该文件→Delete 即可

在删除之后,如果你想查看它所带来的影响,同样可以使用 Git Status 命令

现在,我删除了 ApollConfigUtil.java 文件,使用 Git Status 来查看当前状态

此时,你具有两种选择

1.确实要从版本库中删除该文件,则直接提交改动即可提交改动

2.误删除该文件,那么因为版本库中还有,所以可以很轻松地把巫山的文件恢复到最新版本

使用IDEA 的 RollBack 操作回滚改动 或者 git checkout -- XX.java

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

十、分支管理

分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git 的时候,另一个你正在另一个平行宇宙里努力学习SVN。

如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git 又学会了SVN!

learn-branches

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作

其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。

但Git 的分支是与众不同的,无论创建、切换和删除分支,Git 在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

1.Git 的分支原理

版本回退里,你已经知道,每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git 里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支。

一开始的时候,master分支是一条线,Git 用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

git-br-initial

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。

当我们创建新的分支,例如dev时,Git 新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

git-br-create

你看,Git 创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

git-br-dev-fd

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git 怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

git-br-ff-merge

所以Git 合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

git-br-rm

真是太神奇了,你看得出来有些提交是通过分支完成的吗?

下面开始实战。

首先,我们创建dev分支,然后切换到dev分支:

$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后,用git branch命令查看当前分支:

$ git branch
* dev
  master

git branch命令会列出所有分支,当前分支前面会标一个*号。

然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:

Creating a new branch is quick.

然后提交:

$ git add readme.txt 
$ git commit -m "branch test"
[dev b17d20e] branch test
 1 file changed, 1 insertion(+)

现在,dev分支的工作完成,我们就可以切换回master分支:

$ git checkout master
Switched to branch 'master'

切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:

git-br-on-master

现在,我们把dev分支的工作成果合并到master分支上:

$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

注意到上面的Fast-forward信息,Git 告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。

合并完成后,就可以放心地删除dev分支了:

$ git branch -d dev
Deleted branch dev (was b17d20e).

删除后,查看branch,就只剩下master分支了:

$ git branch
* master

因为创建、合并和删除分支非常快,所以Git 鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

2.本地分支 / 远程分支的概念

分支分为本地分支,远程分支两大类;注意,这是学习分支内容的重要前提!

a.本地分支的理解

现在你的导师给你分配了一个任务 —— 给某一个服务新增字段;可能他会给你具体的工程路径,也可能让你自己推测(我导师即是如此)

好的,经过努力,你找到了新增服务所在的工程路径,现在回到第二步 从远程Git Lab下拉取项目代码

此时你的代码就从 远程的工程路径分支(可能是master 也可能是 你导师的分支)克隆到 → 你的本地分支(如果你没有创建新的分支,则为master)

接下来,导入拉取的工程,进行你的修改并保存到暂存区,再提交到版本库中,对应于前文的 第三点,第四点,第五点

b.远程分支的理解(master release rel_xx_xx)

我们知道,公司的代码存放于 GitLab,我们也是从 GitLab 上拉取工程代码,回顾第二步 从远程Git Lab下拉取项目代码 ,其实,我们忽略了一步——选择分支

Master分支:主分支,公司服务正在使用的代码分支;开发过程中的最后一步即合并到Master分支,Master为生产环境,对Master的操作不当将直接影响生产环境,因此对Master分支的操作需要极度小心(如果你有权限的话)

Release分支:可以理解为Master分支的防线,我们所作的改动会现在Release分支上运行检验,通过后才会合并到Master分支,Release分支的内容与Master分支完全一致

Rel_xx_xx需求分支:由于 Git 创建分支的便捷性,我们提倡每一个需求都创建一个对应的分支,这些分支可以命名为 Rel_xx_xx(根据公司规定),这些分支里面包含我们的具体改动,比如

注意,需求分支一般需要先在本地创建,然后推送到远程仓库时,远程仓库会创建对应同名分支

3.创建和合并分支

对于Master分支和Release分支,我们一般没有权限操作,在此不表;

那么对于需求分支,我们先在本地创建即可

a. 使用Git branch命令创建本地分支

b. 使用 IDEA 分支面板 创建本地分支

右下角master→New Branch →Create 即可

注意:IDEA 关于 Git 的操作面板即为此处,可完成分支的新增,删除,切换,查看等

4.切换分支

当前你工作在rel_test_002分支上,你需要查看rel_test_001分支状态的代码,那么你可以 切换分支

a. 使用git checkout <name>或者git switch <name>命令切换
b.使用 IDEA 的分支面板切换分支

右下角→选择分支→checkout 即可

Git 鼓励大量使用分支:

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>或者git switch <name>

创建+切换分支:git checkout -b <name>或者git switch -c <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

5.对比分支

使用IDAE对比分支

6.分支冲突

人生不如意之事十之八九,合并分支往往也不是一帆风顺的。

准备新的feature1分支,继续我们的新分支开发:

$ git switch -c feature1
Switched to a new branch 'feature1'

修改readme.txt最后一行,改为:

Creating a new branch is quick AND simple.

feature1分支上提交:

$ git add readme.txt

$ git commit -m "AND simple"
[feature1 14096d0] AND simple
 1 file changed, 1 insertion(+), 1 deletion(-)

切换到master分支:

$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Git 还会自动提示我们当前master分支比远程的master分支要超前1个提交。

master分支上把readme.txt文件的最后一行改为:

Creating a new branch is quick & simple.

提交:

$ git add readme.txt 
$ git commit -m "& simple"
[master 5dc6824] & simple
 1 file changed, 1 insertion(+), 1 deletion(-)

现在,master分支和feature1分支各自都分别有新的提交,变成了这样:

git-br-feature1

这种情况下,Git 无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:

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

果然冲突了!Git 告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件:

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

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.txt

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

我们可以直接查看readme.txt的内容:

Git  is a distributed version control system.
Git  is free software distributed under the GPL.
Git  has a mutable index called stage.
Git  tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1

Git 用<<<<<<<=======>>>>>>>标记出不同分支的内容,我们修改如下后保存:

Creating a new branch is quick and simple.

再提交:

$ git add readme.txt 
$ git commit -m "conflict fixed"
[master cf810e4] conflict fixed

现在,master分支和feature1分支变成了下图所示:

git-br-conflict-merged

用带参数的git log也可以看到分支的合并情况:

$ git log --graph --pretty=oneline --abbrev-commit
*   cf810e4 (HEAD -> master) conflict fixed
|\  
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/  
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file

最后,删除feature1分支:

$ git branch -d feature1
Deleted branch feature1 (was 14096d0).

工作完成。

7.分支合并

a.Fast forward模式

通常,合并分支时,如果可能,Git 会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git 就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

b.不使用Fast forward模式

merge后就像这样:

git-no-ff-mode

8.Git 的Head指针

Git 中的 HEAD 可以理解为指针,指向当前仓库所处的分支。 一般在有 Git 管理的目录下打开 Git 终端都能在当前路径的尾巴上,看到所处的分支名。 还可以在命令行中输入 查看当前 HEAD 指向哪里。

9.Bug分支

软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git 中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交:

$ git status
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   hello.py

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:   readme.txt

并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?

幸好,Git 还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge

现在,用git status查看工作区,就是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复bug。

首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)

$ git checkout -b issue-101
Switched to a new branch 'issue-101'

现在修复bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:

$ git add readme.txt 
$ git commit -m "fix bug 101"
[issue-101 4c805e2] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:

$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)

$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
 readme.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

太棒了,原计划两个小时的bug修复只花了5分钟!现在,是时候接着回到dev分支干活了!

$ git switch dev
Switched to branch 'dev'

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

工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:

$ git stash list
stash@{0}: WIP on dev: f52c633 add merge

工作现场还在,Git 把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

另一种方式是用git stash pop,恢复的同时把stash内容也删了:

$ git stash pop
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   hello.py

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:   readme.txt

Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)

再用git stash list查看,就看不到任何stash内容了:

$ git stash list

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}

10.Feature分支

软件开发中,总有无穷无尽的新的功能要不断添加进来。

添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。

现在,你终于接到了一个新任务:开发代号为Vulcan的新功能,该功能计划用于下一代星际飞船。

于是准备开发:

$ git switch -c feature-vulcan
Switched to a new branch 'feature-vulcan'

5分钟后,开发完毕:

$ git add vulcan.py

$ git status
On branch feature-vulcan
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   vulcan.py

$ git commit -m "add feature vulcan"
[feature-vulcan 287773e] add feature vulcan
 1 file changed, 2 insertions(+)
 create mode 100644 vulcan.py

切回dev,准备合并:

$ git switch dev

一切顺利的话,feature分支和bug分支是类似的,合并,然后删除。

但是!

就在此时,接到上级命令,因经费不足,新功能必须取消!

虽然白干了,但是这个包含机密资料的分支还是必须就地销毁:

$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.

销毁失败。Git 友情提醒,feature-vulcan分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用大写的-D参数。。

现在我们强行删除:

$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e).

终于删除成功!

十一、Pull最新代码

Pull操作会把远程仓库最新的代码拉取下来,这样能确保你本地分支的代码是最新的,因此,在开发过程中,如果你发现其他人修改了你工作对应的远程分支,你应该立即Pull最新的代码

十二、Push到远程仓库

现在,你终于完成了代码修改,你确定一切准备就绪,那么可以将你的分支推送到远程了;之前我们所有的操作均在本地分支上,如果想让我们的修改生效或者被其他人所看到,则需要推送到远程仓库

右键工程→Git →Push

当然,建议在Push你的修改之前,先Pull一下,Pull操作会把远程仓库最新的代码拉取下来,这样能确保你本地分支的代码是最新的,因此,在开发过程中,如果你发现其他人修改了你工作对应的远程分支,你应该立即Pull最新的代码(再次强调)

十三、修改 commit 描述信息

idea中,如何修改已经commit记录的message?如何修改已经push过记录message?全冉 的博客-CSDN博客idea修改commit信息

完结

Git 是目前世界上最先进的分布式版本控制系统(没有之一)。如果你想要学习更多的 Git 操作,可以前往廖雪峰前辈的博客网站进行学习!


她喜欢所以就做咯