Select Git revision
-
Benoît Minisini authored
* BUG: Version control: Correctly trim the identity name and e-mail. * NEW: Version control: Display a big label when there is no change to commit. * NEW: Version control: Correctly update 'Change' tab when there is no change to commit.
Benoît Minisini authored* BUG: Version control: Correctly trim the identity name and e-mail. * NEW: Version control: Display a big label when there is no change to commit. * NEW: Version control: Correctly update 'Change' tab when there is no change to commit.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CVersionControlGit.class 14.49 KiB
' Gambas class file
Inherits CVersionControl
Create Static
Public Const Name As String = "Git"
Public Const LongName As String = "Git"
Public Const DoNotPush As Boolean = True
Public Const CancelUpdate As Boolean = True
Public Const NeedMove As Boolean = False
Public Const CanCreateBranch As Boolean = True
Public Const HasIdentity As Boolean = True
Private $aConflict As String[] = ["DD", "AU", "UD", "UA", "DU", "AA", "UU"]
Private $bHasGit As Boolean
Private $bCheckGit As Boolean
Private $sRoot As String
Private $bCanControl As Boolean
Private $bCanInit As Boolean
Private $bHasRemote As Boolean
' Private $iPadHistory As Integer
' Private $hHighlightDiff As TextHighlighter
Private Sub Init()
If $bCheckGit Then Return
$bHasGit = System.Exist("git")
$bCheckGit = True
End
Private Sub RunShell(sCmd As String, Optional bSilent As Boolean) As String
Return VersionControl.Shell("cd " & Shell(Project.Dir) & " && " & sCmd, bSilent)
End
Static Public Sub FindRoot(Optional sDir As String) As String
Dim sPath As String
Dim sData As String
If Not sDir Then sDir = Project.Dir
While Len(sDir) > 1
sPath = sDir &/ ".git"
If Exist(sPath) Then
If Exist(sPath &/ "HEAD") Then Return sDir &/ ".git"
Try sData = File.Load(sPath)
If sData Begins "gitdir:" Then Return LTrim(Mid$(sData, 8, -1))
Endif
sDir = File.Dir(sDir)
Wend
End
Public Sub Check() As Boolean
Dim sResult As String
Dim sRoot As String
Init()
If $bHasGit Then
'sResult = RunShell("git status --porcelain .project")
Exec ["git", "status", "--porcelain", ".project"] With ["PWD=" & Project.Dir] To sResult
If Process.LastValue Then
$bCanInit = True
$bCanControl = False
Else
$bCanInit = False
$bCanControl = sResult Begins "??"
If Not $bCanControl Then
sRoot = FindRoot()
If sRoot Then
$sRoot = File.Dir(sRoot)
'$bHasRemote = RunShell("git remote show")
Exec ["git", "remote", "show"] With ["PWD=" & Project.Dir] To sResult
$bHasRemote = Trim(sResult)
Return True
Endif
Endif
Endif
Endif
End
Public Sub GetCurrentBranch() As String
' Works only with git > 2.22
' Return Trim(RunShell("git branch --show-current"))
Return Trim(RunShell("git rev-parse --abbrev-ref HEAD"))
End
Public Sub GetBranches(ByRef sCurrent As String) As String[]
Dim sResult As String
Dim sBranch As String
Dim aBranches As New String[]
Dim bCurrent As Boolean
sResult = RunShell("git branch -a", True)
For Each sBranch In Split(Trim(sResult), "\n")
sBranch = Trim(sBranch)
If sBranch Begins "*" Then
sBranch = Trim(Mid$(sBranch, 2))
bCurrent = True
Else
bCurrent = False
If sBranch Begins "+ " Then sBranch = Mid$(sBranch, 3)
Endif
If sBranch Begins "remotes/origin/" Then
sBranch = Mid$(sBranch, 16)
If InStr(sBranch, " -> ") Then Continue
Endif
If bCurrent Then sCurrent = sBranch
If Not aBranches.Exist(sBranch) Then aBranches.Add(sBranch)
Next
aBranches.Sort(gb.Natural)
Return aBranches
End
Public Sub Diff(sPath As String, Optional bFull As Boolean, bNoWhiteSpace As Boolean) As String
Dim sDiff As String
Dim sCmd As String
Dim sHead As String
Dim sFull As String
Dim iPos As Integer
Dim sOption As String
'If VersionControl.Shell("cd " & Shell(Project.Dir) & " && git log -1", True) Then
If RunShell("git log -1", True) Then
sHead = "HEAD"
Else
sHead = "--staged"
Endif
If bFull Then sFull = " -U100000"
If bNoWhiteSpace Then sOption = " -b --ignore-blank-lines"
If IsDir(sPath) Then
sCmd = "cd " & Shell(sPath) & " && git diff" & sOption & sFull & " " & sHead & " ."
Else
sCmd = "cd " & Shell(File.Dir(sPath)) & " && git diff" & sOption & sFull & " " & sHead & " " & Shell(File.Name(sPath))
Endif
sDiff = VersionControl.Shell(sCmd)
If bFull Then
iPos = InStr(sDiff, "@@\n")
If iPos Then
sDiff = Mid$(sDiff, iPos + 3)
Else
sDiff = ""
Endif
Endif
Return sDiff
End
Public Sub History(sPath As String, Optional sPath2 As String, bFull As Boolean) As String
Dim sCmd As String
Dim sFull As String
If bFull Then sFull = "-p -b "
If IsDir(sPath) Then
sCmd = "cd " & Shell(sPath) & " && git log --date=rfc2822 " & sFull & "."
Else
sCmd = "cd " & Shell(File.Dir(sPath)) & " && git log --date=rfc2822 " & sFull & Shell(File.Name(sPath))
If sPath2 Then sCmd &= " " & Shell(File.Name(sPath2))
Endif
'Return VersionControl.Shell(sCmd)
Shell sCmd Wait
End
Public Sub Status(Optional sPath As String) As String
Dim sStatus As String
If Not sPath Then sPath = Project.Dir
sStatus = VersionControl.Shell("cd " & Shell$(sPath) & " && git status .", True)
Return sStatus
End
Public Sub GetDefaultJournal() As String
Dim aStatus As String[]
Dim I As Integer
aStatus = Split(Status(Project.Dir), "\n")
For I = 0 To aStatus.Max
aStatus[I] = "# " & aStatus[I]
Next
Return "# " & VersionControl.GetDelimChange() & "\n#\n" & aStatus.Join("\n")
End
Public Sub Update() As Integer
Dim aEnv As String[]
aEnv = VersionControl.LANG_ENV.Copy()
aEnv.Add("PWD=" & Project.Dir)
VersionControl.Run(["git", "remote", "update", "origin", "--prune"], True, True, aEnv)
Return VersionControl.Run(["git", "pull", "-q"], True, True, aEnv)
End
' Public Sub UpdatePath(aPath As String[])
'
' Dim sStatus As String
' Dim sCmd As String
' Dim sPath As String
'
' sCmd = "cd " & Shell$(Project.Dir) & " && git status -uall --porcelain -z"
' For Each sPath In aPath
' sCmd &= " " & Mid$(sPath, Len(Project.Dir) + 2)
' Next
'
' sStatus = VersionControl.Shell(sCmd, True)
' UpdatePathFromStatus(sStatus)
'
' End
Public Sub CheckPaths()
Dim sStatus As String
'sStatus = VersionControl.Shell("cd " & Shell$(Project.Dir) & " && git status -uall --porcelain -z .", True)
sStatus = RunShell("git status -uall --porcelain -z .", True)
UpdatePathFromStatus(sStatus)
End
Private Sub UpdatePathFromStatus(sStatus As String)
Dim sFile As String
Dim sPath As String
For Each sStatus In Split(sStatus, Chr$(0), "", True)
sFile = Mid$(sStatus, 4)
sPath = $sRoot &/ sFile
If sPath Not Begins Project.Dir Then Continue
If sStatus Begins "??" Then
Project.SetFlag(sPath, Project.FLAG_ADDED)
Else If $aConflict.Exist(Left(sStatus, 2)) Then
Project.SetFlag(sPath, Project.FLAG_CONFLICT)
Else If InStr("MDR", Mid$(sStatus, 2, 1)) Or If InStr("AMR", Left(sStatus)) Then
Project.SetFlag(sPath, Project.FLAG_MODIFIED)
Endif
Next
End
Public Sub AddFile(sPath As String, Optional (bForce) As Boolean)
RunShell("git add " & Shell(sPath))
End
Public Sub AddDir((sPath) As String)
' git does not track directories
' AddFile(sPath)
End
Public Sub Revert(Optional sPath As String) As Boolean
If sPath Then
RunShell("git checkout " & Shell(sPath))
Else
RunShell("git checkout " & Shell(Project.Dir))
Endif
End
Public Sub RemoveFile(sPath As String, Optional (bForce) As Boolean)
RunShell("git rm " & Shell(sPath))
End
Public Sub RemoveDir(sPath As String)
RunShell("git rm -rf --cached " & Shell(sPath))
Shell.RmDir(sPath)
End
Public Sub Commit(sChange As String, bDoNotPush As Boolean) As Boolean
Dim sFile As String
Dim aEnv As String[]
If sChange Then
sFile = Temp$()
File.Save(sFile, sChange)
'VersionControl.Run(["git", "commit", "-F", sFile, Project.Dir], False, False, VersionControl.LANG_ENV)
RunShell("git commit -F " & Shell$(sFile) & " . 2>&1") ', Project.Dir)
If Process.LastValue Then Return True
Endif
If Not bDoNotPush And If $bHasRemote Then
aEnv = VersionControl.LANG_ENV.Copy()
aEnv.Add("PWD=" & Project.Dir)
VersionControl.Run(["git", "push"], True, True, aEnv)
If Process.LastValue Then VersionControl.ShowError(("Unable to push the project."))
Endif
End
Public Sub Info() As Collection
Dim cInfo As New Collection
Dim aResult As String[]
Dim sResult As String
Dim nModif As Integer
Dim sText As String
cInfo[("Local root path")] = $sRoot
aResult = Split(VersionControl.Shell("cd " & Shell(Project.Dir) & " && git log -n1"), "\n")
cInfo[("Last commit")] = Trim(Mid$(aResult[0], InStr(aResult[0], " ") + 1))
cInfo[("Last commit author")] = Trim(Mid$(aResult[1], InStr(aResult[1], " ") + 1))
cInfo[("Last commit date")] = Trim(Mid$(aResult[2], InStr(aResult[2], " ") + 1))
aResult = Split(RunShell("git branch -vv"), "\n")
For Each sResult In aResult
If sResult Begins "*" Then
aResult = Scan(sResult, "* * * [[]*] *")
If aResult.Count = 0 Then aResult = Scan(sResult, "* * *")
cInfo[("Current branch")] = aResult[1]
If aResult.Count >= 4 Then cInfo[("Origin")] = aResult[3]
Break
Endif
Next
Try nModif = Split(Trim(RunShell("git status --porcelain")), "\n").Count
If nModif = 0 Then
sText = ("The current branch is up to date.")
Else If nModif = 1 Then
sText = ("One file to commit in the current branch.")
Else
sText = Subst(("&1 files to commit in the current branch."), nModif)
Endif
If nModif Then
Try nModif = Split(Trim(RunShell("git status --porcelain " & Shell(Project.Dir))), "\n").Count
sText &= "\n"
If nModif = 0 Then
sText &= ("None in the current project.")
Else If nModif = 1 Then
sText &= ("One in the current project.")
Else
sText &= Subst(("&1 in the current project."), nModif)
Endif
Endif
cInfo[("Status")] = sText
aResult = Split(RunShell("git remote -vv"), "\n")
Try cInfo[("Remote repository URL")] = Scan(aResult[0], "* * *")[1]
Return cInfo
End
Public Sub SetBranch(sBranch As String)
RunShell("git checkout " & Shell(sBranch) & " 2>&1")
End
Public Sub MoveFile(sOld As String, sNew As String)
RunShell("git mv " & Shell(sOld) & " " & Shell(sNew) & " && git add " & Shell(sNew))
If Exist(sOld) And If Not Exist(sNew) Then Move sOld To sNew
End
Public Sub MoveDir(sOld As String, sNew As String) As Boolean
MoveFile(sOld, sNew)
End
Public Sub UpdatePath(sPath As String, Optional sPath2 As String)
Dim sStatus As String
Dim sCmd As String
' svn status is automatically recursive!
sCmd = "cd " & Shell$(Project.Dir) & "; git status -uall --porcelain -z " & Shell(Project.MakeRelativePath(sPath))
If sPath2 Then sCmd &= " " & Shell(Project.MakeRelativePath(sPath2))
sStatus = VersionControl.Shell(sCmd, True)
UpdatePathFromStatus(sStatus)
End
Public Sub CanControlProject() As Boolean
Return $bCanControl Or $bCanInit
End
Public Sub ControlProject() As Boolean
If Not CanControlProject() Then Return True
If $bCanInit Then
If Message.Warning(("A new Git repository will be created for this project."), ("OK"), ("Cancel")) = 2 Then Return
RunShell("git init && git add .")
If Process.LastValue Then Return True
Else
RunShell("git add .")
Endif
End
Public Sub HasRemote() As Boolean
Return $bHasRemote
End
Public Sub SolveConflict(sPath As String, Optional iAccept As Integer) As Boolean
If iAccept Then
Select iAccept
Case VersionControl.ACCEPT_OURS
RunShell("git checkout --ours " & Shell$(sPath))
Case VersionControl.ACCEPT_THEIRS
RunShell("git checkout --theirs " & Shell$(sPath))
End Select
Return Process.LastValue
Endif
RunShell("git add " & Shell$(sPath))
If Process.LastValue Then Return True
VersionControl.CheckPaths()
If Project.HasConflict Then Return
'FVersionControl.Run(True)
RunShell("git commit -m " & Shell$(("Solve conflict."))) ', Project.Dir)
End
' Private Sub FormatDate(sDate As String) As String
'
' Dim dDate As Date
'
' Try dDate = Date.FromRFC822(sDate)
' If Not dDate Then Return "?"
' Return Format(dDate, gb.LongDate)
'
' End
Public Sub InitHistory(hEditor As TextEditor)
hEditor.Highlight = "commit_git"
End
' Fast Public Sub HighlightHistory(Text As String)
'
' Dim iState As Integer
' Dim iLen As Integer
'
' iState = TextHighlighter.State
' iLen = String.Len(Text)
'
' TextHighlighter.Limit = False
'
' If $iPadHistory = 0 Then
' $iPadHistory = Max(Max(String.Len(("Date")), String.Len(("Author"))), String.Len("Commit"))
' Endif
'
' TextHighlighter.Alternate = True
' If Text Begins "commit " Then
' TextHighlighter.TextAfter = String.PadRight("Commit", $iPadHistory) & " : " & Mid$(Text, 8)
' TextHighlighter.Add(Highlight.DataType, String.Len(TextHighlighter.TextAfter))
' 'TextHighlighter.Add(Highlight.DataType, String.Len(Text))
' TextHighlighter.Limit = True
' Else If Text Begins "Merge: " Then
' TextHighlighter.TextAfter = String.PadRight("Merge", $iPadHistory) & " : " & Mid$(Text, 8)
' TextHighlighter.Add(Highlight.Number, String.Len(TextHighlighter.TextAfter))
' 'TextHighlighter.Add(Highlight.DataType, String.Len(Text))
' TextHighlighter.Limit = True
' Else If Text Begins "Author: " Then
' TextHighlighter.TextAfter = String.PadRight(("Author"), $iPadHistory) & " : " & Mid$(Text, 9)
' TextHighlighter.Add(Highlight.Function, String.Len(TextHighlighter.TextAfter))
' 'TextHighlighter.Add(Highlight.Function, String.Len(Text))
' Else If Text Begins "Date: " Then
' TextHighlighter.TextAfter = String.PadRight(("Date"), $iPadHistory) & " : " & FormatDate(Mid$(Text, 7))
' TextHighlighter.Add(Highlight.Preprocessor, String.Len(TextHighlighter.TextAfter))
' 'TextHighlighter.Add(Highlight.Preprocessor, String.Len(Text))
' Else
' TextHighlighter.Alternate = False
' If Not $hHighlightDiff Then $hHighlightDiff = TextHighlighter["diff"]
' $hHighlightDiff.Run(Text)
' 'TextHighlighter.Add(Highlight.Normal, iLen)
' Endif
'
' End
Public Sub GetRoot() As String
Return $sRoot
End
Public Sub CreateBranch(sNewBranch As String) As Boolean
RunShell("git branch " & Shell(sNewBranch))
If Process.LastValue Then Return True
End
Public Sub GetIdentity(ByRef sName As String, ByRef sEmail As String)
Try sName = Trim(RunShell("git config user.name"))
Try sEmail = Trim(RunShell("git config user.email"))
End
Public Sub SetIdentity(sName As String, sMail As String)
If sName Then
RunShell("git config user.name " & Shell$(sName))
Else
RunShell("git config user.name --unset")
Endif
If sMail Then
RunShell("git config user.email " & Shell$(sMail))
Else
RunShell("git config user.email --unset")
Endif
End