GitUp:高效直观的 Git 客户端,可视化仓库管理与操作

The Git interface you've been missing all your life has finally arrived.

分支3Tags82
文件最后提交记录最后更新时间
7 个月前
2 年前
7 年前
1 个月前
1 个月前
2 个月前
1 个月前
7 年前
1 年前
6 年前
4 年前
8 年前
5 年前
1 个月前
2 个月前
7 个月前
4 年前
2 年前

GitUp GitUpKit Tests

GitUp

快速、安全、无烦恼地工作。你一直苦苦寻觅的 Git 界面终于来了。

Git 最近刚庆祝了它的 10 周年,但大多数工程师仍然对其复杂性感到困惑(Stack Overflow 上历来投票最高的 5 个问题中就有 3 个与 Git 相关)。由于 Git 能将简单操作都变成令人费解的命令(比如用“git add”暂存,却要用“git reset HEAD”取消暂存,这谁懂啊?),难怪用户会浪费时间、感到沮丧、不得不打扰团队其他人寻求帮助,更糟的是,还可能搞乱自己的代码库!

GitUp 旨在开创一种全新的 Git 交互模式,让各个层级的工程师都能快速、安全、无烦恼地工作。无论是其构建方式(直接与磁盘上的 Git 数据库交互),还是其工作方式(直接操作仓库图谱而非提交记录),都与市面上其他 Git 客户端截然不同。

有了 GitUp,你将获得一款真正高效的 Mac Git 客户端:

  • 实时交互式仓库图谱(编辑、重排、修正、合并提交……),
  • 几乎所有操作都支持无限撤销/重做(甚至包括变基和合并),
  • 类似 Time Machine 的快照功能,一键回滚到仓库之前的状态,
  • 一些 Git 原生并不存在的功能,例如可视化提交拆分器统一的引用日志浏览器
  • 即时搜索整个仓库,包括差异内容,
  • 快得离谱的用户界面,通常比命令行还要快。

此外,GitUp 的核心和主要 UI 元素作为开源框架 GitUpKit 提供。你可以用它来构建自己的 Git GUI!GitUpKit 已经催生出了一些独特的应用:

  • Retcon**,**一款让重写历史记录变得快速且灵活的 Git 客户端

GitUp 由 @swisspol 于 2014 年底创建,旨在重新定义开发者与 Git 的交互方式。经过数月的开发,它于 2015 年初发布预览版,并登上了 Hacker News 榜首,同时被 Product HuntDaring Fireball 专题报道。在编写了 30,000 行代码后,GitUp 于 2015 年 8 月中旬迎来 1.0 版本,并作为给开发者社区的礼物开源发布。

入门指南

下载方式:

请阅读 文档,并通过 GitHub Issues 获取支持和提供反馈。

发布说明可在 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 项目并点击“运行”。

重要提示: 如果您没有用于 Mac 应用代码签名的开发者账户 Apple ID,构建将因代码签名错误而失败。只需删除“Application”目标的“Code Signing Identity”构建设置即可解决此问题:

或者,如果您有开发者账户,可以创建文件“Xcode-Configurations/DEVELOPMENT_TEAM.xcconfig”,并在其中添加以下构建设置内容:

DEVELOPMENT_TEAM = [您的 TeamID]

有关详细说明,您可以查看文件“Xcode-Configurations/Base.xcconfig”末尾的注释。

GitUpKit

GitUp 构建于一个名为“GitUpKit”的可复用通用 Git 工具包之上,自身仅作为一层轻量封装。这意味着您也可以使用同一个 GitUpKit 框架来构建您自己的 Git UI!

GitUpKit 的目标与 ObjectiveGit 有很大不同。它并非提供对 libgit2 的全面原始绑定,而是仅使用 libgit2 的最小子集,并在此基础上重新实现了其他所有功能(例如,它拥有自己的“变基引擎”)。 这使得它能够提供一套紧密且一致的 API,完全遵循 Objective-C 约定,并隐藏了 libgit2 的复杂性及偶尔出现的不一致性。此外,GitUpKit 还添加了许多独特而强大的功能,从撤销/重做、类 Time Machine 快照,到完整的即插即用 UI 组件。

架构

GitUpKit 源代码分为两个独立层,仅通过公共 API 进行通信:

基础层(仅依赖 Foundation,兼容 OS X 和 iOS)

  • Core/:对 libgit2 所需最小功能的封装,GitUp 所需的所有 Git 功能均在此基础上实现(请注意,GitUp 使用 经过略微定制的 libgit2 分支
  • Extensions/Core 类的分类,用于添加仅使用公共 API 实现的便捷功能

UI 层(依赖 AppKit,仅兼容 OS X)

  • Interface/:低级视图类,例如用于渲染 GitUp 地图视图的 GIGraphView
  • Utilities/:界面工具类,例如基础视图控制器类 GIViewController
  • Components/:可重用的单视图视图控制器,例如用于渲染差异的 GIDiffContentsViewController
  • Views/:高级可重用多视图视图控制器,例如用于实现整个 GitUp 高级提交视图的 GIAdvancedCommitViewController

重要提示:如果在构建 GitUpKit 时将预处理器常量 DEBUG 定义为非零值(这是“Debug”配置下构建的默认设置),则会在运行时启用大量额外的一致性检查以及额外的日志记录。请注意,此开销可能会显著影响性能。

GitUpKit API

GitUpKit API 的使用应该非常简单直观,因为它是按功能(例如仓库、分支、提交、界面组件等)组织的,并且已尽力清晰地命名函数。

关于“Core”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]);

完整示例 #1:GitDown

GitDown 是一款非常基础的应用,它会提示用户输入仓库信息,并显示该仓库中存储的交互式实时更新列表(在 -[AppDelegate applicationDidFinishLaunching:] 中仅用约 20 行代码实现):

借助 GitUpKit,这款基础应用还能免费获得无限撤销/重做、统一和并排差异比较、文本选择与复制、键盘快捷键等功能。

此源代码还演示了如何使用 GitUpKit 的其他一些视图控制器,以及如何构建自定义的视图控制器。

完整示例 #2:GitDiff

GitDiff 演示了如何创建一个视图控制器,以 git diff HEAD 的风格显示 HEAD 与工作区之间的实时更新差异:

完整示例 #3:GitY

GitY 是一个 GitX 克隆版,使用 GitUpKit 构建,代码量不到 200 行:

完整示例 #4:iGit

iGit 是一个测试性 iOS 应用,它仅使用 GitUpKit 来克隆 GitHub 仓库并执行提交操作。

贡献

详见 CONTRIBUTING.md

致谢

同时,非常感谢 libgit2 的优秀贡献者们,没有他们,GitUp 就不可能存在!

许可协议

GitUp 版权所有 2015-2018 Pierre-Olivier Latour,基于 GPL v3 许可协议 发布。有关更多信息,请参阅项目中的 LICENSE 文件。

重要提示: GitUp 包含一些其他开源项目,这些项目仍遵循其各自的许可协议。

项目介绍

您一直苦寻未得的 Git 界面终于问世了。【此简介由AI生成】

定制我的领域
19312.12 K1.49 K访问 GitHub