Git and libgit2

A Streamlined Git Commit

Published 2024-12-12. Last modified 2024-12-30.
Time to read: 2 minutes.

This page is part of the git collection.

Ever have git push choke on a large file, for example, a file over 2 GB? Wouldn't it be nice for the names of overly large files to automagically be added to .gitignore instead of having to look up how git undo works again?

Free Yourself From the Fear of Accidental Commitment

I have maintained a series of streamlined commit scripts for CVS, SVN and Git for 19 years. I removed the CVS and SVN support several years ago, so only Git is supported now.

Originally written in bash, the current version is written in Ruby, and published as a Ruby gem. It uses the rugged gem. The Ruby language binding to libgit2 that rugged provides allows for more advanced features than Git porcelain commands can offer.

High-Level Functionality

The commit scripts perform the following:

  1. git add
  2. git commit
  3. git push

Ruby Version

This is the latest version, and is the only version with the ability to handle large files. Using this version means you no longer have to worry about getting tangled up in undoing commits that failed because they included a large file.

The Ruby version has two important features that are possible because it examines the sizes of the files that are about to be added to the commit:

  1. It ensures that files over 100 MB are added to .gitignore instead of causing git push to fail. A message is displayed, so the user is informed when large files are ignored. A future version will send those files to Git LFS instead, of the repository is configured for Git Large File Storage (LFS).
  2. When the amount of data being added gets close to the maximum pack size of 2 GB, the commit and subsequent push are performed in stages. This trades off a perfectly groomed Git history for error-free Git operation and better manageability. This feature is especially useful for large files, such as those that require a Git LFS.

This version requires that Ruby is set up properly on your computer. If you do not want to set up Ruby, you can run the older bash version of commit instead, but that version does not include the large file handling features.

At present, Git LFS has not yet been implemented, so the largest file that can be handled before it must be included in .gitignore is 100 MB. I am working on it - 12 articles are in progress on this subject right now.

The mice are pedaling as fast as they can.

Installation

  1. Follow the directions in Setting Up a Ruby Development Environment.
  2. Install the rugged gem.
  3. Install the commit gem:
    Shell
    $ gem install commit

Help Message

Shell
$ commit -h
Runs git commit without prompting for a message.
Files larger than 2 GB are added to .gitignore instead of being committed.
Usage: commit [options] [file...]
  Where options are:
      -a "tag message"
      -m "commit message"
      -v 0 # Minimum verbosity
      -v 1 # Default verbosity
      -v 2 # Maximum verbosity
Examples:
  commit  # The default commit message is just a single dash (-)
  commit -v 0
  commit -m "This is a commit message"
  commit -v 0 -m "This is a commit message"
  commit -a 0.1.2 

Source Code

The source code for the Ruby version of commit is provided on GitHub. The Walk Through Git’s Dirty Files section of the Working With Git Repos Using Ruby's Rugged Gem article discusses how the central portion of the code works.

Sample Usage

Shell
$ commit
Adding my_new_file.txt
Not adding 'video.mp4' because the git file size limit is 2 GB,
however the file is 2.12 GB.
The file will be added to .gitignore.
Pushing to origin master

$ commit No changes were detected to this git repository.

Older Bash Version

The bash version installs more easily than the Ruby version, but it cannot prevent big files from causing git push to choke and fail.

Installation

  1. Download the bash script to a directory on your PATH, for example, /usr/local/bin/, the standard Ubuntu directory for user scripts ~/.local/bin/
  2. Make the script executable:
    Shell
    $ chmod a+x /usr/local/bin/commit

Help Message

Shell
$ commit -h
Runs git commit without prompting for a message.
Usage: commit [options] [file...]
  Where options are:
      -a "tag message"
      -d # enables debug mode
      -m "commit message"
Examples:
  commit # The default commit message is just a single dash (-)
  commit -m "This is a commit message"
  commit -a 0.1.2 

Source Code

#!/bin/bash

# Originally written 2005-09-05 by Mike Slinn for CVS, then SVN, then git.

function help {
   echo "Runs git commit without prompting for a message."
   echo "Usage: commit [options] [file...]"
   echo "   Where options are:"
   echo "      -a \"tag message\""
   echo "      -d # enables debug mode"
   echo "      -m \"commit message\""
   echo "Examples:"
   echo "  commit  # The default commit message is just a single dash (-)"
   echo "  commit -m \"This is a commit message\""
   echo "  commit -a 0.1.2"
   exit 1
}

function isGitProject {
  cd "$( git rev-parse --git-dir )/.." || exit 2
  [ -d .git ]
}


BRANCH="$(git rev-parse --abbrev-ref HEAD)"
MSG=""
while getopts "a:dhm:?" opt; do
   case $opt in
       a ) TAG="$OPTARG"
           git tag -a "$TAG" -m "v$TAG"
           git push origin --tags
           exit
           ;;
       d ) set -xv ;;
       m ) MSG="$OPTARG" ;;
       h ) help ;;
       \?) help ;;
   esac
done
shift "$((OPTIND-1))"


for o in "$@"; do
   if [ "$o" == "-m" ]; then unset MSG; fi
done

if isGitProject; then
  if [ "$@" ]; then
    git add -A "$@"
  else
    git add -A .
  fi
  shift
  if [ "$MSG" == "" ]; then MSG="-"; fi
  git commit -m "$MSG" "$@" 3>&1 1>&2 2>&3 | sed -e '/^X11/d'  | sed -e '/^Warning:/d'
  git push origin "$BRANCH" --tags 3>&1 1>&2 2>&3 | sed -e '/^X11/d'  | sed -e '/^Warning:/d'
else
  echo "Error: '$( pwd )' is not a git project"
fi

if [ -f 0 ]; then rm -f 0; fi
* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.