Wednesday, April 5, 2023

They say the best way to learn is by doing, but sometimes the best way is to automate!

Ah, the version control system git. We've all been there, typing out commands to push a new commit to the server, trying to remember which is which. For example to update the remote repository with your local changes, I use the git pull, add, commit and push commands in sequence. This will ensure that the remote repository is up-to-date with the local repository. Well, I had enough of it. I decided to take matters into my own hands and wrote a script that I named 'gits'. It's just a one-liner that does the steps of git pull, git add, git commit and git push for me, without all the hassle of having to type each paticular command. The commit message is given as argument to gits, if I forget about it, the script puts the number of changed files there as a placeholder.

@echo off
:: Batch script to commit and push your git changes
:: and quickly resolve conflicts
::
:: by Wil
:: March 2023 V0.21
::
:: The script has the decency to ask before adding new files
:: If an argument is given, this is used as the commit message
:: otherwise a generic commit message is generated

setlocal ENABLEDELAYEDEXPANSION

for /F "delims=#" %%E in ('"prompt #$E# & for %%E in (1) do rem "') do set "ESCchar=%%E"
set "red=%ESCchar%[91m"
set "green=%ESCchar%[92m"
set "yellow=%ESCchar%[93m"
set "magenta=%ESCchar%[95m"
set "cyan=%ESCchar%[96m"
set "white=%ESCchar%[97m"
set "black=%ESCchar%[30m"
set "nocolor=%ESCchar%[0m"
set "bold=%ESCchar%[1m"

::stage modifications and deletions
set countmodified=0
for /f %%C in ('git ls-files -m') do set /A countmodified=!countmodified!+1

if NOT "!countmodified!"=="0" (
  git add -u
)

set /A total=!countmodified!

for /f %%C in ('git diff --cached --numstat') do set /A total=!total!+1

::check if there are untracked (new) files
set countnew=0
for /f %%C in ('git ls-files . --exclude-standard --others') do set /A countnew=!countnew!+1

if NOT "!countnew!"=="0" (
  git ls-files . --exclude-standard --others
  echo.
  echo There are !countnew! files, should they be added?
  CHOICE /C asx /M "Press [A] for adding the files, [S] for skipping without and [X] for exiting this script."
  IF !ERRORLEVEL! EQU 3 (
    exit /b
  )
  IF !ERRORLEVEL! EQU 1 (
    git add .
    set /A total=!total!+!countnew!
  )
)

if "!total!"=="0" (
  echo Nothing to do!
) else (
  if "%1"=="" (
    git commit -m "updated !total! files"
  ) else (
    git commit -m "%*"
  )
  git pull
  git push

  set conflicts=0
  set unsolved=0
  for /f %%C in ('git ls-files -u  ^| cut -f 2  ^| sort ^|uniq') do (
    set cff=%%C
    call :SUBCHOICE
    IF !ERRORLEVEL! EQU 2 (
      git checkout --theirs !cff!
      git add !cff!
    ) ELSE IF !ERRORLEVEL! EQU 3 (
      git checkout --ours !cff!
      git add !cff!
    ) ELSE IF !ERRORLEVEL! EQU 4 (
      set /A unsolved=!unsolved!+1
    ) ELSE IF !ERRORLEVEL! EQU 5 (
      exit /b
    )
    set /A conflicts=!conflicts!+1
  )

  if !unsolved! GTR 0 (
    echo There are still %red%!conflicts! files%nocolor% in conflict.
    exit /b
  )
 
  if !conflicts! GTR 0 (
    git commit -m "merged conflicted files"
    git push
  )
)

exit /b

:SUBCHOICE
echo|set /p="File %red%!cff!%nocolor% is in conflict "
CHOICE /C dtosx /M "(show [D]iff, use [T]heirs, use [O]urs, [S]kip file, e[X]it script)"
   IF !ERRORLEVEL! EQU 1 (
      git diff !cff!
      goto SUBCHOICE
    )
   exit /B !ERRORLEVEL!

The Windows .bat code is a script for committing and pushing git changes, with the ability to quickly resolve conflicts. It sets up some color codes for the text output and checks for modifications, deletions, and untracked (new) files. It then adds the files to be committed and either uses an argument given to the script as the commit message, or a generic commit message. It then pulls, pushes, and checks for conflicts. If conflicts are present, it provides the user with the option to view a diff, select a version of the file, skip the file, or exit the script. If conflicts are resolved, the script commits the merged files and pushes them.

gits in action. Here it found files not added to the repo yet and proposes to add them, to do the commit without adding them or to stop the script