19 min read

环境搭建 - Git

GIT作为分布式版本控制系统,在现代软件开发中扮演着至关重要的角色。本文将介绍如何搭建GIT开发环境,并探讨其在项目开发中的重要性以及一些技巧。通过正确配置和善用GIT,开发者能够轻松跟踪代码变更、协同工作、回滚修改,并且更好地管理项目的代码版本。了解GIT的基本原理和运用方法,将为开发人员提供更高效、可靠的开发流程,提升团队协作和代码质量。
环境搭建 - Git

GIT作为分布式版本控制系统,在现代软件开发中扮演着至关重要的角色。本文将介绍如何搭建GIT开发环境,并探讨其在项目开发中的重要性以及一些技巧。通过正确配置和善用GIT,开发者能够轻松跟踪代码变更、协同工作、回滚修改,并且更好地管理项目的代码版本。了解GIT的基本原理和运用方法,将为开发人员提供更高效、可靠的开发流程,提升团队协作和代码质量。

安装

Windows 

只需要到官网下载安装即可, https://git-scm.com/download/win

Linux

从源码编译 Git 允许你安装最新的 Git 版本,并且自定义一些构建选项。 不管怎么样,这样你就无法通过yum包管理器来维护你的 Git 安装过程了。

在 CentOS 上开始安装一些构建 Git 的必要依赖软件包

sudo yum groupinstall "Development Tools"
sudo yum install curl-devel expat-devel gettext-devel openssl-devel  perl-CPAN perl-devel zlib-devel

通过log版本检测是否安装成功:

 git --version
 >> git version 2.25.1

设置

查看config配置信息

git与npm一样具体多个位置的配置文件. 即:system级别, global(用户级别) 和local(当前仓库)三个。 配置级别的优先级是:Local > Global > System, 这意味着如果在本地级别进行了配置,它将覆盖全局和系统级别的相同配置。

#查看系统
config git config --system --list

#查看当前用户(global)配置 
git config --global --list

#查看当前仓库配置信息 
git config --local --list

更新Email/User

git config --global user.name "myname" 
git config --global user.email "test@gmail.com"

示例

一次简单的Git操作包括克隆,添加与提交更改,再到摘取与推送:

git clone <远程仓库URL>

git add <文件名>
git commit -m "提交消息"

git pull origin <分支名>
git push origin <分支名>

其中, 我们可查看上次提交后是否有修改 git status, 一般配合 git status 使用  git diff 查看详细改动.

git add是将快照内容写入缓存区, 它有三个参数:

  • git add -A表示添加所有内容 
  • git add . 表示添加新文件和编辑过的文件不包括删除的文件
  • git add -u 表示添加编辑或者删除的文件,不包括新添加的文件 

执行 git commit 将缓存区内容添加到本地仓库中, 使用 -m 选择提交注释 git commit, 将对应分支推送到远程仓库 git push.

应用

代理

为使用 http/https 协议的 git 配置代理

git config --global http.proxy 'socks5://127.0.0.1:9999'
git config --global https.proxy 'socks5://127.0.0.1:9999'

删除代理

git config --global --unset http.proxy
git config --global --unset https.proxy
npm config delete proxy

SSH config

为 ssh 客户端或者使用 ssh 协议的 git 配置代理 在你用户目录下,建立 .ssh/config,在里面添加如下配置:

# 将这里的 User、Hostname、Port 替换成你需要用 ssh 登录的服务器的配置。
# Host 可以认为像是书签一样的东西,当你用 Host 指明的字符串代替你服务器的 IP/域名 时,
# 便会应用该节点下的配置。当然你也可以将 Host 和 Hostname 设置成一样。
Host yourserver.com
        User    someone
        Hostname        yourserver.com
        Port    22
        Proxycommand    /usr/bin/ncat --proxy 127.0.0.1:9999 --proxy-type socks5 %h %p

# 如果是给某同性社交网站用的(走 ssh 协议),可以直接使用该配置。
# 其它类似网站的话,替换掉域名( Host/Hostname)即可。
# 可以看出,ssh 协议的 git 客户端,配置与 ssh 一模一样。
# 需要注意的是这里的 User 应该是 git,而不是你在该网站上注册的用户名。
# (虽然有些提供 git 仓库托管的网站会用其它用户名,这种情况根据网站配置。)
Host github.com
        User    git
        Hostname        github.com
        Port    22
        Proxycommand    /usr/bin/ncat --proxy 127.0.0.1:9999 --proxy-type socks5 %h %p

命令分类

根据功能和用途,我们可以将Git命令分为以下五个主要类别

基本操作:

  • git add:将文件或更改添加到暂存区。
  • git commit:将暂存区的更改提交到版本库。
  • git status:查看工作区和暂存区的状态。
  • git rm:从工作区和版本库中删除文件。
  • git init:初始化一个新的Git仓库。

分支与合并:

  • git branch:管理分支,包括创建、列出和删除分支。
  • git merge:将一个分支的更改合并到另一个分支。
  • git stash:将当前的工作进度保存到一个新的存储栈中。
  • git cherry-pick:选择一个或多个提交并将其应用到当前分支。

远程操作:

  • git pull:从远程仓库获取最新的更改并合并到本地仓库。
  • git push:将本地的更改推送到远程仓库。
  • git clone:克隆远程仓库到本地。
  • git remote:管理与远程仓库的连接。

查询与比较:

  • git log:查看提交日志。
  • git diff:比较文件或提交之间的差异。
  • git tag:标记特定的提交。
  • git fetch:从远程仓库获取最新的提交,但不合并到本地分支。

配置与管理:

  • git reset:重置当前分支到指定的提交。
  • git config:配置Git的全局或仓库级别的设置。
  • git remote:管理与远程仓库的连接。
  • git rebase:将一个分支的更改应用到另一个分支。

常用技巧

获取远程tag

git fetch --tags -f

刷新分支

git remote update origin --prune

删除远程不存在的分支

git fetch --prune origin    #带fetch后的prune
git remote prune origin		# 仅prune	

删除冗余tag

git fetch --prune --prune-tags

下载并跟踪所有分支

for branch in $(git branch --all | grep '^\s*remotes' | egrep --invert-match '(:?HEAD|master)$'); do
    git branch --track "${branch##*/}" "$branch"
done

回退

查找历史版本 

git log 

恢复到历史版本 

git reset --hard fae6966548e3ae76cfa7f38a461c438cf75ba965

将改动强制推送

git push -f -u origin master

保存用户名密码

设置记住密码(默认15分钟):

git config --global credential.helper cache git config credential.helper cache

手动设置, 这样就设置一个小时之后失效:

git config credential.helper 'cache --timeout=3600'

长期存储密码:

git config --global credential.helper store git config credential.helper store

增加远程地址的时候带上密码也是可以的(推荐)

http://yourname:password@git.oschina.net/name/project.git

git push 超过100M解决办法

git config http.postBuffer 524288000(500M)

常用操作

创建 | CREATE

$ git clone ssh://user@domain.com/xx.git 克隆远程仓库 
$ git init 初始化本地 git 仓库(新建仓库)

修改远程仓库地址

git remote set-url origin [url]

先删除再修改地址

git remote rm origin git remote add origin [url]

本地更改 | LOCAL CHANGES

$ git status 查看当前版本状态(是否修改) 
$ git diff 显示所有未添加至 index 的变更 
$ git diff HEAD 查看已缓存的与未缓存的所有改动 
$ git add <path> 将该文件添加到缓存 
$ git commit -m ‘xxx’ 提交 
$ git commit --amend -m ‘xxx’ 合并上一次提交(用于反复修改) 
$ git commit -am ‘xxx’ 将 add 和 commit 合为一步

提交历史记录 | COMMIT HISTORY

$ git log 显示日志 
$ git show <commit> 显示某个提交的详细内容 
$ git blame <file> 在每一行显示 commit 号,提交者,最早提交日期

分支机构和标签 | BRANCHES & TAGS

$ git branch 显示本地分支 
$ git checkout <branch> 切换分支 
$ git branch <new-branch> 新建分支 
$ git branch --track <new> <remote> 创建新分支跟踪远程分支 
$ git branch -d <branch> 删除本地分支
$ git tag <tag-name> 给当前分支打标签

更新和发布 | UPDATE & PUBLISH

$ git remote -v 列出远程分支详细信息 
$ git remote show <remote> 显示某个分支信息 
$ git remote add <remote> <url> 添加一个新的远程仓库 
$ git fetch <remote> 获取远程分支,但不更新本地分支,另需 merge 
$ git pull <remote> <branch> 获取远程分支,并更新本地分支 
$ git push <remote> <branch> 推送本地更新到远程分支 
$ git push <remote> --delete <branch> 删除一个远程分支 
$ git push --tags 推送本地标签

合并与衍合 | MERGE & REBASE

$ git merge <branch> 合并分支到当前分支,存在两个 
$ git rebase <branch> 合并分支到当前分支,存在一个 
$ git rebase --abort 回到执行 rebase 之前 
$ git rebase --continue 解决矛盾后继续执行 rebase 
$ git mergetool 使用 mergetool 解决冲突 
$ git add <resolve-file> 使用冲突文件解决冲突 
$ git rm <resolved-file>

撤消 | UNDO

$ git reset --hard HEAD 		将当前版本重置为 HEAD(用于 merge 失败) (改过的代码就没) 
$ git reset --hard <commit> 	将当前版本重置至某一个提交状态(慎用!) 
$ git reset <commit> 			将当前版本重置至某一个提交状态,代码不变 
$ git reset --merge <commit> 	重置至某一状态,保留版本库中不同的文件 
$ git reset --keep <commit> 	重置至某一状态,重置变化的文件,代码改变 
$ git checkout HEAD <file> 		丢弃本地更改信息并将其存入特定文件 
$ git revert <commit> 			撤消提交 
$ git reset --mixed 			(版本库和暂存区都将进行了代码回退,工作区代码没动,保留修改)

帮助 | HELP帮助 | HELP

$ git help <command> #获取命令行上的帮助

Rebase

git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>] [<upstream> [<branch>]] 
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>] --root [<branch>] 
git rebase --continue | --skip | --abort | --quit | --edit-todo | --show-current-patch

Rebase参数解析:

  • --onto <newbase>: newbase指的是需要rebase代码的起点,newbase可以是分支(branch),也可以是任意的提交记录(commit1)。rebase成功后,将以newbase为代码分支起点。
  • <upstream>: 需要与newbase比对的分支或提交记录。
  • <branch>:需要rebase的工作分支。默认为HEAD,例如dev1
  • --continue: 当处理完冲突后,可以使用该命令让rebase继续。
  • --abort: 终止rebase操作,将HEAD设置为rebase之前的分支。如果指定了<branch>,则HEAD将重置为<branch>。否则,HEAD将被重置为rebase之前的分支。
  • --quit: 终止rebase操作,但不会将HEAD重置为原来的分支。index和working tree将不会发生任何改变。
  • --autostash: 在rebase操作之前自动stash当前分支未提交的代码,在rebase操作结束后,自动将stash的记录进行unstash,并与rebase后的代码合并。注意,此操作有可能会导致严重的冲突(conflict),谨慎使用。
  • --merge: 进行rebase操作的时候,同时使用merge进行代码合并。需要注意的是,在进行rebase merge产生冲突的时候,ours为<upstream>指定的分支,theirs为<branch>指定的分支。原因是,rebase merge work的工作原理为,将<branch>上的所有提交记录在<upstream>分支上进行重提交。

例子:

git checkout dev git rebase origin git rebase --continue

rebase/merge区别

git rebasegit merge是Git中用于合并分支的两种不同方法,它们具有一些区别:

Commit历史记录:

  • git merge会创建一个新的合并提交,将两个分支的历史记录保留下来,形成一个新的合并节点。
  • git rebase会将当前分支的提交应用到目标分支上,重新生成一系列新的提交,形成一个线性的提交历史。

分支合并视图:

  • git merge会保留分支合并的结构,即保留两个分支的独立性,生成一个合并的提交节点。
  • git rebase会将当前分支的提交移动到目标分支之后,使得分支合并看起来更加线性,没有合并提交节点。

历史记录的清晰度:

  • git merge会保留分支的完整历史记录,每个分支的提交都会被保留下来,保持了分支之间的关系清晰可见。
  • git rebase会将当前分支的提交重新应用到目标分支上,可以使提交历史更加简洁、清晰,但可能会丢失一些分支的详细历史信息。

冲突解决:

  • git merge在合并过程中,如果存在冲突,会生成一个合并冲突的状态,需要手动解决冲突并进行提交。
  • git rebase在应用每个提交时,如果存在冲突,需要解决冲突并使用git rebase --continue命令继续应用提交。

选择使用git merge还是git rebase取决于项目和个人偏好。通常,使用git merge更适合保留分支独立性和清晰的历史记录,而使用git rebase则更适合创建线性的提交历史和简洁的合并视图。然而,需要注意的是,git rebase应该避免在公共分支上进行,因为它会改变提交历史,可能导致其他开发者的困惑和冲突。

保存凭据

使用以下命令来保存凭据(用户名和密码)

git config --global credential.helper store

当你首次使用git pushgit pull等命令时,Git会提示你输入用户名和密码,并将它们保存在本地的凭据存储中。以后的操作将自动使用保存的凭据进行身份验证。另外可手动设置缓存时间, 单位timeout为秒

git config credential.helper 'cache --timeout=<timeout>'

不带merge的Pull  

git pull --rebase

Git merge --no-ff

在许多介绍 Git 工作流的文章里,都会推荐在合并分支时,加上 --no-ff 参数:

$ git checkout develop $ git merge --no-ff feature

--no-ff 在这的作用是禁止快进式合并。

Git 合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward),比如下图

A---B---C feature / D---E---F master

要把 feature 合并到 master 中,执行以下命令

$ git checkout master $ git merge feature

结果就会变成

A---B---C feature / master D---E---F

因为 feature 就在 master 的下游,所以直接移动了 master 的指针,master 和 feature 都指向了 C。而如果执行了 git merge --no-ff feature 的话,是下面的结果:

A---B---C feature / \ D---E---F-----------G master

由于 --no-ff 禁止了快进,所以会生成一个新的提交,master 指向 G。

从合并后的代码来看,结果其实是一样的,区别就在于 --no-ff 会让 Git 生成一个新的提交对象。为什么要这样?通常我们把 master 作为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 feature 是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master 的提交历史。所以如果你根本不在意提交历史,也不爱管 master 干不干净,那么 --no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,比如上例,你就会发现退一个版本到了 B,而不是想要的 F,因为 feature 的历史合并进了 master 里。

交互式变基合并

查看提交历史 git log

要知道自己想合并的是哪几个提交,可以使用git log命令来查看提交历史,(历史记录是按照时间排序的,时间近的排在前面) , 假如最近4条历史如下:

commit 3ca6ec340edc66df13423f36f52919dfa3...... 
commit 1b4056686d1b494a5c86757f9eaed844...... 
commit 53f244ac8730d33b353bee3b24210b07...... 
commit 3a4226b4a0b6fa68783b07f1cee7b688.......

git rebase

想要合并1-3条有两个方法

1.从HEAD版本开始往过去数3个版本

git rebase -i HEAD~3

2.指名要合并的版本之前的版本号

git rebase -i 3a4226b

请注意3a4226b这个版本是不参与合并的,可以把它当做一个坐标

选取要合并的提交

1.执行了rebase命令之后,会弹出一个窗口,头几行如下:

pick 3ca6ec3 '注释**********' pick 1b40566 '注释*********' pick 53f244a '注释**********'

2.将pick改为squash或者s,之后保存并关闭文本编辑窗口即可。改完之后文本内容如下:

pick 3ca6ec3 '注释**********' s 1b40566 '注释*********' s 53f244a '注释**********'

3.然后保存退出,Git会压缩提交历史,如果有冲突,需要修改,修改的时候要注意,保留最新的历史,不然我们的修改就丢弃了。修改以后要记得敲下面的命令:

git add . git rebase --continue

如果你想放弃这次压缩的话,执行以下命令:

git rebase --abort

4.如果没有冲突,或者冲突已经解决,则会出现如下的编辑窗口:

# This is a combination of 4 commits. #The first commit’s message is: 注释...... # The 2nd commit’s message is: 注释...... # The 3rd commit’s message is: 注释...... # Please enter the commit message for your changes. Lines starting # with ‘#’ will be ignored, and an empty message aborts the commit.

5.输入wq保存并推出, 再次输入git log查看 commit 历史信息,你会发现这两个 commit 已经合并了。

git 遴选(cherry-pick)

git cherry-pick 命令,也叫 遴选 或者 摘取,目的是把一个分支里面的某次提交,合并到另一个分支里面。

以TortoiseGit为例,叫摘取。

比如说有两个分支:1 分支和 2分支。

我在1分支上,修改了内容,备注为“1测试”,然后提交并推送到远端了。之后又有很多次的提交。

但是我只想把“1测试” 这个提交,合并到 2分支上,要怎么操作呢。

  1. 先切换到2分支,拉取最新代码。
  2. 右击 -> 显示日志
  3. 在日志信息界面,点左上角的分支名称,切换到 remotes/origin/1分支 ,双击进入
  4. 在日志信息界面上,选择 备注为 “1测试” 的那次提交记录
  5. 右击->摘取此提交,进入摘取界面,选中记录,点继续,则合并到2分支中了。
  6. 推送2分支到远端

 

Git的开发模式

Trunk-based开发和Git Flow是两种常见的代码版本管理和分支管理策略,它们之间存在一些区别:

 分支模型:

  • Trunk-based开发:Trunk-based开发采用主干(trunk)为主要开发分支,所有开发者在同一个主干上进行工作。一般情况下,只有一个主要的长期分支(通常是主分支或者开发分支)。
  • Git Flow:Git Flow采用分支模型,包括主分支(master)和开发分支(develop),以及用于特性开发、修复bug、发布版本等的各种辅助分支。

分支生命周期:

  • Trunk-based开发:Trunk-based开发中的特性分支(feature branch)通常只存在很短的时间,一旦开发完成并通过测试,就会尽快合并到主干中。
  • Git Flow:Git Flow中的特性分支和其他类型的分支可以存在较长时间,不断进行开发、测试和合并。每个分支都有明确定义的目的和生命周期。

上线频率:

  • Trunk-based开发:Trunk-based开发鼓励频繁的集成和部署,使得新功能和修复能够快速上线。
  • Git Flow:Git Flow通常倾向于较长的发布周期,通过发布分支(release branch)和预发布环境进行稳定性测试,以确保代码的可靠性和稳定性。

管理复杂性:

  • Trunk-based开发:Trunk-based开发简化了分支管理,减少了分支间的冲突和合并问题,适用于较小规模的团队或者较简单的项目。
  • Git Flow:Git Flow提供了更多的分支和工作流选项,适用于较大规模的团队或者复杂的项目,可以更好地管理多个功能并行开发、版本发布等。

总体而言,Trunk-based开发适合追求快速交付、持续集成和部署的团队,适用于小型和敏捷的项目。Git Flow适合有较长的发布周期、稳定性和版本管理要求的团队,适用于较大规模和复杂的项目。选择适合自己团队和项目需求的开发模型是关键,也可以根据具体情况结合使用两种策略的元素。

trunk-based.jpg
Trunk-Based
git-flow.jpg
Git-flow

 

资料

https://docs.github.com/zh