iOS开发经验总结(持续更新中)

本文会持续记录自己在学习、工作中,接触的和iOS开发相关的各种技术。包括写代码时容易忽视的细节问题,项目中接触到实用技术以及优秀的三方框架。欢迎收藏,点赞,若有不足欢迎各位指出来一起探讨,共同进步。

Section One — Coding Tips

1.为私有方法名加前缀

  • 这条建议是我最近看《Effective Objective-C 2.0》才知道的。
  • 因为一个类要做的事情通常比外面看到的要多。在·m文件中,经常要写一些内部使用的代码。而我们应该给这些方法加上某些前缀,这有助于调试,因为据此很容易就能把公共方法和私有方法区分开。
  • 具体使用何种前缀完全可以根据个人喜好来,没有固定标准。
    • 但有一点要注意:苹果官方保留用单一下划线作为前缀命名私有方法
  • 如果你想模仿苹果的写法也使用单一下划线,很可能在无意中重写了父类的同名方法,造成很多莫名其妙的问题。
  • 我个人对于私有方法喜欢以 p_methordName 的形式命名,p即代表pravite.

2.建议书写枚举模仿苹果——在列出枚举内容的同时绑定了枚举数据类型NSUInteger,这样带来的好处是增强的类型检查和更好的代码可读性,示例:

typedef NS_ENUM(NSUInteger, GPSectionType) {
    GPSectionTypeNone              = 0,
    GPSectionTypeNews              = 1 ,
    GPSectionTypeInformation      = 2,
};

3.头文件 #import的顺序

  • 写法模板
#import <系统库>
#import <第三方库>
#import “其他类”
  • 尽量按照先系统类 第三方类 自己写的类顺序导入 中间不能有空格
  • 建议的写法
#import<UIKit/UIkit.h>
#import<Google/Analytics.h>
#import"GPCustomView.h

4.@Class的写法

  • 写法模板:@class class1, class2;
// 建议的写法
@class UIView, UIImage;
// 不建议的写法
@class UIView;
@class UIImage;

5.声明const的字符串

  • 开头用k标识
  • 推荐k+模板名字首字母大写+作用名称 防止和其他的重复
  • 比如:CartViewModel类需要声明更新购物车列表的通知
    • kCVMNoticationUpdateCartList

6.方法尽量控制最多五十行

  • 一个方法内部最多五十行
  • 如果超过就精简代码 就分开方法写
  • 方便之后进行热修复 代码重构

7.注释一定要写

  • 自己管理的类一定注释属性用途 方法的用途 参数的说明

  • 属性如果设置默认值 一定注明默认值是什么

  • 如果方法内部存在逻辑判断 方法跳转 一定注释判断用法 方法跳转用法

  • 除了初始化操作

  • 其他声明变量 赋值 判断 应该注明注释用途

  • 方法注释

/**
 *  @brief 直播间发送礼物
 *
 *  @param gift     礼物
 *  @param groupId  直播间id
 *  @param count    数量
 *  @param success  成功回调
 *  @param failure  失败回调
 */
 
 + (void)readySendGiftWithGift:(MoerLiveRoomGift*)gift
                      groupId:(NSString*)groupId
                        count:(NSInteger)count
                      success:(void(^)(Goods *goods))success
                      failure:(Failure)failure;                
/**
 *  @brief 根据字典信息实例化订单
 *
 *  @param dictionary 字典信息
 *
 *  @return 订单实例
 */
-(instancetype)initWithDictionary:(NSDictionary*)dictionary;

  • 属性注释
/**
 *  打赏对象
 */
@property (nonatomic, copy) NSString *targetId;

  • 枚举注释
typedef NS_ENUM(NSInteger, MoerGoodsType) {
    /**
     *  无
     */
    MoerGoodsTypeNone,
    /**
     *  文章
     */
    MoerGoodsTypeArticle = 1,
    /**
     *  活动
     */
    MoerGoodsTypeActivity = 2
}

8.头文件引入其他类的时候使用@class

  • 可以防止互相引入导致编译失败,造成不容易查找的bug
  • 同时在.m文件中使用#import导入对应的类

9.多使用pragma mark

  • 尤其是一个控制器包含非常多的业务逻辑,可以让结构更加清晰

10.控件的命名规范

  • 不要使用简写,password不要写成pwd,button不要写成btn等;
  • UILabel结尾加上Label;
  • UIImageView结尾记上ImageView
  • 等等让其他的编程人员看名字就知道变量的用法 和属于什么控件

11.对于#define宏命名

  • 单词全部的大写 单词之间用_分割
  • 建议的写法
#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)

12.对于局部的变量尽量的初始化

  • 局部的变量要初始化 属性有默认的值 所以我们不必须对于属性进行初始化
  • 我之前遇到的一个BUG就是int类型没有初始化给我默认Nan造成崩溃
//正确的写法
int index = 0;
//错误的写法
int index;
  • 对于一些对象判断是否赋值可以不进行初始化 但是对于一定不会为nil要进行初始化

13.block的命名规范

  • 之前研究过很多的第三方的命名 对于苹果官方的没找到
  • 有CallBack结尾 Complete结尾 Block结尾 还有CompletionHandle结尾的
  • 我看到苹果很多的结尾都是用CompletionHandle结尾
// 建议的写法
typedef void(DidUpdateViewCompletionHandle)(void)
// 不建议的写法
typedef void(DidUpdateViewCallBack)

14.在dealloc方法中移除通知

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

15.属性要尽量使用懒加载

  • 我们一个界面有很多控件
  • 利用懒加载可以美化代码
  • 所有的懒加载放在Getter的mark的下面

16.多使用字面量

  • NSString @“”
  • NSNumber @()
  • NSDictionary @{}
  • NSArray @[]

17.为第三方类添加分类添加前缀

  • 比如为系统UIView添加分类Add的添加前缀
@interface UIView (GP_Add)
- (void)gp_addCustomView:(CustomView *)customView;
@end;

18.数组和字典最好指定元素的类型

NSArray<NSString *> *names = [NSArray array];

Section Two — Work Experience

1.建议加载xib,xib名称用NSStringFromClass(),避免书写错误

// 推荐写法
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([GPTableViewCell class]) bundle:nil] forCellReuseIdentifier:ID];

// 不推荐写法
[self.tableView registerNib:[UINib nibWithNibName:@"GPTableViewCell" bundle:nil] forCellReuseIdentifier:ID];

2.自定义cell的时候,将重用标识符同cell文件绑定在一起,而不是在控制器里定义一堆重用标识符

  • 在.h中
#import "GPBaseCell.h"

UIKIT_EXTERN NSString * const GPContentCelltCellIdentifier;

@interface GPContentCell : GPBaseCell

@end

  • 在.m中
#import "GPContentCell.h"

NSString * const "GPContentCell = @"GPContentCell";

@interface GPContentCell ()
@property (weak, nonatomic) IBOutlet UILabel *contentLabel;
@end

@implementation MoerQAAskerContentCell

- (void)awakeFromNib {
    [super awakeFromNib];
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.contentLabel.textColor = [UIColor redColor];
}
  • UIKIT_EXTERN简单来说,就是将函数修饰为兼容以往C编译方式的、具有extern属性(文件外可见性)、public修饰的方法或变量库外仍可见的属性
  • 参考资料

3.使用XIB创建自定义View

  • 我们创建一个继承自UIView的类时,底下Also Creat XIB file处于灰色不可选择的状态。或许是苹果官方不建议这样做,但我们仍然可以单独创建一个View文件将其关联起来。
  • 在.h文件中声明一个初始化方法
- (instancetype)initWithXib;
  • 在.m中实现它
- (instancetype)initWithXib {
    self = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] lastObject];
    // 初始化设置调整UI样式
    ...
    return self;
}

4.善于利用autoresizingMask技术

  • 用于处理比较简单的、单一的父子视图关系
  • 一般情况下,确定一个子控件在其父控件中的位置,我们只需要确定4个方向中的两个有效方向就够了,如果多于两个有效方向,那么多出来的方向约束会被替代。具体说来就是,4个方向的约束线是有优先级的,顶部的约束线优先级高于底部的约束线,左边的约束线优先级高于右边的约束线。如果你同时约束了左边和右边,那么起作用的就是左边;如果你同时约束了上边和下边,那么起作用的就是上边;如果你同时约束了4个方向,那么起作用的是左上角。为了保证约束有效,不能同时约束上、下或者是左、右。
  • 参考资料

5.拉伸图片

  • 有些时候UI给的图片不能满足我们的需求,这个时候我们就要自己简单处理一下图片。
  • 比如以某edgeInsets进行拉伸图片
  • 涉及到的方法
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets NS_AVAILABLE_IOS(5_0); // create a resizable version of this image. the interior is tiled when drawn.
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode NS_AVAILABLE_IOS(6_0); // the interior is resized according to the resizingMode

6.使用SDWebImage给button设置图片

// 第一步:导入头文件
#import <SDWebImage/UIButton+WebCache.h>
// 第二步:调用方法并设置占位图片
[self.avatarButton sd_setImageWithURL:[NSURL URLWithString:model.avatarUrlString] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed:@"PlaceholderImage"]];

7.使用SDWebImage加载gif图片

// 第一步:导入头文件
#import "UIImage+GIF.h"
// 第二步:调用方法
    UIImage *hoopImage = [UIImage sd_animatedGIFNamed:@"hula_hoop"];
    self.hoopImageView = [[UIImageView alloc] initWithImage:hoopImage];
    self.hoopImageView.frame = CGRectMake(10, 10, 100, 100);
    [self.view addSubview:self.hoopImageView];

8.使用dSYM文件查找线上程序的crash日志

  • 什么是 dSYM 文件
    • Xcode编译项目后,我们会看到一个同名的 dSYM 文件,dSYM 是保存16进制函数地址映射信息的中转文件,我们调试的 symbols 都会包含在这个文件中,并且每次编译项目的时候都会生成一个新的 dSYM 文件
    • 位于 /Users/<用户名>/Library/Developer/Xcode/Archives 目录下,对于每一个发布版本我们都很有必要保存对应的 Archives 文件 。

  • dSYM 文件有什么作用
    • 当我们软件 release 模式打包或上线后,不会像我们在 Xcode 中那样直观的看到用崩溃的错误,这个时候我们就需要分析 crash report 文件了,iOS 设备中会有日志文件保存我们每个应用出错的函数内存地址
    • 通过 Xcode 的 Organizer 可以将 iOS 设备中的 DeviceLog 导出成 crash 文件,这个时候我们就可以通过出错的函数地址去查询 dSYM 文件中程序对应的函数名和文件名。
    • 大前提是我们需要有软件版本对应的 dSYM 文件,这也是为什么我们很有必要保存每个发布版本的 Archives 文件了。

  • 如何将文件一一对应
    • 每一个 xx.app 和 xx.app.dSYM 文件都有对应的 UUID,crash 文件也有自己的 UUID,只要这三个文件的 UUID 一致,我们就可以通过他们解析出正确的错误函数信息了。

  • 1.查看 xx.app 文件的 UUID,terminal 中输入命令 :
    dwarfdump --uuid xx.app/xx (xx代表你的项目名)

  • 2.查看 xx.app.dSYM 文件的 UUID ,在 terminal 中输入命令:
    dwarfdump --uuid xx.app.dSYM

  • 3.crash 文件内第一行 Incident Identifier 就是该 crash 文件的 UUID。


9.block的注意事项

  • 在类中声明block为属性时,如果使用assgin修饰,那么它被放到了栈中,方法一过就会被销毁,
  • 所以,尽量使用copy作为修饰词,这样一来block就被存放到了堆中,生命周期就会延长,保证block不会被立即销毁;
  • 要防止循环引用,所以在block外部通常要先弱引用一次,然后在block内部强引用一次。
  • __weak typeof(self) weakSelf = self;
  • __strong typeof(self) strongSelf = weakSelf;
  • block使用的时候要先进行判断
if (self.backBlock) {
    self.backBlock(self.textView.text)
}


10.不要把本地调试的代码提交到git上

  • 如果在提交前忘记改回来,要善于利用宏
  • 下面的代码只会在debug模式下运行
  • 如果切换到release模式不会运行
#ifdef DEBUG
    isDebug = YES;
#else
    isDebug = NO;
#endif

11.使用自定义标签警告

  • // TODO:标识将来要完成的内容;
  • // FIXME:标识以后要修正或完善的内容。
  • // ???: 疑问的地方
  • /// !!!: 需要注意的地方

12.使用runtime关联对象


13.使用contentMode让图片长得好看


14.控件字体颜色设置相同时使用IBOutletCollection

  • 对于很多控件我们有的时候可能要设置相同的颜色或者字体大小,这个时候我们不必把每一个控件都拖成属性,而是使用IBOutletCollection统一设置
  • 参考资料1
  • 参考资料2

15.修改状态栏字体颜色

// 首先写一个属性
@property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
// 根据具体需求来修改状态栏的样式
self.statusBarStyle = UIStatusBarStyleLightContent;// 白色
self.statusBarStyle = UIStatusBarStyleDefault; // 黑色
// 告诉系统更新状态栏样式
[self setNeedsStatusBarAppearanceUpdate];
// 重写该方法,将新的样式返回给系统
- (UIStatusBarStyle)preferredStatusBarStyle {
    return self.statusBarStyle;
}

16.关闭刷新section的动画效果

// 虽然动画效果选择的是UITableViewRowAnimationNone
// 但实际上还是会动画效果
 [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:GPSectionTypeNews] withRowAnimation:UITableViewRowAnimationNone];
  • 正确做法
[UIView performWithoutAnimation:^{
            [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:GPSectionTypeNews] withRowAnimation:UITableViewRowAnimationNone];
        }];

17.善于利用round/ceil/floorf函数

  • round:如果参数是小数,则求本身的四舍五入。
  • ceil:如果参数是小数,则求最小的整数但不小于本身.
  • floor:如果参数是小数,则求最大的整数但不大于本身.
Example:如何值是3.4的话,则
3.4 -- round 3.000000
    -- ceil 4.000000
    -- floor 3.00000

18.APP内拨打电话

  • 方法一
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://010-88888888"]];

  • 方法二
#import <UIKit/UIWebView.h>

UIWebView * callWebview = [[UIWebView alloc]init];
[callWebview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"tel:010-88888888"]]];
[[UIApplication sharedApplication].keyWindow addSubview:callWebview];
  • 区别
区别一:第一种会先跳出程序到系统的打电话程序,第二种是一直都在自己的app中运行,没有出去过。
区别二:第一种触发直接到打电话界面,第二种会先弹出一个对话框,可以选择打不打电话,对话框如下。

19.善于利用UIStackView


20.iOS中常用动画详解


21.使用NSTextAttachment实现图文混排

//     
    NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ ", article.title]];
    NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithData:nil ofType:nil];
    textAttachment.image = [UIImage imageNamed:@"icon"];
    CGFloat offsetY = -1.0;
    textAttachment.bounds = CGRectMake(0, offsetY, textAttachment.image.size.width, textAttachment.image.size.height);
    NSAttributedString *textAttachmentString = [NSAttributedString attributedStringWithAttachment:textAttachment];
    [titleString insertAttributedString:textAttachmentString];

22.TextKit的学习


23.支付相关


24.关于dispatch_semaphore的使用


25.NSStringFromSelector(_cmd)说明

  • _cmd 代表本方法的名称

  • _cmd是隐藏的参数,代表当前方法的selector,他和self一样都是每个方法调用时都会传入的参数,动态运行时会提及如何传的这两个参数,
    你在方法里加入CCLOG(@"%@, %@",NSStringFromSelector(_cmd),self);语句之后,执行这个方法就会输出方法的名称,
    这样做是为了跟踪查看方法调用的前后顺序,或者想看看程序到底在那个方法内部崩溃的!

  • 在Apple的官方介绍里看到轻描淡写的说了一句:“The _cmd variable is a hidden argument passed to every method that is the current selector”,其实说的就是_cmd在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对……

26.iOS方法警告

  • 当苹果SDK升级时废弃某些方法,就需要方法警告。

  • 外部调用方法警告

__deprecated_msg("方法废弃,请使用...替换")
  • 当前方法警告
__attribute__((visibility("警告")));
- (void)test __deprecated_msg("方法废弃,请使用...替换") __attribute__((visibility("方法废弃")));


27.友盟推送踩的坑

  • 首先友盟的推送是分为开发环境和生产环境,开发环境就是指我们在开发阶段,应用还没有上架到app store的时候,这时候我们按照友盟的官方文档集成友盟消息推送就可以了。
  • 然后要测试的时候,这时候选择测试模式进行测试,要在下面的方法中获取当前设备的device token,然后测试模式添加测试设备,只要上传的证书没有错误,发送消息手机就可以收到推送消息了
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"%@",[[[[deviceToken description] stringByReplacingOccurrencesOfString: @"<" withString: @""]
                  stringByReplacingOccurrencesOfString: @">" withString: @""]
                 stringByReplacingOccurrencesOfString: @" " withString: @""]);
}

  • 开发环境只能在测试模式下测试,消息列表那边只能是app上线后,变成生产环境了才可以在消息列表发送消息测试。
  • app上线后,第一天一般发送推送消息是失败的,因为device token在友盟那边的入库是有一天的延时的,具体可以看友盟上的这篇文章
  • 关于app点击消息跳转到指定页面,分为当前app是在前台还是后台后者未运行,所以需要在
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  • 两个方法里面写页面的跳转,这个需要和后台约定好传过来的消息需要跳转到什么页面,再自己做跳转,页面跳转只能自己在代码中进行操作.

  • 推送消息一直显示发送失败,不知道该如何查找原因,找了客服很多次,说device token无效,重新获取,可是重新获取很多次也还是无效
  • 后来碰到好心人建议查看证书的包名和bundle ID是否一致,于是把导出的上传到友盟的推送证书在钥匙串中打开,发现包名确实不一样了,但是证书制作过程没有出错的,所以想不通,把证书删除了,重新导出,上传,OK。可以推送了。如果用户第一次打开app 没有允许推送,后面在设置中打开允许推送也是可以的,因为在第一次打开和每天的第一次运行app的时候都会发送token给友盟的服务器,所以推送开关的开启和关闭不影响token。
  • 最后如果需要在生产环境下将应用程序安装到设备上测试,或者APP并没有上线也需要推送组件,要以Ad Hoc方式打包应用

28.配置Gitlab

  • GitLab是企业版的GitHub,并且GitLab是开源的,也就是说可以部署到自己的内网上。
  • 如果配置好了SSH公钥还是不能通过Sourcetree把公司的代码拉到本地的电脑上,可能是你的老大忘了把你的Gitlab账号开通权限
  • GitLab的简单使用

29.过滤掉字符串前后的空格

  • 有时候服务端返回的数据前后会带\n
  • 我们可以调用下面的方法将它去掉
 NSString* trimedURL = [stringURL stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Section Three — Third Party

1.一款非常强大的文字编辑器


2.实现顶部弹窗的HUD


3.非常好用的一款加载弹窗


4.每一个网络请求封装成对象的网络库


5.让响应手势变得更简单


6.让每一个试图控制器拥有独立的导航栏


7.绘制图表、折线图的框架


8.一个比UISegmentedControl更好用的东西


9.轮播图必备


10.tableView算高神器


11.超级强大的开源框架


12.小抽屉展示


13.侧滑抽屉


14.夜间模式


15.图片浏览器


16.HTML标签解析


Section Four — Development Tool

1.捕捉网络请求 — Charles


2.切换host的工具 — Gas Mask


3.高效的编辑器 — Subline Text


4.模拟发送网络请求 — Postman


5.图形化Git工具 — SourceTree


6.分析他人APP界面 — Reveal


7.翻墙必备 — Shadowsocks


8.快捷键太多记不住? — Cheetsheet


Section Five — About Git

很多人做iOS开发,可能先接触方便好用的Sourcetree,记住了合并代码的那几个步骤,然后才接触git。为了能更好的理解Sourcetree做的每一步,很有必要学习博大精深的git,以下内容为本人恶补git知识时的笔记,感谢廖雪峰老师写的git教程。


  • 创建一个文件夹(默认路径:/Users/fsl/learngit)
    • mkdir learngit
  • 进入该文件夹
    • cd learngit
  • 显示当前目录
    • pwd
  • 初始化git仓库
    • git init
  • 把文件添加到git仓库
    • git add <file>
    • git commit
      • git commit -m "提交信息"


  • 查看当前仓库的状态
    • git status
  • 查看当前仓库某个文件的改变
    • git diff readme.txt
  • 显示从最近到最远的提交日志
    • git log


  • 版本回退
    • git reset --hard HEAD^
    • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
    • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
    • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。



版本库(Repository)

  • 查看工作区和版本库里最新文件的区别

    • git diff HEAD -- readme.txt
  • 撤销修改

    • git checkout -- readme.txt
    • git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令


  • 撤销已经提交到暂存区的修改(重新放回工作区)

    • git reset HEAD readme.txt
    • git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。
  • 删除文件

    • rm test.txt
    • git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
    • 命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

添加到远程仓库

  • 关联一个远程库
  • git push -u origin master (第一次推送master分支的所有内容)
    • 把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。
    • 由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
  • 此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
  • 从现在起,只要本地做了提交,就可以通过
    • git push origin master
    • 把本地master分支的最新修改推送至GitHub,现在,就拥有了真正的分布式版本库!

查看分支

  • git branch

切换分支(创建新分支)

  • git checkout -b dev
  • git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
    • $ git branch dev
    • $ git checkout dev
      • Switched to branch 'dev'
  • 切换分支
    • git checkout <name>

合并指定分支(dev)到当前分支(master)

  • git merge dev

删除分支

  • git branch -d dev
  • 查看分支
    • git branch

查看分支图

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

分支管理策略

  • 通常情况下,合并分支时,Git会使用Fast Forward(快进)模式,即改变指针指向


  • 使用Fast Forward模式有一个缺点,就是删除分支后,会丢掉分支信息。
  • 如果要强制禁用Fast Forward模式,Git就会在merge时生成一个新的commit,这样的话在分支历史上就能看到分支信息。
    • git merge --no-ff -m "merge with no-ff" dev
    • 因为本次合并会创建一个新的commit,所以要加上-m 参数,把commit的描述写进去。

Bug分支

  • 修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
  • 当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
  • 查看暂存列表
    • git stash list
  • 恢复工作现场
    • 方式一:用git stash apply恢复,但是恢复后,藏匿内容并不删除,需要你用git stash drop来删除;
    • 方式二:用git stash pop,恢复的同时把stash内容也删了

Feature分支

  • 添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
  • 有一种可能是该分支开发到一半,被告知新功能取消。此时执行 git branch -d 分支名,是直接删不掉分支的
    • git会提醒你,该分支还没有被合并,如果删除将丢失掉修改
    • 如果要强行删除,需要使用命令git branch -D 分支名。

多人协作

  • 多人协作的工作模式通常是这样:
    • 首先,可以试图用git push origin branch-name推送自己的修改;
    • 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
    • 如果合并有冲突,则解决冲突,并在本地提交;
    • 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
  • 如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。
  • 查看远程仓库信息
    • git remote -v
  • 如果新建的分支不推送到远程,对其他人就是不可见的
  • 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
  • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致

标签管理

  • 发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
  • tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
  • 创建标签
    • git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id
    • git tag -a <tagname> -m "blablabla..."可以指定标签信息;
    • git tag -s <tagname> -m "blablabla..."可以用PGP签名标签;
    • 命令git tag可以查看所有标签
  • 操作标签
    • 删除标签
      • git tag -d <tagname>
    • 推送一个本地标签到远程
      • git push origin <tagname>
    • 一次性推送全部尚未推送到远程的本地标签
      • git push origin --tags
    • 删除远端的标签
      • 先删除本地的标签 git tag -d <tagname>
      • 在使用git push origin :refs/tags/<tagname> 删除远端的标签

忽略文件

  • 忽略某些文件时,需要编写.gitignore
  • .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理

使用rebase而不是merge

  • 为了让提交代码的时间线是笔直的一条线,而不是各种分叉,我们要使用rebase(变基)
  • 关于rebase的知识可以看下面的链接
  • git rebase使用笔记

最后

学而时习之,不亦说乎。

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

推荐阅读更多精彩内容