Git实例学习

按实例的方式进行学习。

概念

Git 本地数据管理,大概可以分为三个区:

工作区(Working Directory):电脑里能看到的目录,例如下面例子中的D:/learngit就是一个工作区
版本库(commit History):存放已经提交的数据。工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
暂存区(Stage/Index):数据暂时存放的区域。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

工作区的文件 git add 后到暂存区,暂存区的文件 git commit 后到版本库。

创建、提交、撤销

本地已创建了项目文件夹(D:/learngit),现在需要将此项目纳入到git版本管理

创建git版本库

cd d:/learngit
git init

通过git init命令把D:/learngit目录变成Git可以管理的仓库,文件夹下将会产生一个.git文件夹

添加文件

touch index.php

查看状态

git status

我们对文件的各种操作新建、编辑(写代码)都是在工作区完成的,但是工作区的文件还是不被Git所管理的,Git会告诉你index.php是未被追踪的文件,需要执行git add 文件名把index.php提交到暂存区以便纳入到Git版本管理中来。

在git中,文件的状态有4种:Untracked(未跟踪)、Staged(暂存状态)、Unmodify(文件已经入库,未修改)、Modified(文件已修改)

  • Untracked: 未跟踪
    此文件在文件夹中, 但并没有加入到git库, 不参与版本控制。
  • Staged: 已暂存
    执行git add 将文件状态变为Staged。执行git rm –cached将文件状态变回Untracked。执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态.

  • Unmodify 文件已经入库, 未修改
    执行git commit将文件状态变为Unmodify. 这种类型的文件有两种去处, 如果它被修改, 则变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件

  • Modified: 文件已修改
    仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git restore 丢弃修改返回到unmodify状态。在git add后执行git reset HEAD filename取消暂存, 文件状态变回Modified

把文件存入暂存区

git add .

用命令git add告诉Git,把文件存入暂存区。
此时index.php文件的状态是已暂存

如果我们想把现在的暂存撤销,可以使用git rm --cached index.php命令来撤销,如果想提交到版本库,就再执行git commit操作就可以了。
如果add了多个文件,想一次性撤销,可以使用git rm --cached -r ././代表当前文件夹)

将暂存区的文件提交到版本库

git commit -m '说明'

提交后,此时index.php文件的状态是已提交

现在修改index.php文件,打开index.php,填写如下内容:

<?php
phpinfo();

此时查看状态可以看到index.php文件处于已修改状态:

index.php被修改后,可以把工作区修改的文件git add提交到暂存区,也可以使用git restore --staged index.php把暂存区的文件从暂存区撤出,然后使用git restore index.php把工作区的修改撤销,这样,文件就会回退到上一次提交时的状态。
如果有多个工作区的文件想撤销可以使用git restore ./
如果使用git commit提交了此次修改后,想回退至上一个版本,那么可以使用:

git reset --hard HEAD^

小结

初始化一个Git仓库,使用git init命令。

添加文件到Git仓库,分两步:

1、使用命令git add <file>,注意,可反复多次使用,添加多个文件;
2、使用命令git commit -m <message>,完成。

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git restore <file>
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>git restore --staged <file>,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,用命令git reset --hard HEAD^

版本回退

假如工作区中有一个test.txt文件,该文件的内容如下:

111
222
333
444

该文件一共提交了5次,第一次是提交了一个空的test.txt文件,后面4次,分别为提交了111、222、333、444这4行数字。
现在如果想回退到

111
222

这个版本,那么首先通过git log查看日志:

找到这个版本对应的版本号(commit id)。
然后执行:

git reset --hard db077

db077为版本号的前几位,没必要写全,前几位就可以了,Git会自动去找。
执行完以上命令后,打开test.txt文件,内容已恢复到111、222的版本。

此时如果想回退至111、222、333这个版本,该如何操作呢?
此时通过git log已经不能看到333、444这两个版本了:

也就意味你回退到了某个版本,又后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?
Git提供了一个命令git reflog用来记录你的每一次命令:

通过该命令可以查看到333这个版本的版本号了。

小结

HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id

穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

删除文件

直接在工作区中删除了文件,通过git status查看状态如下:

现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

git restore <file>

小结

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

远程仓库

添加远程库

如果你希望把你本地的git仓库同步到Github或GitLab上,那么就需要添加远程库。
首先在Github上新建一个learngit的库。
然后在本地关联远程库:

git remote add origin https://github.com/dedemao/learngit.git

如果是gitlab:

git remote add origin ssh://git@git.884358.com:211/884358/learngit.git

其中211是ssh的端口号(一般默认为22)

从远程仓库拉取

git pull origin main

推送到远程库

git push origin main

从远程库克隆

现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。

git clone https://github.com/dedemao/learngit.git

查看远程库信息

git remote -v

移除远程仓库

git remote remove origin

分支管理

查看分支

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>

删除远程分支:

git push origin --delete <name>

实战

1、创建并切换到dev分支

git switch -c dev

2、修改文件并提交
例如修改README.md文件内容

git add README.md
git commit -m "update README.md"

3、切换回main分支

git checkout main

4、把dev分支的工作成果合并到master分支上

git merge dev

5、删除dev分支

git branch -d dev

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

解决冲突

在合并分支时,可能会造成冲突,如图:

只需打开冲突文件,Git用<<<<<<<=======>>>>>>>标记出不同分支的内容,只需要根据标记修改后,重新提交即可。

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

git log --graph命令可以看到分支合并图。

分支管理策略

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

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

git merge --no-ff -m "merge with no-ff" dev

Bug分支

场景:当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交,并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

git stash

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug,假定需要在main分支上修复,就从main创建临时分支:

git switch main
git switch -c issue-101

修复bug后提交:

git add .
git commit -m "fix bug 101"

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

git switch main
git merge --no-ff -m "merged bug fix 101" issue-101

现在,是时候接着回到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
再用git stash list查看,就看不到任何stash内容了。

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

$ git stash apply stash@{0}

在master分支上修复了bug后,我们要想一想,dev分支是早期从main分支分出来的,所以,这个bug其实在当前dev分支上也存在。

那怎么在dev分支上修复同样的bug?重复操作一次,提交不就行了?

有木有更简单的方法?

有!

同样的bug,要在dev上修复,我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个main分支merge过来。

为了方便操作,Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支:

$ git branch
* dev
  master
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

Git自动给dev分支做了一次提交,注意这次提交的commit是1d4b803,它并不同于main的4c805e2,因为这两个commit只是改动相同,但确实是两个不同的commit。用git cherry-pick,我们就不需要在dev分支上手动再把修bug的过程重复一遍。

小结

修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;

当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场;

在main分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支,避免重复劳动。

多人协作

1、test用户克隆远程仓库

ssh://git@git.884358.com:211/884358/learngit.git

2、test用户创建本地dev分支

git switch -c dev origin/dev

3、在dev分支上提交代码

git add .
git commit -m "test commit"
git push origin dev

因此,多人协作的工作模式通常是这样:
首先,可以试图用git push origin <branch-name>推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
这就是多人协作的工作模式,一旦熟悉了,就非常简单。

小结

查看远程库信息,使用git remote -v
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git switch -c branch-name origin/branch-name,本地和远程分支的名称最好一致;
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

发表评论

邮箱地址不会被公开。 必填项已用*标注