Git版本控制管理 总结

CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统

先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。

分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。

CVS作为最早的开源而且免费的集中式版本控制系统,直到现在还有不少人在用。由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。

Git是一款免费、开源的分布式版本控制系统,

项目管理适合 SVN, 代码管理适合 Git

当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:

git config --global user.name "xxx"
git config --global user.email xxx@xxx.com
git cofnig --list 显示所有配置
git config --global color.ui true 让Git显示颜色,会让命令输出看起来更醒目

基础命令

  • pwd 显示当前目录
  • git reflog 用来记录你的每一次命令
  • git log 命令显示从最近到最远的提交日志
    git log --pretty=oneline 简化日志信息
    git log --graph 命令可以看到分支合并图
    一大串类似 3628164...882e1e0 的是commit id(版本号),是一个SHA1计算出来的一个非常大的数字,用十六进制表示

远程仓库

远程仓库的默认名称是origin
克隆仓库

  • git clone git@github.com:xxx/xxx.git 克隆仓库到本地
  • git push origin master 把本地分支的最新修改推送远程

本地新建仓库

  • git init 使用当前目录作为Git仓库
  • git remote add origin git@github.com:xxx/xxx.git 把一个已有的本地仓库关联一个远程库
  • git push -u origin master 把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来
  • git push origin master 从本地推送到远程分支,如果推送失败,先用 git pull origin master 抓取远程的新提交

其他

  • git remote -v 查看远程库信息,显示了可以抓取和推送的origin的地址

分支

Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

  • git branch [-a] 会列出所有分支,当前分支前面会标一个*号。
  • git branch dev 在当前分支基础上创建 dev 分支
  • git checkout dev 切换到 dev 分支
  • git checkout -b dev 在当前分支基础上创建并切换到dev分支 相当于 git branch devgit checkout dev 2个命令
  • git branch -d dev 删除dev分支
  • git branch -D dev 强制删除dev分支

合并分支 merge

  • git merge dev 用于合并 dev 到当前分支
  • git merge --no-ff -m "merge with no-ff" dev 其中 --no-ff 表示禁用Fast forward 本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

临时储藏 stash

  • git stash 可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
  • git stash list 查看工作现场
  • 恢复
    • git stash apply,恢复后,stash内容并不删除,你需要用git stash drop来删除
    • git stash pop,恢复的同时把stash内容也删了

远程分支

  • git fetch [branch-name] 取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名,将某个远程主机的更新,全部取回本地
  • git checkout -b branch-name origin/branch-name 在本地创建和远程分支对应的分支,本地和远程分支的名称最好一致
  • git branch --set-upstream branch-name origin/branch-name 建立本地分支和远程分支的关联

标签管理

Git 标签 tag 就是一个让人容易记住的有意义的名字,它就是指向某个commit的指针

  • git tag 查看所有标签,标签不是按时间顺序列出,而是按字母排序的
  • git show <tagname> 查看标签信息
  • git tag <name> [commit id] 就可以打一个新标签,默认标签是打在最新提交的commit上
  • git tag -a v0.1.0 -m "release 0.1.0 version" 打一个有描述信息的标签
  • git push origin <tagname> 推送某个标签到远程
  • git push origin --tags 一次性推送全部尚未推送到远程的本地标签
  • git tag -d <tagname> 可以删除一个本地标签
  • git push origin :refs/tags/<tagname> 可以删除一个远程标签。
  • git push origin --delete tag <tagname> 可以删除一个远程标签。

如果标签已经推送到远程,要删除远程标签,先从本地删除: git tag -d v0.9 然后,从远程删除: git push origin :refs/tags/v0.9

gitignore 忽略特殊文件

github/gitignore

  1. cd 项目根目录
  2. touch .gitignore 在文件夹就生成了一个.gitignore文件
  3. 编辑
  4. 提交到Git

GitHub下fork后同步源的更新

  • git remote -v 查看,如果没有原作者的源
  • git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git 添加原作者源
  • git fetch upstream
  • git checkout master
  • git merge upstream/master
  • git push origin master

Submodule 子模块

常用命令

1
2
3
4
5
git clone <repository> --recursive 递归的方式克隆整个项目
git submodule add <repository> <path> 添加子模块
git submodule init 初始化子模块
git submodule update 更新子模块
git submodule foreach git pull 拉取所有子模块

克隆带子模块的版本库

初始化 submodule

初始化只需要做一次,之后每次只需要直接update就可以了,需要注意submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。

  1. clone父项目 git clone xxxx.git
  2. 初始化submodule git submodule init
  3. 最后更新submodule git submodule update

递归 clone

采用递归参数 --recursive 需要注意同样submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。
git clone xxxx.git --recursive

日常使用

  • git clone git地址 克隆远程仓库到当前位置
  • git status 查看文件状态(显示变更的文件)
  • git diff 对比文件差异
  • git add . 添加所有文件, 实际上就是把要提交的所有修改放到暂存区(Stage)
  • git commit -m '本次提交的说明' 把暂存区的所有内容提交到当前分支
  • git pull origin master 同步文件
  • git push origin master 推送文件

使用 rebase 合并多次 commit

查看记录 git log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
commit fc595c13010b4267e422de385febe1223796ca35 (HEAD -> dev)
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:20:03 2019 +0800

4

commit b7c2a6d34f97810f0b46445a13462a0b3725645f
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:18:24 2019 +0800

3

commit 405f54dbf7c57b9a5356ce01b4ea59ea60892657
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:18:03 2019 +0800

2

commit 0511f5c357d924179d8c1566a34aa9e578ff338d
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:17:50 2019 +0800

1

git rebase -i 0511f5c357 将 2 / 3 / 4 合并 为 5, -i 的参数是不需要合并的 1 的 hash 值(0511f5c357d924179d8c1566a34aa9e578ff338d)

进入 vi 窗口
pick 的意思是要会执行这个 commit
squash 的意思是这个 commit 会被合并到前一个commit
除第一个 pick 外, 将其他的 pick 改为 s / squash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
pick 405f54d 2
pick b7c2a6d 3
pick fc595c1 4

# Rebase 0511f5c..fc595c1 onto 0511f5c (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# 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 405f54d 2
squash b7c2a6d 3
squash fc595c1 4

#...

保存退出(:wq)后进入 commit 窗口, 填写 commit 注释保存退出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# This is a combination of 3 commits.
# This is the 1st commit message:

2

# This is the commit message #2:

3

# This is the commit message #3:

4

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Thu Feb 14 11:18:03 2019 +0800
#
# interactive rebase in progress; onto 0511f5c
# Last commands done (3 commands done):
# squash b7c2a6d 3
# squash fc595c1 4
# No commands remaining.
# You are currently rebasing branch 'dev' on '0511f5c'.
#
# Changes to be committed:
# modified: demo/AppDelegate.swift
#

再次查看 log

1
2
3
4
5
6
7
8
9
10
11
commit 9f077d1de022062381e8ada7774adf73c13dc329 (HEAD -> dev)
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:18:03 2019 +0800

This is a combination of 3 commits.

commit 0511f5c357d924179d8c1566a34aa9e578ff338d
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:17:50 2019 +0800

1

如果需要强制推送远程仓库使用 git push --force

删除 某一次 commit

查看 log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
commit 71b4cd9c932ed421c6a0446ab47aaf2246c79ff3 (HEAD -> dev)
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:58:48 2019 +0800

6

commit 9f077d1de022062381e8ada7774adf73c13dc329
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:18:03 2019 +0800

This is a combination of 3 commits.

commit 0511f5c357d924179d8c1566a34aa9e578ff338d
Author: syc <doingself@163.com>
Date: Thu Feb 14 11:17:50 2019 +0800

1

git rebase -i 0511f5c357 删除 This is a combination of 3 commits. 提交记录
将要删除的 commit 的 pick 改为 drop

1
2
3
4
5
6
7
8
9
10
pick 9f077d1 This is a combination of 3 commits.
pick 71b4cd9 6

# Rebase 0511f5c..71b4cd9 onto 0511f5c (2 commands)
#
# ...

// 删除
drop 9f077d1 This is a combination of 3 commits.
pick 71b4cd9 6

处理冲突后, 这里需要重新提交 6

  • git rebase --continue 处理冲突继续 rebase
  • git rebase --abort 取消 rebase

再次 log 发现 提交记录/代码 已经没有 This is a combination of 3 commits.

撤销修改

修改文件后需要还原文件

  • git reset --hard HEAD^ 回退到上一个版本,用HEAD表示当前版本,上一个版本就是HEAD^
  • git add 后撤销:
    撤销所有add文件 git reset HEAD .
    撤销单个add文件 git reset HEAD -filename
  • git checkout . 撤销所有本地改动代码

回退 详情查看 reset

git reset主要是取消上一次的操作

  • git reset --hard HEAD^ 回退到上一个版本,用HEAD表示当前版本,上一个版本就是HEAD^
  • git reset --hard 3628164 回退到指定版本,版本号没必要写全,前几位就可以了,Git会自动去找

reset命令有3种方式:

  1. git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
  2. git reset –soft:回退到某个版本,只回退了commit的信息,保留修改代码, 不会恢复到index file一级。如果还要提交,直接commit即可
  3. git reset –hard:彻底回退到某个版本,不保留修改代码, 本地的源码也会变为上一个版本的内容

撤销本地修改 checkout

一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

  • git checkout -- readme.txt 把readme.txt文件在工作区的修改全部撤销
  • git checkout . 撤销所有本地改动代码

先提交文件, 再添加 ignore

先提交了文件, 才添加了 .gitignore 配置

  • git rm -r --cached .idea cached不会把本地的.idea删除
  • git commit -m 'delete .idea dir'
  • git push -u origin master

合并分支文件冲突

git merge dev 用于合并 指定分支dev 到当前分支 文件冲突,必须手动解决冲突后再提交。
git status 也可以告诉我们冲突的文件 Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容

BUG分支(stash 使用)

每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

  1. 在 dev分支上把当前工作现场“储藏”起来 git stash
  2. 切换到master分支,基于master创建临时分支
    1
    2
    git checkout master
    git checkout -b bug002
  3. 修复bug并提交到 bug002
  4. 切换到master分支,完成合并,删除 bug002 分支
    1
    2
    3
    4
    git checkout master
    git merge --no-ff -m "merged bug " bug002
    git branch -d bug002
    git pull / push
  5. 回到dev分支 恢复 stash
    1
    2
    git checkout dev
    git stash pop

git checkout

  1. 切换分支 git checkout <branchname>
  2. 放弃对某个文件的修改 git checkout -- fielname.xx
  3. 新建一个分支并切换到该分支 git checkout <-b> <branchname>

删除不在版本库的文件

git clean -d -fx

  • x 删除忽略文件已经对git来说不识别的文件
  • d 删除未被添加到git的路径中的文件
  • f 强制运行

日志输出参数

查看帮助 man git log

author=“Alex Kras” ——只显示某个用户的提交任务
name-only ——只显示变更文件的名称
oneline ——将提交信息压缩到一行显示
graph ——显示所有提交的依赖树
reverse ——按照逆序显示提交记录(最先提交的在最前面)
after ——显示某个日期之后发生的提交
before ——显示发生某个日期之前的提交

如:
git log --oneline --graph
在每周五提交周报 git log --author="Alex Kras" --after="1 week ago" --oneline

查看文件的详细变更

git log -p filename 显示提交说明、提交者以及提交日期、每次提交实际修改的内容

查看尚未合并的变更

git log --no-merges master.. 尚未合并到master分支。
--no-merges 标志意味着只显示没有合并到任何分支的变更
master.. 是指显示没有合并到master分支的变更(在master后面必须有..

git show --no-merges master.. 输出结果 == git log -p --no-merges master..

查看其他分支中的文件

git show devBranch:readMe.md 可以很方便地查看其他分支上的文件而无需切换到那个分支。

git show devBranch:readMe.md > temp.md 将输出重定向到一个临时文件

git diff devBranch readMe.md 查看另一个分支上文件与当前分支上文件的差异

关于变更基线的几点说明

在远程分支上工作会有大量的合并提交。使用 git rebase 可以避免这些提交

git pull –rebase

假设你正在master分支的一个本地版本上工作,你已经向仓库提交了一小部分变更。与此同时,也有人向master分支提交了他一周的工作成果。当你尝试推送本地变更时,git提示你需要先运行一下 git pull , 来解决冲突。你运行了一下git pull ,并且git自动生成了Merge remote-tracking branch ‘origin/master’的提交信息。尽管这不是什么大问题,也完全安全,但是不太有利于历史记录的聚合。

这种情况下,git pull --rebase 是一个不错的选择。

这个命令会迫使git将远程分支上的变更同步到本地,然后将尚未推送的提交重新应用到这个最新版本,就好象它们刚刚发生一样。这样就可以避免合并以及随之而来的丑陋的合并信息了。

忽略本地文件

使用场景: 拉取了服务端配置, 修改为本地配置, 不提交此处的修改,但是在’git status’中看到文件修改

在本机忽略本地文件修改的办法:

git update-index --assume-unchanged project/path/file.swift

要恢复的话,方法如下:

git update-index --no-assume-unchanged project/path/file.swift

如果想知道当前被忽略修改的本地文件列表,使用如下命令:

git ls-files -v | grep -e "^[hsmrck]"


参考文章

本文标题:Git版本控制管理 总结

文章作者:史彦超

发布时间:2016年10月11日 - 22:10

最后更新:2021年07月20日 - 16:07

原始链接:https://doingself.github.io/2016/10/11/2016-10-11-Git%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6%E7%AE%A1%E7%90%86%E6%80%BB%E7%BB%93/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Donate comment here