Ubuntu---Git

本篇文章简单总结了常用 Git 的使用

前言

设置用户信息

1, Git 是分布式的 SSH 代码管理工具,远程的代码管理是基于 SSH 的,所以要使用远程的 Git 则需要 SSH 的配置。

step 1: 设置 Git 用户的 name 和 email:

$ git config --global user.name "peng.zhang"
$ git config --global user.email "peng.zhang@yeah.net"

生成 SSH 密钥对

step 2: 生成 ssh 密钥:

# Ubuntu 默认已安装了 git 和 ssh
# 进入家目录下的隐藏文件夹 .ssh 下
$ cd ~/.ssh

# 生成公私钥对
# 生成的公私钥对名称分别为:公钥:id_rsa 私钥:id_rsa.pub,如果不是,则用 mv 命令重命名即可 $
ssh-keygen

加入 SSH 公钥到远端仓库(Repo)

step 3: 登录 github 账户,然后把生成的公钥加入到 github 账户下的 SSH 公钥列表中,即可对github 进行 ssh 访问了

# 测试是否能连接到 git 账户
$ git clone git@github.com:ssezhangpeng/script-to-chouti.git

 git 操作

初始化 git 仓库

  method1:自己在本地创建一个空仓库

  method2:从远程 clone 一个仓库到本地

# 创建一个空文件夹作为仓库
$ mkdir git

# 进入空文件夹,初始化该仓库
$ cd git
$ git init

加入文件到工作区(Work Directory),此时未 add 进 暂存区(Stage)

# 加入新文件到仓库
<~git>$ mkdir dir1 dir2 dir3
<~git>$ vim dir1/main.cpp
<~git>$ vim dir2/logic.cpp
<~git>$ vim dir3/logs.txt

# 此时用 git status 看一下,发现是
# status: Untracked

add 文件到暂存区(Stage)

# add 文件到 Stage 区
# . 表示本目录下的所有文件
<~git>$ git add .

# 此时用 git status 看一下,发现是 
# status: changes to be commit 
<~git>$ git status

# 此时如果想要撤回 add 的文件
# stage---> unstage
<~git>$ git rm --cached file-name

commit 文件到本地仓库分支(Repo)

$ 提交暂存区所有文件到本地仓库
<~git>$ git commit -m "version 0.1"此时如果想要撤回 add 的文件

# 此时用 git status 看一下,发现是
# status: nothing to commit, working tree clean

# 此时如果想要撤回 commit 的文件
暂时还没整理好,待续...

commit 后继续修改原文件

# 继续开发新功能,修改了 dir1/main.cpp 
<~git>$ vim dir1/main.cpp

# 此时用 git status 看一下,发现是
# status: modified:   dir1/main.cpp

# ===============如果想要更新该文件===============
<~git>$ git add dir1/main.cpp
# add 之后如果想要撤销此次 add 进的文件
<~git>$ git reset HEAD dir1/main.cpp
# 此时可以用 git status 看一下,发现回到了修改后未 add 的状态,此时可以用 add / checkout -- file-name 来决定是否要更新/忽略此次修改
# ====================END======================
# 如果想要忽略此次修改,将修改后的文件恢复到未修改之前的状态,像修改文件后没有保存直接退出的操作 
<~git>$ git checkout -- dir1/main.cpp

# 如果想要看一下修改的内容是什么
# 查看当前工作区和暂存区的不同,当然 git diff 还有其它功能,后面有补充
<~git>$ git diff

 补充:时刻用 git diff 来查看不同之处

# git diff 的强大之处
# ==========[1]工作区 VS 暂存区===========
#
如果还没 add 进暂存区,则查看文件自身修改前后的差别 $ git
diff <file-name>

# 查看与工作区与另一分支的区别
$ git diff <branch> <file-name>

# ==========[2]暂存区 VS Git仓库==========
# 查看已经 add 进暂存区但是尚未 commit 的内容同最新一次 commit 的内容的差异
# git diff --cached <file-name>

# 上述可以指定 commit 的版本
$ git diff --cached <commit-ID> <file-name>

# ==========[3]工作目录 VS Git仓库==========
# 查看工作目录同 Git仓库指定的 commit 的内容差异,当 commit-ID = HEAD 时,查看同最近一次 commit 的内容差异
$ git diff <commit-ID> <file-name>

# ==========[4]Git 仓库 VS Git仓库==========
# Git 库任意两次 commit 的差别
$ git diff <commit-ID> <commit-ID>

注1:以上命令均可以不指定 <file-name>,此时对全部文件操作

注2:以上涉及和 Git 仓库进行对比的,均可以指定 commit 的版本(HEAD、HEAD^ ,HEAD~100 等命令可指定)

版本回退

=======前言===========
# 用来显示从近到远的 commit 日志
$ git log

# 用来记录每一次命令
$ git reflog

# 移动到任意一个版本[版本穿梭]
git reset --hard <commit-ID>

========版本回退========
# 想回到上一个版本
$ git reset --hard HEAD^
# 回到未来的版本:通过 git reflog 找到未来的 commit-ID
$ git reset --hard <commit-ID>

删除文件

# 删除文件也是一个修改操作
# 我们先加一个文件
$ git add test.txt
$ git commit -m "add test.txt"

#============删除文件========
# 一般情况下,通常在工作区直接把文件删除了
$ rm -r test.txt

# 此时 Git 知道你删除了文件,此时工作区和版本库就不一致了
# 用 git status 看一下: Changes not staged for commit [delete:test.txt]

# 1,如果你确实要从版本库中删除该文件
$ git rm -r  test.txt
$ git commit -m "remove test.txt"

# 2,如果你是删除错了,因为版本库中还有,所以可以恢复到版本库中的最新版本
$ git checkout -- test.txt

 分支操作

#============创建分支============
# 在本地 master分支下创建并切换到新分支 dev [note:如果想在dev分支下创建新分支,首先切换到 dev 分支,然后再执行下述命令]
$ git checkout -b dev
# 等价于下面两条命令
$ git branch dev
$ git checkout dev

# 创建远程分支
# 当我们在本地创建了新分支之后,直接推送到远端,此时远端就会生成一个同名分支
$ git push origin dev

#============删除分支============
# 删除本地分支 dev
$ git branch -d dev
# 强制删除
$ git branch -D dev
# 删除远端分支 dev 
$ git push origin
--delete dev

注:删除该分支之前必须要切换到其它分支,然后再执行删除操作

合并操作

# 本地合并操作
# 合并指定分支到当前分支,当前分支在 master 上
$ git merge dev

解决冲突

# 当进行合并操作时,如果两个要合并的分支内容不同,则产生冲突,因为 git 当前分支不知
# 道我是继续保留我自己的分支,还是要换成指定分支的内容,需要用户手动解决冲突

# 例如 master 分支内容为:
to test conflict!
# feature1 分支内容为:
TO TEST CONFLICT!

# 我们想要把 dev 分支上的内容合并到 master 上
# 执行下面命令后会出现错误提示: Merge conflict in readme.txt(冲突文件名)
$ git merge feature1

# 此时我们用 vim 打开冲突的文件,进行手动编辑决定保留哪一个
# 此时冲突文件中:
# <<<<<<<<<HEAD :表示 master 冲突文件中不同的内容
# >>>>>>>>> dev : 表示指定合并的分支的冲突文件中不同的内容
# 并用 ==============来分割两个不同的分支的内容

# 解决冲突后可以重新进行合并操作,但是注意也要重新 add 文件
$ git add readme.txt
$ git commit -m "fixed conflict"

此时查看分支的合并情况:

$ git log --graph --pretty=oneline --abbrev-commit

Rebase 合并提交历史记录

  当多人在一个分支上协同工作时,很容易出现冲突。即使没有冲突,后 push 的同学不得不先 pull ,在本地合并,然后才能 push 成功。每次合并再 push 后,分支就会变成下图那样:

  那能不能使 Git 的提交历史是一条干净的直线?当然可以,这就是 Rebase 的作用。

# 首先我们在本地分支 master 上添加新文件 helo.py,内容为 # Author:peng.zhang
# 然后 add , commit
$ git add hello.py
$ git commit -m ".py file add Author"

# 此时用 git status 看一下发现当前分支提前 origin/master 一个提交
# 然后我们在 github 上修改 README.md 文件,然后直接在页面上 commit,以此模拟其它同学的提交操作
# 然后我们推送我们的修改到远端
# 此时发生错误:updates were rejected because...,这说明有人先于我们推送了远程分支
$ git push origin master

# 按照经验,先 pull 一下
# 提示:Merge made by the ‘recursive’ strategy
# pull 中包含 merge 操作,没有发生冲突,因为我们只是增加了文件,没有修改其它相同文件
# 如果发生了冲突,则需要先 fetch 到本地,然后手动解决冲突,再执行 merge 操作
$ git pull 

此时我们看一下 commit 历史记录:

$ git log --graph --pretty=oneline --abbrev-commit

可以看到,此时历史提交记录已经分叉了,我们用 rebase 试试看结果是什么?

$ git rebash

此时,我们再看一下历史提交记录

我们可以发现历史提交记录变成了一条直线,我们仔细看可以发现变化的是什么?其实就是 Git 把本地的提交移动了位置,相当于[先从本地执行 pull 操作,然后再在本地做修改,接着再提交修改]的顺序执行,把一个并行操作转换为一个顺序执行的操作,这样就不会发生任何冲突,所以也就不需要进行合并操作,即历史记录不会有分支。

开发过程中所用到的一些操作

git fetch

  当我们在自己的分支进行开发时,别的同事可能已经对 master 分支进行过合并操作,我们需要取回远端 master 分支上我们本地没有的内容,然后再进行本地和远程分支的合并操作,之后 push 到远端。

# git fetch 可以从远端仓库获取到最新版本到本地
# 将远程主机的更新全部取回本地,git fetch 获取所有分支的更新
$ git fetch

# 取回特定分支的更新,可以指定分支名称
$ git fetch origin master

#当取回远程主机的更新以后,可以执行合并操作,在本地分支上合并远程分支,当然,此时可能会发生冲突,需要手动解决冲突
# 在当前分支上合并 origin/master
$ git merge origin/master

注:具体图示见文末参考资料链接[1]

git stash

  当我们在自己的分支进行开发工作时,此时有一个 Bug 需要我们紧急修复,我们没有办法先把我们的开发工作提交,因为该工作还没完成,这是我们就可以用打 stash 命令了。这条命令会把当前个工作现场“储存起来”,等以后恢复现场后继续工作。

# 存储现场
$ git stash

# 此时用 git status 看一下工作区,发现是干净的
========修复 Bug=========
# 如果我们要在 master 分支上修复 issue
$ git checkout master
$ git checkout -b issue-101
$ vim bug-file 进行修复
$ git add bug-file
$ git commit -m "fixed issue-101"
# 切换回 master 分支,完成合并
$ git checkout master
$ git merge --no-ff -m "merged bug fix issue-101"

=======恢复现场=======
# 查看保存的工作现场
$ git stash list

#恢复现场方法1:该方法不会删除保存的工作现场,需要用 git stash drop 来删除
$ git stash apply

# 恢复现场方法2:恢复的同时也把 stash 给删除了
$ git stash pop

===========多次 stash========
# 恢复的时候,先用 git stash list 查看,然后恢复指定的 stash
$ git stash apply stash@{0}

===========清空 stash========
#如果有多个 stash 队列,下面命令会清空所有 stash 队列
$ git stash clear

多人协作

  在工作中,我们都会往 master 和 dev 分支上推送各自的修改,当我们从远程库 clone 时,默认情况下,只能看到本地的 master 分支,当我们要在 dev 分支上进行开发时,就必须创建远程的 dev 分支到本地(现实情况是 master 是稳定分支,dev 是开发分支,我们再建立每个人自己的开发分支,比如我的分支名称为: from_zhangpeng,然后不断往 dev 分支上进行何合并,由管理员合并 dev 分支到 master 分支)

# 建立自己的分支 dev
# 下行命令可以自动追踪 dev 分支[此时远程的 dev 分支必须已存在]
$ git checkout -b dev  origin/dev

# 不自动追踪 dev 分支
$ git checkout -b dev

# 不断进行修改,时不时把本地 dev 分支推送到远程 dev 分支
# 如果已建立追踪,则可以忽略分支名称
$ git push origin dev

 git 相关配置

gitconfig 相关配置

# ===========配置用户名和密码============
$ git config --global user.name "peng.zhang"
$ git config --global user.email "peng.zhang@yeah.net"

# 如果希望在不同的项目中使用不同的 user.name 和 user.email,可在该项目中运行:
$ git config user.name "peng.zhang"
$ git config user.email "peng.zhang@yeah.net"

# ===========配置默认编辑器============
$ git config --global core.editor vim

# ===========配置默认比较工具============
$ git config --global merge.tool vimdiff

# ===========检查配置============
$ git config --list

# ===========添加配置项============
# 默认为 local 范围修改
$ git config [--local | --global | --system ] --add site.name yiibai 

# ===========删除配置项============
$ git config --local --unset set.name

# ===========获取帮助============
$ git help config

 参考资料

[1] https://git-scm.com/book/zh-tw/v1

[2] https://www.liaoxuefeng.com/wiki/896043488029600

[3] https://www.yiibai.com/git/git-quick-start.html

 

posted on 2019-06-28 16:21  爱笑的张飞  阅读(279)  评论(0编辑  收藏  举报

导航