本文會持續記錄自己在學習、工作中,接觸的和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.dSYM3.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
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 remote add origin https://github.com/Bestmer/learngit.git
- 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使用筆記
最后
學而時習之,不亦說乎。