快速,安全,沒有頭痛。您一生中遺漏的Git界面終於到了。
GIT最近慶祝了其10週年紀念日,但大多數工程師仍然對其複雜性感到困惑(堆棧溢出的有史以來5個問題中的3個與Git有關)。由於GIT甚至將簡單的動作變成了神秘的命令(“ git add”到舞台與“ git重置頭”以拆除任何人嗎?擰緊他們的倉庫!
Gitup是發明新的GIT交互模型的賭注,該模型使各個層次的工程師都可以快速,安全且無頭痛。它與其他任何GIT客戶端不同(與磁盤上的GIT數據庫直接交互)不同於其工作方式(您可以操縱存儲庫圖而不是操縱提交)。
使用Gitup,您將獲得Mac的真正高效的Git客戶端:
Gitup是由@Swisspol在2014年底創建的,目的是重塑開發人員與GIT互動的方式。經過幾個月的工作,它在2015年初發布的預發行前提供,並進入了Hacker News的頂端,並由產品Hunt和Daring Fireball飾演。後來有30,000行代碼,Gitup於2015年8月中旬達到1.0,並被公開發售,作為向開發人員社區的禮物。
brew install homebrew/cask/gitup
(注意:已經有一個稱為Gitup的公式,因此必須指定全名!)閱讀文檔並使用GitHub問題進行支持和反饋。
發行說明可在https://github.com/git-up/gitup/releases上找到。用v
標記的構建(例如v1.2.3
)在“穩定”通道上釋放,而用b
(例如b1234
)標記的構建僅在“連續”通道上釋放。您可以更改GITUP在應用程序首選項中使用的更新頻道。
要自己構建gitup,只需運行命令git clone --recursive https://github.com/git-up/GitUp.git
在終端中,然後打開GitUp/GitUp.xcodeproj
xcode xcode project和hit rum。
重要的是:如果您沒有帶有代碼簽名Mac應用程序的開發人員帳戶的Apple ID,則該構建將在代碼簽名錯誤時失敗。只需刪除“應用程序”目標的“代碼簽名身份”構建設置,以解決問題:
另外,如果您確實有一個開發人員帳戶,則可以創建以下構建設置為其內容:
development_team = [您的TeamID]
有關此的更詳細說明,您可以在文件“ Xcode-configurations/base.xcconfig”的末尾查看註釋。
gitup是在可重複使用的通用git工具包上的薄層中構建的,稱為“ gitupkit”。這意味著您可以使用相同的gitupkit框架來構建自己的git UI!
Gitupkit的目標與Objectivesgit的目標截然不同。 Gitupkit不用對Libgit2提供廣泛的原始綁定,而僅使用Libgit2的最小子集,並在其頂部重新實現所有其他內容(例如,它具有自己的“ Rebase Engine”)。這使其可以暴露出非常緊密且一致的API,該API完全遵循OBJ-C約定,並掩蓋了Libgit2的複雜性,有時甚至不一致。 Gitupkit在此之上添加了許多獨家和強大的功能,從撤消/重做和時間機(如快照)到整個UI組件。
GitupKit源代碼是2個獨立層,僅通過使用公共API來通信:
基層(僅取決於基礎,與OS X和iOS兼容)
Core/
:包裝器圍繞LibGit2所需的最小功能,然後在其上實現了Gitup所需的所有GIT功能(請注意,Gitup使用libgit2的稍微自定義的叉子)Extensions/
: Core
類別上的類別以添加僅使用公共API實現的便利性功能UI層(取決於AppKit,僅與OS X兼容)
Interface/
:低級視圖類,例如GIGraphView
呈現gitup地圖視圖Utilities/
:接口實用程序類,例如基本視圖控制器類GIViewController
Components/
:可重複使用的單視圖控制器,例如GIDiffContentsViewController
渲染差異Views/
:高級可重複使用的多視圖視圖視圖控制器,例如GIAdvancedCommitViewController
實現整個GITUP高級提交視圖重要:如果在構建gitupkit時將預處理器常數DEBUG
定義為非零值(這是在“調試”配置中構建時默認值),則在運行時啟用了許多額外的一致性檢查以及額外的記錄。請注意,此開銷會嚴重影響性能。
使用gitupkit API應該非常簡單,因為它是由功能(例如存儲庫,分支,提交,接口組件等)組織的,並且已經為清晰的命名函數做出了最大的努力。
關於“核心” API,學習它們的最佳方法是仔細閱讀相關的單元測試 - 例如,請參閱分支API的分支測試。
這是一些示例代碼可以使您開始(將錯誤處理作為練習給讀者):
打開和瀏覽一個存儲庫:
// Open repo
GCRepository* repo = [[GCRepository alloc ] initWithExistingLocalRepository: <PATH> error: NULL ];
// Make sure repo is clean
assert ([repo checkClean: kGCCleanCheckOption_IgnoreUntrackedFiles error: NULL ]);
// List all branches
NSArray * branches = [repo listAllBranches: NULL ];
NSLog ( @" %@ " , branches);
// Lookup HEAD
GCLocalBranch* headBranch; // This would be nil if the HEAD is detached
GCCommit* headCommit;
[repo lookupHEADCurrentCommit: &headCommit branch: &headBranch error: NULL ];
NSLog ( @" %@ = %@ " , headBranch, headCommit);
// Load the *entire* repo history in memory for fast access, including all commits, branches and tags
GCHistory* history = [repo loadHistoryUsingSorting: kGCHistorySorting_ReverseChronological error: NULL ];
assert (history);
NSLog ( @" %lu commits total " , history.allCommits.count);
NSLog ( @" %@ n %@ " , history.rootCommits, history.leafCommits);
修改存儲庫:
// Take a snapshot of the repo
GCSnapshot* snapshot = [repo takeSnapshot: NULL ];
// Create a new branch and check it out
GCLocalBranch* newBranch = [repo createLocalBranchFromCommit: headCommit withName: @" temp " force: NO error: NULL ];
NSLog ( @" %@ " , newBranch);
assert ([repo checkoutLocalBranch: newBranch options: 0 error: NULL ]);
// Add a file to the index
[[ NSData data ] writeToFile: [repo.workingDirectoryPath stringByAppendingPathComponent: @" empty.data " ] atomically: YES ];
assert ([repo addFileToIndex: @" empty.data " error: NULL ]);
// Check index status
GCDiff* diff = [repo diffRepositoryIndexWithHEAD: nil options: 0 maxInterHunkLines: 0 maxContextLines: 0 error: NULL ];
assert (diff.deltas.count == 1 );
NSLog ( @" %@ " , diff);
// Create a commit
GCCommit* newCommit = [repo createCommitFromHEADWithMessage: @" Added file " error: NULL ];
assert (newCommit);
NSLog ( @" %@ " , newCommit);
// Restore repo to saved snapshot before topic branch and commit were created
BOOL success = [repo restoreSnapshot: snapshot withOptions: kGCSnapshotOption_IncludeAll reflogMessage: @" Rolled back " didUpdateReferences: NULL error: NULL ];
assert (success);
// Make sure topic branch is gone
assert ([repo findLocalBranchWithName: @" temp " error: NULL ] == nil );
// Update workdir and index to match HEAD
assert ([repo resetToHEAD: kGCResetMode_Hard error: NULL ]);
Gitdown是一個非常基本的應用程序,它可以提示用戶進行存儲庫,並顯示其藏匿處的交互式和實時更新的列表(所有內容都在-[AppDelegate applicationDidFinishLaunching:]
)中:
通過gitupkit,此基本應用程序還可以免費獲得無限制的撤消/重做,統一和並排的差異,文本選擇和復制,鍵盤快捷鍵等...
該源代碼還演示瞭如何使用其他一些gitupkit視圖控制器以及構建自定義的控制器。
Gitdiff演示瞭如何創建一個視圖控制器,該視圖控制器顯示了HEAD
和WorkDiràlagit git diff HEAD
之間的實時更新差異:
Gity是使用GitupKit構建的Gitx克隆,少於200行代碼:
IGIT是一個測試iOS應用程序,僅使用gitupkit克隆github repo並執行提交。
參見貢獻。
也要非常感謝gitup永遠不會存在的優秀libgit2貢獻者!
Gitup是2015-2018 Pierre-Olivier Latour的版權,並獲得GPL V3許可證。有關更多信息,請參見項目中的許可證文件。
重要的是: Gitup還包括其他一些開源項目,此類項目仍遵守自己的許可。