Git Branch watcher
Posted: Tue Feb 21, 2012 5:27 pm
Hi,
I just needed a tool that shows me the current branch of my GIT repositories. I think it may be helpful for some of you.
Currently running only on Windows, because of some API tricks to make opaque windows. Would be great to have this for Linux, too
Compile and call it like this (I use a shortcut):
GitBranchWatch.exe "RepoFolder" "GITexecutable"
The RepoFolder must be the folder your GIT folders are inside.
GITexecutable is the complete path of your git executable.
Example:
GitBranchWatch.exe "c:\git_sources" "C:\Programme\msysgit\msysgit\cmd\git.cmd"
It's just quick and dirty and not really clean source, but I just needed about 4 hours to do and some 2 hours to optimize (threads etc.).
It is limited to a maximum of 100 repositories, but mostly your screen will be the limit (on my 1680 pixel screen, the limit is about 15 repositories). It actualizes the state about every 10 seconds. Because of tasks, it benefits from multi-core processors and hyper-threading.
Kukulkan
I just needed a tool that shows me the current branch of my GIT repositories. I think it may be helpful for some of you.
Currently running only on Windows, because of some API tricks to make opaque windows. Would be great to have this for Linux, too

Compile and call it like this (I use a shortcut):
GitBranchWatch.exe "RepoFolder" "GITexecutable"
The RepoFolder must be the folder your GIT folders are inside.
GITexecutable is the complete path of your git executable.
Example:
GitBranchWatch.exe "c:\git_sources" "C:\Programme\msysgit\msysgit\cmd\git.cmd"
Code: Select all
; GIT Branch watch
; PB 4.51 / Windows / threadsafe / singlebyte
EnableExplicit
; --- SOME SETTINGS ---
#WindowWidth = 100 ; width of the repo windows
#FontSize = 6 ; font size for repo info
Global globalColorChanged = RGB(255,255,240)
Global globalColorMaster = RGB(150,255,150)
; --- structure and repo-array definition ---
Structure structRepo
Folder.s
Name.s
WinID.i
LabelID.i
Branch.s
LastWindowOffset.i
LastBranch.s
EndStructure
Global Dim Repositorys.structRepo(100)
; --- check threadsave compiler switch ---
CompilerIf #PB_Compiler_Thread = 0
MessageRequester("GitBranchWatch", "Need to compile threadsafe!")
End
CompilerEndIf
; --- CHECK COMMANDLINE PARAMETERS ---
Global RepositoryFolder.s = ProgramParameter()
Global GitCommandline.s = ProgramParameter()
If RepositoryFolder.s = "" Or GitCommandline.s = ""
MessageRequester("GitBranchWatch", "Please give me RepoFolder and git commandline as parameters!")
End
EndIf
If Right(RepositoryFolder.s, 1) <> "\"
RepositoryFolder.s = RepositoryFolder.s + "\"
EndIf
If FileSize(GitCommandline.s) < 1
MessageRequester("GitBranchWatch", "Can not find the given GIT executable!")
End
EndIf
ExamineDesktops()
; =========================================
; THREAD to actualize the repository status
; =========================================
Procedure ThreadRefresh(Offset)
Protected x, Compiler, Output.s, Branch.s
Repeat
For x = Offset To 99 Step 2
If Repositorys(x)\Folder <> ""
; Debug "GetRepo status of repo <" + Repositorys(x)\Name + ">"
SetCurrentDirectory(Repositorys(x)\Folder)
Compiler = RunProgram(GitCommandline.s, "status", "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
Output.s = ""
If Compiler
While ProgramRunning(Compiler)
If AvailableProgramOutput(Compiler)
Output.s + ReadProgramString(Compiler) + Chr(10)
EndIf
Wend
Output.s + Chr(10)
CloseProgram(Compiler)
Else
Debug "can not run GIT executable with 'status' in folder " + Repositorys(x)\Folder
EndIf
Output.s + Chr(10)
; Debug Output
Protected Pos = FindString(Output.s, "# On branch", 1)
If Pos > 0
Protected EndPos = FindString(Output.s, Chr(10), Pos)
Branch.s = Mid(Output.s, Pos, EndPos - Pos)
Branch.s = Trim(Mid(Branch.s, 12))
Else
Branch = "err"
EndIf
Repositorys(x)\Branch = Branch.s
Delay(10)
EndIf
Next
; wait a gui loop of 10 seconds
Delay(10000)
ForEver
EndProcedure
; =========================================
; get available repositorys from folder
;{=========================================
Define Counter.l = 0
If ExamineDirectory(0, RepositoryFolder.s, "*.*")
While NextDirectoryEntry(0)
Define FileName.s = DirectoryEntryName(0)
If DirectoryEntryType(0) = #PB_DirectoryEntry_Directory And FileName.s <> "." And FileName.s <> ".."
Repositorys(Counter.l)\Folder = RepositoryFolder.s + FileName.s
Repositorys(Counter.l)\Name = FileName.s
Repositorys(Counter.l)\WinID = 0
Repositorys(Counter.l)\LabelID = 0
; Debug "Add Repo " + FileName.s + " -> " + Repositorys(Counter.l)\Folder
Counter.l = Counter.l + 1
EndIf
Wend
Else
MessageRequester("GitBranchWatch","Can't examine this directory: " + RepositoryFolder.s)
End
EndIf
;}
; =========================================
; create window for each repository
;{=========================================
Define FontID = LoadFont(#PB_Any, "Microsoft Sans Serif", #FontSize)
Counter.l = 0
Define x
For x = 0 To 99
; create window
If Repositorys(x)\Folder <> ""
Define WinPos = DesktopWidth(0) - 2* #WindowWidth - (x * (#WindowWidth + 4))
Repositorys(x)\WinID = OpenWindow(#PB_Any, WinPos, 4, #WindowWidth, 20, "", #PB_Window_BorderLess | #PB_Window_Invisible)
Repositorys(x)\LabelID = TextGadget(#PB_Any, 0, 0, #WindowWidth, 20, Repositorys(x)\Name + #CR$ + "-", #PB_Text_Center)
SetWindowColor(Repositorys(x)\WinID, globalColorChanged)
SetGadgetColor(Repositorys(x)\LabelID, #PB_Gadget_BackColor, globalColorChanged)
SetGadgetFont(Repositorys(x)\LabelID, FontID(FontID))
SetWindowLong_(WindowID(Repositorys(x)\WinID),-20,GetWindowLong_(WindowID(Repositorys(x)\WinID),-20)|#WS_EX_TOOLWINDOW)
HideWindow(Repositorys(x)\WinID, 0)
AddKeyboardShortcut(Repositorys(x)\WinID, #PB_Shortcut_Escape, 101)
; stay topmost
StickyWindow(Repositorys(x)\WinID, 1)
; make layered to get transparent later
SetWindowLong_(WindowID(Repositorys(x)\WinID), #GWL_EXSTYLE, GetWindowLong_(WindowID(Repositorys(x)\WinID), #GWL_EXSTYLE) | #WS_EX_LAYERED);
EndIf
Next
;}
Define Quit = #False
; =========================================
; Start two threads to get status.
; One thread for the even and one for the
; odd numbers.
; =========================================
Define ThreadID1 = CreateThread(@ThreadRefresh(), 0)
ThreadPriority(ThreadID1, 10) ; set lower priority
Define ThreadID2 = CreateThread(@ThreadRefresh(), 1)
ThreadPriority(ThreadID2, 10) ; set lower priority
; =========================================
; Normal GUI loop
;{=========================================
Repeat
Repeat
Define Event = WaitWindowEvent(50)
Define EventWin = EventWindow()
If Event = #PB_Event_CloseWindow ; If the user has pressed on the close button
Quit = #True
EndIf
If Event = #PB_Event_Menu
Select EventMenu()
Case 101
Quit = #True
EndSelect
EndIf
Define MouseX = DesktopMouseX()
Define MouseY = DesktopMouseY()
For x = 0 To 99
If Repositorys(x)\Folder <> ""
Define DistanceX = MouseX - WindowX(Repositorys(x)\WinID) - WindowWidth(Repositorys(x)\WinID) / 2
Define DistanceY = MouseY
Define Distance = Sqr(DistanceX * DistanceX + DistanceY * DistanceY)
Define Opacity = Distance
If Opacity > 255: Opacity = 255: EndIf
If Opacity < 0: Opacity = 0: EndIf
SetLayeredWindowAttributes_(WindowID(Repositorys(x)\WinID), 0, Opacity, 2)
Define WindowOffset = Opacity / 20 - 10
If WindowOffset <> Repositorys(x)\LastWindowOffset
; move window only, if position changed
ResizeWindow(Repositorys(x)\WinID, #PB_Ignore, WindowOffset, #PB_Ignore, #PB_Ignore)
Repositorys(x)\LastWindowOffset = WindowOffset
EndIf
If Repositorys(x)\Branch <> Repositorys(x)\LastBranch
If Repositorys(x)\Branch = "master"
SetWindowColor(Repositorys(x)\WinID, globalColorMaster)
SetGadgetColor(Repositorys(x)\LabelID, #PB_Gadget_BackColor, globalColorMaster)
Else
SetWindowColor(Repositorys(x)\WinID, globalColorChanged)
SetGadgetColor(Repositorys(x)\LabelID, #PB_Gadget_BackColor, globalColorChanged)
EndIf
Repositorys(x)\LastBranch = Repositorys(x)\Branch
EndIf
SetGadgetText(Repositorys(x)\LabelID, Repositorys(x)\Name + ":" + #CR$ + Repositorys(x)\Branch)
EndIf
Next
Until Quit = #True
Until Quit = #True
;}
; =========================================
; Cleanup program.
;{=========================================
KillThread(ThreadID1)
KillThread(ThreadID2)
For x = 0 To 99
If Repositorys(x)\Folder <> ""
CloseWindow(Repositorys(x)\WinID)
EndIf
Next
FreeFont(FontID)
;}
End
It is limited to a maximum of 100 repositories, but mostly your screen will be the limit (on my 1680 pixel screen, the limit is about 15 repositories). It actualizes the state about every 10 seconds. Because of tasks, it benefits from multi-core processors and hyper-threading.
Kukulkan