Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit 417881b

Browse files
Merge pull request #999 from github-for-unity/file-history-view
File History Window
2 parents 3daf9a4 + a1ec31c commit 417881b

23 files changed

+837
-140
lines changed

src/GitHub.Api/Application/ApiClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,20 +469,20 @@ private GitHubUser GetValidatedGitHubUser()
469469
}
470470
}
471471

472-
class GitHubHostMeta
472+
public class GitHubHostMeta
473473
{
474474
public bool VerifiablePasswordAuthentication { get; set; }
475475
public string GithubServicesSha { get; set; }
476476
public string InstalledVersion { get; set; }
477477
}
478478

479-
class GitHubUser
479+
public class GitHubUser
480480
{
481481
public string Name { get; set; }
482482
public string Login { get; set; }
483483
}
484484

485-
class GitHubRepository
485+
public class GitHubRepository
486486
{
487487
public string Name { get; set; }
488488
public string CloneUrl { get; set; }

src/GitHub.Api/Application/IApiClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace GitHub.Unity
44
{
5-
interface IApiClient
5+
public interface IApiClient
66
{
77
HostAddress HostAddress { get; }
88
void CreateRepository(string name, string description, bool isPrivate,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
namespace GitHub.Unity
22
{
3-
class Organization
3+
public class Organization
44
{
55
public string Name { get; set; }
66
public string Login { get; set; }
77
}
8-
}
8+
}

src/GitHub.Api/Cache/CacheContainer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public void Dispose()
9090

9191
public IBranchCache BranchCache { get { return (IBranchCache)caches[CacheType.Branches].Value; } }
9292
public IGitLogCache GitLogCache { get { return (IGitLogCache)caches[CacheType.GitLog].Value; } }
93+
public IGitFileLogCache GitFileLogCache { get { return (IGitFileLogCache)caches[CacheType.GitFileLog].Value; } }
9394
public IGitAheadBehindCache GitTrackingStatusCache { get { return (IGitAheadBehindCache)caches[CacheType.GitAheadBehind].Value; } }
9495
public IGitStatusCache GitStatusEntriesCache { get { return (IGitStatusCache)caches[CacheType.GitStatus].Value; } }
9596
public IGitLocksCache GitLocksCache { get { return (IGitLocksCache)caches[CacheType.GitLocks].Value; } }

src/GitHub.Api/Cache/CacheInterfaces.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public enum CacheType
99
RepositoryInfo,
1010
Branches,
1111
GitLog,
12+
GitFileLog,
1213
GitAheadBehind,
1314
GitStatus,
1415
GitLocks,
@@ -22,6 +23,7 @@ public interface ICacheContainer : IDisposable
2223

2324
IBranchCache BranchCache { get; }
2425
IGitLogCache GitLogCache { get; }
26+
IGitFileLogCache GitFileLogCache { get; }
2527
IGitAheadBehindCache GitTrackingStatusCache { get; }
2628
IGitStatusCache GitStatusEntriesCache { get; }
2729
IGitLocksCache GitLocksCache { get; }
@@ -115,6 +117,11 @@ public interface IGitLogCache : IManagedCache
115117
List<GitLogEntry> Log { get; set; }
116118
}
117119

120+
public interface IGitFileLogCache : IManagedCache
121+
{
122+
GitFileLog FileLog { get; set; }
123+
}
124+
118125
public interface ICanUpdate<T>
119126
{
120127
void UpdateData(T data);

src/GitHub.Api/Git/GitClient.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,15 @@ public interface IGitClient
208208
/// <returns>String output of git command</returns>
209209
ITask<string> DiscardAll(IOutputProcessor<string> processor = null);
210210

211+
/// <summary>
212+
/// Executes at least one `git checkout` command to checkout files at the given changeset
213+
/// </summary>
214+
/// <param name="changeset">The md5 of the changeset</param>
215+
/// <param name="files">The files to check out</param>
216+
/// <param name="processor">A custom output processor instance</param>
217+
/// <returns>String output of git command</returns>
218+
ITask<string> CheckoutVersion(string changeset, IList<string> files, IOutputProcessor<string> processor = null);
219+
211220
/// <summary>
212221
/// Executes at least one `git reset HEAD` command to remove files from the git index.
213222
/// </summary>
@@ -250,6 +259,14 @@ public interface IGitClient
250259
/// <returns><see cref="List&lt;T&gt;"/> of <see cref="GitLogEntry"/> output</returns>
251260
ITask<List<GitLogEntry>> Log(BaseOutputListProcessor<GitLogEntry> processor = null);
252261

262+
/// <summary>
263+
/// Executes `git log -- <file>` to get the history of a specific file.
264+
/// </summary>
265+
/// <param name="file"></param>
266+
/// <param name="processor">A custom output processor instance</param>
267+
/// <returns><see cref="List&lt;T&gt;"/> of <see cref="GitLogEntry"/> output</returns>
268+
ITask<List<GitLogEntry>> LogFile(string file, BaseOutputListProcessor<GitLogEntry> processor = null);
269+
253270
/// <summary>
254271
/// Executes `git --version` to get the git version.
255272
/// </summary>
@@ -341,6 +358,22 @@ public ITask<List<GitLogEntry>> Log(BaseOutputListProcessor<GitLogEntry> process
341358
.Then((success, list) => success ? list : new List<GitLogEntry>());
342359
}
343360

361+
///<inheritdoc/>
362+
public ITask<List<GitLogEntry>> LogFile(string file, BaseOutputListProcessor<GitLogEntry> processor = null)
363+
{
364+
if (file == NPath.Default)
365+
{
366+
return new FuncTask<List<GitLogEntry>>(cancellationToken, () => new List<GitLogEntry>(0));
367+
}
368+
369+
return new GitLogTask(file, new GitObjectFactory(environment), cancellationToken, processor)
370+
.Configure(processManager)
371+
.Catch(exception => exception is ProcessException &&
372+
exception.Message.StartsWith("fatal: your current branch") &&
373+
exception.Message.EndsWith("does not have any commits yet"))
374+
.Then((success, list) => success ? list : new List<GitLogEntry>());
375+
}
376+
344377
///<inheritdoc/>
345378
public ITask<TheVersion> Version(IOutputProcessor<TheVersion> processor = null)
346379
{
@@ -565,6 +598,13 @@ public ITask<string> DiscardAll(IOutputProcessor<string> processor = null)
565598
.Configure(processManager);
566599
}
567600

601+
///<inheritdoc/>
602+
public ITask<string> CheckoutVersion(string changeset, IList<string> files, IOutputProcessor<string> processor = null)
603+
{
604+
return new GitCheckoutTask(changeset, files, cancellationToken, processor)
605+
.Configure(processManager);
606+
}
607+
568608
///<inheritdoc/>
569609
public ITask<string> Remove(IList<string> files,
570610
IOutputProcessor<string> processor = null)

src/GitHub.Api/Git/GitFileLog.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace GitHub.Unity
5+
{
6+
[Serializable]
7+
public struct GitFileLog
8+
{
9+
public static GitFileLog Default = new GitFileLog(null, new List<GitLogEntry>(0));
10+
11+
public string path;
12+
public List<GitLogEntry> logEntries;
13+
14+
public GitFileLog(string path, List<GitLogEntry> logEntries)
15+
{
16+
this.path = path;
17+
this.logEntries = logEntries;
18+
}
19+
20+
public string Path
21+
{
22+
get { return path; }
23+
set { path = value; }
24+
}
25+
26+
public List<GitLogEntry> LogEntries
27+
{
28+
get { return logEntries; }
29+
set { logEntries = value; }
30+
}
31+
}
32+
}

src/GitHub.Api/Git/IRepository.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public interface IRepository : IEquatable<IRepository>, IDisposable, IBackedByCa
2121
ITask RequestLock(NPath file);
2222
ITask ReleaseLock(NPath file, bool force);
2323
ITask DiscardChanges(GitStatusEntry[] discardEntries);
24+
ITask CheckoutVersion(string changeset, IList<string> files);
2425

2526
/// <summary>
2627
/// Gets the name of the repository.
@@ -61,8 +62,10 @@ public interface IRepository : IEquatable<IRepository>, IDisposable, IBackedByCa
6162
List<GitLogEntry> CurrentLog { get; }
6263
bool IsBusy { get; }
6364
string CurrentHead { get; }
65+
GitFileLog CurrentFileLog { get; }
6466

6567
event Action<CacheUpdateEvent> LogChanged;
68+
event Action<CacheUpdateEvent> FileLogChanged;
6669
event Action<CacheUpdateEvent> TrackingStatusChanged;
6770
event Action<CacheUpdateEvent> StatusEntriesChanged;
6871
event Action<CacheUpdateEvent> CurrentBranchChanged;
@@ -78,7 +81,8 @@ public interface IRepository : IEquatable<IRepository>, IDisposable, IBackedByCa
7881
ITask DeleteBranch(string branch, bool force);
7982
ITask CreateBranch(string branch, string baseBranch);
8083
ITask SwitchBranch(string branch);
84+
ITask UpdateFileLog(string path);
8185
void Refresh(CacheType cacheType);
8286
event Action<IProgress> OnProgress;
8387
}
84-
}
88+
}

src/GitHub.Api/Git/Repository.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ sealed class Repository : IEquatable<Repository>, IRepository
2525
private HashSet<CacheType> cacheInvalidationRequests = new HashSet<CacheType>();
2626
private Dictionary<CacheType, Action<CacheUpdateEvent>> cacheUpdateEvents;
2727
private ProgressReporter progressReporter = new ProgressReporter();
28+
private string lastFileLog;
2829

2930
public event Action<CacheUpdateEvent> LogChanged;
31+
public event Action<CacheUpdateEvent> FileLogChanged;
3032
public event Action<CacheUpdateEvent> TrackingStatusChanged;
3133
public event Action<CacheUpdateEvent> StatusEntriesChanged;
3234
public event Action<CacheUpdateEvent> CurrentBranchChanged;
@@ -63,6 +65,7 @@ public Repository(NPath localPath, ICacheContainer container)
6365
{ CacheType.GitAheadBehind, c => TrackingStatusChanged?.Invoke(c) },
6466
{ CacheType.GitLocks, c => LocksChanged?.Invoke(c) },
6567
{ CacheType.GitLog, c => LogChanged?.Invoke(c) },
68+
{ CacheType.GitFileLog, c => FileLogChanged?.Invoke(c) },
6669
{ CacheType.GitStatus, c => StatusEntriesChanged?.Invoke(c) },
6770
{ CacheType.GitUser, cacheUpdateEvent => { } },
6871
{ CacheType.RepositoryInfo, cacheUpdateEvent => {
@@ -91,6 +94,7 @@ public void Initialize(IRepositoryManager theRepositoryManager, ITaskManager the
9194
this.repositoryManager.GitStatusUpdated += RepositoryManagerOnGitStatusUpdated;
9295
this.repositoryManager.GitAheadBehindStatusUpdated += RepositoryManagerOnGitAheadBehindStatusUpdated;
9396
this.repositoryManager.GitLogUpdated += RepositoryManagerOnGitLogUpdated;
97+
this.repositoryManager.GitFileLogUpdated += RepositoryManagerOnGitFileLogUpdated;
9498
this.repositoryManager.GitLocksUpdated += RepositoryManagerOnGitLocksUpdated;
9599
this.repositoryManager.LocalBranchesUpdated += RepositoryManagerOnLocalBranchesUpdated;
96100
this.repositoryManager.RemoteBranchesUpdated += RepositoryManagerOnRemoteBranchesUpdated;
@@ -138,11 +142,17 @@ public ITask SetupRemote(string remote, string remoteUrl)
138142
public ITask RequestLock(NPath file) => repositoryManager.LockFile(file);
139143
public ITask ReleaseLock(NPath file, bool force) => repositoryManager.UnlockFile(file, force);
140144
public ITask DiscardChanges(GitStatusEntry[] gitStatusEntry) => repositoryManager.DiscardChanges(gitStatusEntry);
145+
public ITask CheckoutVersion(string changeset, IList<string> files) => repositoryManager.CheckoutVersion(changeset, files);
141146
public ITask RemoteAdd(string remote, string url) => repositoryManager.RemoteAdd(remote, url);
142147
public ITask RemoteRemove(string remote) => repositoryManager.RemoteRemove(remote);
143148
public ITask DeleteBranch(string branch, bool force) => repositoryManager.DeleteBranch(branch, force);
144149
public ITask CreateBranch(string branch, string baseBranch) => repositoryManager.CreateBranch(branch, baseBranch);
145150
public ITask SwitchBranch(string branch) => repositoryManager.SwitchBranch(branch);
151+
public ITask UpdateFileLog(string path)
152+
{
153+
lastFileLog = path;
154+
return repositoryManager.UpdateFileLog(path);
155+
}
146156

147157
public void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent) => cacheContainer.CheckAndRaiseEventsIfCacheNewer(cacheType, cacheUpdateEvent);
148158

@@ -215,6 +225,10 @@ private void CacheHasBeenInvalidated(CacheType cacheType)
215225
repositoryManager?.UpdateGitLog().Catch(ex => InvalidationFailed(ex, cacheType)).Start();
216226
break;
217227

228+
case CacheType.GitFileLog:
229+
repositoryManager?.UpdateFileLog(lastFileLog).Catch(ex => InvalidationFailed(ex, cacheType)).Start();
230+
break;
231+
218232
case CacheType.GitAheadBehind:
219233
repositoryManager?.UpdateGitAheadBehindStatus().Catch(ex => InvalidationFailed(ex, cacheType)).Start();
220234
break;
@@ -295,6 +309,11 @@ private void RepositoryManagerOnGitLogUpdated(List<GitLogEntry> gitLogEntries)
295309
taskManager.RunInUI(() => cacheContainer.GitLogCache.Log = gitLogEntries);
296310
}
297311

312+
private void RepositoryManagerOnGitFileLogUpdated(GitFileLog gitFileLog)
313+
{
314+
taskManager.RunInUI(() => cacheContainer.GitFileLogCache.FileLog = gitFileLog);
315+
}
316+
298317
private void RepositoryManagerOnGitLocksUpdated(List<GitLock> gitLocks)
299318
{
300319
taskManager.RunInUI(() => cacheContainer.GitLocksCache.GitLocks = gitLocks);
@@ -360,6 +379,7 @@ public void Dispose()
360379
public string CurrentBranchName => CurrentConfigBranch?.Name;
361380
public GitRemote? CurrentRemote => cacheContainer.RepositoryInfoCache.CurrentGitRemote;
362381
public List<GitLogEntry> CurrentLog => cacheContainer.GitLogCache.Log;
382+
public GitFileLog CurrentFileLog => cacheContainer.GitFileLogCache.FileLog;
363383
public List<GitLock> CurrentLocks => cacheContainer.GitLocksCache.GitLocks;
364384
public string CurrentHead => cacheContainer.RepositoryInfoCache.CurrentHead;
365385

src/GitHub.Api/Git/RepositoryManager.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public interface IRepositoryManager : IDisposable
1313
event Action<GitStatus> GitStatusUpdated;
1414
event Action<List<GitLock>> GitLocksUpdated;
1515
event Action<List<GitLogEntry>> GitLogUpdated;
16+
event Action<GitFileLog> GitFileLogUpdated;
1617
event Action<Dictionary<string, ConfigBranch>> LocalBranchesUpdated;
1718
event Action<Dictionary<string, ConfigRemote>, Dictionary<string, Dictionary<string, ConfigBranch>>> RemoteBranchesUpdated;
1819
event Action<GitAheadBehindStatus> GitAheadBehindStatusUpdated;
@@ -37,12 +38,15 @@ public interface IRepositoryManager : IDisposable
3738
ITask LockFile(NPath file);
3839
ITask UnlockFile(NPath file, bool force);
3940
ITask DiscardChanges(GitStatusEntry[] gitStatusEntries);
41+
ITask CheckoutVersion(string changeset, IList<string> files);
4042
ITask UpdateGitLog();
4143
ITask UpdateGitStatus();
4244
ITask UpdateGitAheadBehindStatus();
4345
ITask UpdateLocks();
4446
ITask UpdateRepositoryInfo();
4547
ITask UpdateBranches();
48+
ITask UpdateFileLog(string path);
49+
4650

4751
int WaitForEvents();
4852

@@ -136,6 +140,7 @@ class RepositoryManager : IRepositoryManager
136140
public event Action<GitAheadBehindStatus> GitAheadBehindStatusUpdated;
137141
public event Action<List<GitLock>> GitLocksUpdated;
138142
public event Action<List<GitLogEntry>> GitLogUpdated;
143+
public event Action<GitFileLog> GitFileLogUpdated;
139144
public event Action<Dictionary<string, ConfigBranch>> LocalBranchesUpdated;
140145
public event Action<Dictionary<string, ConfigRemote>, Dictionary<string, Dictionary<string, ConfigBranch>>> RemoteBranchesUpdated;
141146

@@ -341,6 +346,13 @@ public ITask DiscardChanges(GitStatusEntry[] gitStatusEntries)
341346
return HookupHandlers(task, true);
342347
}
343348

349+
public ITask CheckoutVersion(string changeset, IList<string> files)
350+
{
351+
var task = GitClient.CheckoutVersion(changeset, files)
352+
.Then(() => DataNeedsRefreshing?.Invoke(CacheType.GitStatus));
353+
return HookupHandlers(task, false);
354+
}
355+
344356
public ITask UpdateGitLog()
345357
{
346358
var task = GitClient.Log()
@@ -354,6 +366,20 @@ public ITask UpdateGitLog()
354366
return HookupHandlers(task, false);
355367
}
356368

369+
public ITask UpdateFileLog(string path)
370+
{
371+
var task = GitClient.LogFile(path)
372+
.Then((success, logEntries) =>
373+
{
374+
if (success)
375+
{
376+
var gitFileLog = new GitFileLog(path, logEntries);
377+
GitFileLogUpdated?.Invoke(gitFileLog);
378+
}
379+
});
380+
return HookupHandlers(task, false);
381+
}
382+
357383
public ITask UpdateGitStatus()
358384
{
359385
var task = GitClient.Status()
@@ -644,6 +670,7 @@ private void Dispose(bool disposing)
644670
GitStatusUpdated = null;
645671
GitAheadBehindStatusUpdated = null;
646672
GitLogUpdated = null;
673+
GitFileLogUpdated = null;
647674
GitLocksUpdated = null;
648675
LocalBranchesUpdated = null;
649676
RemoteBranchesUpdated = null;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy