源码管理工具之git的使用

一、git简介

git是目前世界上被最广泛使用的现代软件版本管理系统。git本身亦是一个成熟并处于活跃开发状态的开源项目,它最初是由Linux操作系统内核的创造者Linus Torvalds在2005年创造。

二、在Mac OS X上安装git

如果你正在使用Mac做开发,有两种安装git的方法。

  • 安装homebrew,然后通过homebrew安装git,具体方法请参考homebrew的文档:http://brew.sh/
  • 直接从AppStore安装XcodeXcode集成了git。不过默认没有安装,你需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了。

三、创建本地仓库

仓库:英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被git管理起来,每个文件的修改、删除,git都能记录,以便任何时刻都可以查找历史记录,或者在回滚到以前修改的状态。

1、首先,选择一个合适的地方,创建一个空目录,执行:

git init

创建新的git仓库,会发下在当前的创建的目录下面多了一个.git的目录,这个目录是git来管理仓库的。
注意:
没事千万不要手动修改这个目录里面的文件,不然就把会git仓库给破坏了。

2、添加文件到git仓库

把文件添加到仓库:

git add <filename>
git add .

注意:
git add <filename>是把某一个文件添加到git的缓存区里面。
git add .是把所有的文件添加到git的缓存区里面。

3、把文件提交到本地仓库

git commit -m "代码提交信息"

注意:

  • git commit命令,一般会在后面加上-m表示本次提交到本地仓库的记录。
  • commit message言简意赅,不要写无用信息,这样让别人不能看懂这次提交的意义。
  • 在开发时,良好的习惯是根据工作进度及时commit,并务必注意附上有意义的commit message。创建完项目目录后,第一次提交的commit message一般为Initial commit.
  • 添加一个新的Pod库或pod update后,要单独提交一个commit,统一commit messagepod add xxxpod update xxx

四、远程仓库

一般使用git的公司都会有自己的git服务器或者使用第三方git服务器,比如coding.net、码云等。
由于你的本地git仓库和git服务器仓库之间的传输是通过SSH加密的,需要设置:

  • 创建SSH Key。在用户主目录下,看看有没有.ssh目录。如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有,可直接跳到下一步。如果没有,打开Shell,创建SSH Key
ssh-keygen -t rsa -C "your.email@example.com" -b 4096
  • 将公共SSH密钥复制到剪贴板:
pbcopy < ~/.ssh/id_rsa.pub
  • 登陆git服务器,打开“Account settings”“SSH Keys”页面:
  • “Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
image.png

注意:
为什么git服务器需要SSH Key呢?因为git服务器需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而git支持SSH协议,所以,git服务器只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,git服务器允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到git服务器,就可以在每台电脑上往git服务器推送了。

五、添加远程仓库

  • 登陆git服务器,然后,找到“Create a new repo”按钮,创建一个新的仓库:
  • Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的git仓库。
    注意:
    目前,在git服务器上的这个learngit仓库还是空的,git服务器告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到git服务器仓库。
image.png

通过上图可以看出:
1、如果在本地没有创建仓库,可以通过下面命令从git服务器clone出一个新的仓库:

git clone http://michael@git.51fanxing.com:88/fxbest/ios/learngit.git
cd learngit
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master

2、如果本地已经创建了,可以通过下面命令把本地仓库与git服务器仓库进行关联:

cd existing_folder
git init
git remote add origin http://michael@git.51fanxing.com:88/fxbest/ios/learngit.git
git add .
git commit
git push -u origin master

注意:
1、git remote add origin表示将本地服务器与git服务器进行关联。
2、origingit服务器的别名,取什么名字都可以,你也可以在push时将git服务器替换为 origin。但为了以后push方便,我们第一次一般都会先remote add
3、git push -u origin master将你修改或者添加的文件提交到git服务器。

3、git remote
git remote命令允许你创建、查看和删除和其它仓库之间的远程连接。

git remote

列出和其他仓库之间的远程连接。

git remote -v

列出和其他仓库之间的远程连接,但同时显示每个连接的URL

git remote add <name> <url>

创建一个新的远程仓库连接。在添加之后,可以将<name>作为<url>便捷的别名在其他git命令中使用。

git remote rm <name>

移除名为的远程仓库的连接。

git remote rename <old-name> <new-name>

将远程连接从<old-name>重命名为<new-name>

六、检查仓库状态

1、git status
git status命令显示工作目录和缓存区的状态。你可以看到哪些更改被缓存了,哪些还没有,以及哪些还未被git记录。

2、git log
git log命令查看每次commit的历史记录。

git log

使用默认格式显示完整地commit记录,如果输出超过一屏,你可以用空格键来滚动,按q退出。

git log -n <limit>

用<limit>限制提交的数量,比如git log -n 3只会显示3个提交。

git log --oneline

将每个提交压缩到一行,当你需要查看项目历史的上层情况时这会很有用。

git log --stat

除了git log信息之外,包含哪些文件被更改了,以及每个文件相对的增删行数。

git log -p

显示代表每个提交的一堆信息,显示每个提交全部的差异(diff),这也是项目历史中最详细的视图。

git log --author="<pattern>"

搜索特定作者的提交。<pattern>可以是字符串或正则表达式。

git log --grep="<pattern>"

搜索提交信息匹配特定<pattern>的提交。<pattern>可以是字符串或正则表达式。

七、git reset、git checkout和git revert

git仓库有三个主要组成——工作目录,缓存区和提交历史。

image.png

git resetgit checkoutgit revert是你的git工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件。

因为它们非常相似,所以我们经常会搞混,不知道什么场景下该用哪个命令。

1、git reset

git reset操作会将当前分支的HEAD指向另外一个commit记录,这样可以在当前分支上移除部分commit记录。例如,在hotfix分支上回滚前两次的commit状态:

git reset HEAD~2
image.png
image.png

当执行git reset时,hotfix分支上最后两次提交的状态会变成空状态,等到git执行垃圾回收的时候,hotfix分支上最后两次提交的状态会被回收。

  • --soft – 缓存区和工作目录都不会被改变
  • --mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
  • --hard – 缓存区和工作目录都同步到你指定的提交

git reset一般配合这些参数使用,git reset --mixed HEAD将你当前的改动从缓存区中移除,但是这些改动还留在工作目录中。如果你想完全舍弃你没有提交的改动,你可以使用git reset --hard HEAD,这是git reset最常用的两种用法。
注意:
git reset是不可逆的,因为git reset操作会重写当前分支的历史,用来撤销缓存区和工作目录的修改。git reset只适用于本地修改,不能重设服务器上的commit记录。

2、git checkout

  • 切换分支:
git checkout hotfix

注意:
使用git checkout之前,要把工作区的内容提交到git服务器或者缓存区。git checkout是将HEAD指针从一个分支切换到另一个分支,然后更新工作目录。因为这可能会覆盖本地的修改,git会强制你提交或者缓存工作目录中的所有更改,不然在checkout的时候这些更改都会丢失。

image.png
image.png
  • 查看文件之前的版本

除了切换分支之外,git checkout还可以将HEAD指针移动到当前分支其他的commit记录。

git checkout HEAD~2

git checkout更改的是工作目录而不是缓存区

git checkout HEAD~2 xxx

如果你缓存并且提交了checkout的文件,它具备将某个文件回撤到之前版本的效果,注意它撤销了这个文件后面所有的更改。不影响你仓库的当前状态。你可以在新的快照中像其他文件一样重新提交旧版本。所以,在效果上,git checkout的这个用法可以用来将单个文件回滚到旧版本。

image.png
image.png

注意:
git checkout是可逆的。

3、git revert

git revert撤销一个commit记录的同时会创建另一个新的commit记录,这是一个安全的方法,而不是从项目历史中移除这个提交。这避免了git丢失项目历史记录,这一点对于你的版本历史和协作的可靠性来说是很重要的。

比如,下面的命令会找出倒数第二个提交,然后创建一个新的提交来撤销这些更改,然后把这个提交加入项目中。

git revert HEAD~2
image.png
image.png

git revert应该用在你想要在项目历史中移除一整个提交的时候。比如说,你在追踪一个 bug,然后你发现它是由一个提交造成的,这时候撤销就很有用。与其说自己去修复它,然后提交一个新的快照,不如用git revert,它帮你做了所有的事情。

git revert回滚了单独一个提交,它没有移除后面的提交记录,同时会创建另一个新的commit记录。

image.png

git reset回滚了单独一个提交,并且移除后面的提交记录,是不可逆的

image.png

git revert可以针对历史记录中任何一个提交,而git reset只能从当前提交向前回滚。比如,你想用git reset重设一个旧的提交,你不得不移除那个提交后的所有提交,再移除那个提交,然后重新提交后面的所有提交。一般公司不提倡这么做。因此,git revert可以用在公共分支上,git reset应该用在私有分支上。

4、git reset用慎用
当有commit之后的提交被推送到公共分支上,你绝不应该使用git reset。使用git reset回滚了单独一个提交,并且移除后面的提交记录。当团队成员在上面继续开发的提交在协作时会引发严重的问题。当他们试着和你的仓库同步时,他们会发现项目历史的一部分突然消失了。
下面的序列展示了如果你尝试重设公共提交时会发生什么。origin/master是你本地master分支对应的中央仓库中的分支。

image.png
image.png
image.png

一旦你在重设之后又增加了新的提交,git会认为你的本地历史已经和 origin/master分叉了,同步你的仓库时的合并提交(merge commit)会使你的同事困惑。

5、git clean

git clean命令将未记录的文件从你的工作目录中移除。它只是提供了一条捷径,因为用git status查看未记录的文件,然后手动移除它们也很方便。和一般的rm命令一样,git clean是无法撤消的,所以在删除未记录的文件之前想清楚,你是否真的要这么做。

git clean命令经常和git reset --hard一起使用。记住,git reset只影响被记录的文件,所以还需要一个单独的命令来清理未被记录的文件。这个两个命令相结合,你就可以将工作目录回到之前特定提交时的状态。

注意:
git clean也是不可逆的。

八、分支

1、git branch
分支代表了一条独立的开发流水线,git branch命令允许你创建、列出、重命名和删除分支。一般git branchgit checkoutgit merge这两个命令通常紧密地结合在一起使用。一般使用过git的同学都知道:

  • master是长期分支,一般用于管理对外发布版本,每个commit对一个tag,也就是一个发布版本。
  • develop是长期分支,一般用于作为日常开发汇总,即开发版的代码
  • feature是短期分支,一般用于一个新功能的开发。
  • hotfix是短期分支 ,一般用于正式发布以后,出现bug,需要创建一个分支,进行bug修补。
  • release是短期分支,一般用于发布正式版本之前(即合并到master分支之前),需要有的预发布的版本进行测试。release分支在经历测试之后,测试确认验收,将会被合并的developmaster
git branch

列出仓库中所有分支。

git branch <branch>

创建一个名为 <branch> 的分支。不会自动切换到那个分支去。

git branch -d <branch>

删除指定分支。这是一个安全的操作,git会阻止你删除包含未合并更改的分支。

git branch -D <branch>

强制删除指定分支,即使包含未合并更改。如果你希望永远删除某条开发线的所有提交,你应该用这个命令。

git branch -m <branch>

将当前分支命名为<branch>。

2、git merge
用于合并指定分支到当前分支,git merge命令允许你将git branch创建的多条分支合并成一个。

注意:
合并指定分支到当前分支,当前分支会被更新,以响应合并操作,但目标分支完全不受影响。也就是说git merge经常和git checkout一起使用,选择当前分支,然后用git branch -d删除废弃的目标分支。

git merge <branch>

将指定分支并入当前分支。

git merge --no-ff <branch>

将指定分支并入当前分支,但 总是 生成一个合并提交(即使是快速向前合并)。这可以用来记录仓库中发生的所有合并。

3、git merge几种方法

  • 快速向前合并
    当当前分支顶端到目标分支路径是线性之时,我们可以采取快速向前合并。git只需要将当前分支顶端(快速向前地)移动到目标分支顶端,即可整合两个分支的历史,而不需要“真正”合并分支。它在效果上合并了历史,因为目标分支上的提交现在在当前分支可以访问到。比如,some-featuremaster分支的快速向前合并会是这样的:
image.png
image.png
  • 三路合并
    如果分支已经分叉了,那么就无法进行快速向前合并。当和目标分支之间的路径不是线性之时,git只能执行三路合并。三路合并使用一个专门的提交来合并两个分支的历史。这个术语取自这样一个事实,git使用三个提交来生成合并提交:两个分支顶端和它们共同的祖先。
image.png
image.png

很多开发者喜欢使用git rebase快速向前合并,来合并微小的功能或者修复bug,使用三路合并来整合长期运行的功能。后者导致的合并提交作为两个分支的连接标志。

4、解决冲突

如果你尝试合并的两个分支同一个文件的同一个部分,git将无法决定使用哪个版本。当这种情况发生时,它会停在合并提交,让你手动解决这些冲突。

当你遇到合并冲突时,运行git status命令来查看哪些文件存在需要解决的冲突。

当你手动修复完冲突之后,只需对冲突的文件运行git add告诉git冲突已解决。然后,运行git commit生成一个合并提交。

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

团队合作的分支看起来就像这样:


image.png

注意:
提交冲突只会出现在三路合并中。在快速向前合并中,我们不可能出现冲突的更改。

九、创建标签

一般在公司每一个上线版本都会打一个标签,为了记录和维护,当线上版本出现紧急bug,我们就可以通过git checkout检出项目,然后创建hotfix分支进行bug的修复。

git tag

查看所有标签

git tag <name>
git tag <name> commit id

用于新建一个标签,默认为HEAD,也可以指定一个commit id

git show <tagname>

查看标签信息

git push origin <tagname>

可以推送一个本地标签

git push origin --tags

可以推送全部未推送过的本地标签

git tag -d <tagname>

可以删除一个本地标签

git push origin :refs/tags/<tagname>

可以删除一个远程标签

Reference:
https://www.atlassian.com/git/tutorials/merging-vs-rebasing
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容