User Tools

Site Tools



Git (software)

Every Git working directory is a full-fledged repository with complete history and full version tracking capabilities, not dependent on network access or a central server.

BFG Repo-Cleaner

Fast & simple Git history rewrites with The BFG

So I wanted to remove all *.txt files and the directory named find from all commits of a repository that I'm stripping down to just one bash script prior to publishing it on GitHub.

  1. I copied Roberto Tyley's jar to /home/jo/bfg.jar
  2. in a Terminal in the root of the repository:
    1. java -jar ~/bfg.jar –delete-files *.txt
    2. java -jar ~/bfg.jar –delete-folders find
  3. git reflog expire –expire=now –all && git gc –prune=now –aggressive - as recommended, to shrink the .git folder down

The argument to --delete-folders is a glob expression


Get the latest version of this now indispensible SCM.


  • *.sh files can get associated with C:\Program Files\Git\bin\sh.exe.
  • In my Windows 10, git config –global -e created a default C:\Users\Joseph\.gitconfig
  • (There's a Windows only site, which offers the same latest version.) It installs Git for Windows, and comes with Git GUI (cutely running in explorer.exe as process wish.exe), which isn't easy to make sense of at first.

How Git Works

Mixing metaphors: John Wiegley's 2009 "Git from the bottom up" is advanced, but explains how Git is a kind of leaf-node (= blobs) filesystem organised into trees (= commits). In this way of thinking, git branches are ancestoral histories of trees (a series of developing commits), each child tree being somehow modified from it's parent. The index is there to allow building the next commit in stages.

Oliver Steele's Git Workflow is helpful.

three local areas

I'm finding this a helpful idea: When I create a Git repository in a directory of some text-filey stuff, there are three areas:

  1. my working tree - these are the files that I see in the directory, and any subdirectories, it's the tree of stuff that I can explore and work on as I would on any part of my filesystem
  2. the Git index - this is a kind of bridge to the next area, also known as a cache, or staging area, but in fact it's just a load of pointers to objects in the working tree that you might want to move into the object store. We examine it with git status
  3. the Git Object store - this is Git's store of the contents of your files

GitGuys have a series of images that explain beautifully how this works: What’s The Deal With The Git Index?.

Git Bash

  • grep MidnightBlue * is how to search files in a directory for lines containing MidnightBlue.
  • help lists the available commands. rev ain't there; sed, grep, egrep, awk and gawk aren't listed, but they're available.
  • Setting shell aliases - perfectly explained by Daniel Lee. %UserProfile%\.bashrc is where you store aliases.
  • SSH Keys can be generated with: ssh-keygen -t rsa -b 4096 -C “$(whoami)@-$(date -I)”- which, on my system, generated a comment at the end of the public key like this: “rahula\jo@-2015-01-29”.
  • “This is perl 5, version 22, subversion 1 (v5.22.1) built for x86_64-msys-thread-multi”

Search my local repository collection for LICENSE.txt's, sorted by last modification time:

find -maxdepth 2 -name LICENSE.txt -printf %Ty%Tm%Td-%TH%TM%TS%p\\n | sort

get CRLF'd files from git status -u

(I'm using my alias gs for git status here:)

  1. gs -u | grep “$(echo -ne \\t)” lists just the files, identified by the leading tab
  2. gs -u | grep “$(echo -ne \\t)” | sed 's#\t##' strips out the now un-needed starting tab
  3. gs -u | grep “$(echo -ne \\t)” | sed 's#\t##' | grep -v “deleted:” strips out those that ain't there anymore
  4. gs -u | grep “$(echo -ne \\t)” | sed 's#\t\(modified: \)*##' | grep -v “deleted:” also strips out the un-needed description, if it's there
  5. gs -u | grep “$(echo -ne \\t)” | sed 's#\t\(modified: \)*##' | grep -v “deleted:” | xargs -i{} grep -Ul $'\015' {} homes in on those files that have MSWin line endings


Git for Windows Bash terminal Vim was firing up broken. To diagnose this, I needed to spot the errors while calling Vim from Git's Bash, but they were masked by Vim firing up, so I:

 vim 2> err 

- which caught those ephemeral errors in the text file err.

I was then able to determine, as Mikel nicely points out that Git Bash runs C:\Program Files\Git\share\vim\vim74, but also makes a call to $HOME\_vimrc, which is inconvenient for me, as my C:\Users\jo\_vimrc is geared to running Vim on Windows, not in Bash. So, I added this at the beginning of my _vimrc:

if $VIM == 'C:\Program Files\Git\share\vim'

- which kills off any further calls to my gVim install.

opening a bunch of files that contain a string

Ryan's answer was the only way I could get this to work:

 vim -o $(grep -rl string directory) 

Adapted to open all of Ingo Karkat's plugin files in my vimfiles:

 vi -o $(grep -rl Karkat .) 

- very nice - 21 files opened in one Vim window, all set for an argdo w ++ff=dos.


GitHub for Windows

GitHub.exe is the slick and easy way to get started. It works (invisibly to a novice) with an SSH Keys.


  • %LOCALAPPDATA%\GitHub gets me to C:\Users\jo\AppData\Local\GitHub
  • %USERPROFILE%\Local Settings\Application Data\GitHub gets me to C:\Users\jo\Local Settings\Application Data\GitHub

- and they're both in fact the same location…

When GitHub.exe doesn't want to add uncommitted files (which was just again the case in my vimfiles) I open Git Bash, and git add *, followed by git status to check, then do a commit like this:

git commit -m "these 4 colorizer files didn't go up from GitHub.exe"

After a system reboot (well, it's Windows), GitHub for Windows is able to see the new commits, and sync them up to Laborious, but it works. More recently I've found that just rebooting my netbook gets Git for Windows working again.


  • Fork A Repo is very easy
  • I had to read around quite a bit to make sense of why GitHub is so important, and it was while installing plugins for gVim that I really began to appreciate its worth, then actually populating my own repository with useful projects took a few hours of fiddling, not least because GitHub.exe is a little glitchy on my underpowered Win7 netbook. This got me going.

Sync a local repository

I prefer to rename my GitHub upstreams to “gh”, then, if I need to bring my local repository up-to-date with what's been pushed to GitHub:

git fetch gh
git merge gh/master

Syncing a fork:

git fetch upstream
git merge upstream/master 

- you need to replace upstream with whatever you've called your GitHub remote locally (probably “origin” if you're just getting started). This doesn't change your .git/config.

create and push to a new repository

Adam Dachis' "How the heck" at Lifehacker

Once everything's set, and you've committed your files in a folder to a local repository, go to your GitHub account and create an equivalent but completely empty remote repository there, then you can identify that remote in your local repository, eg:

git remote add origin

- I'm using the standard GitHub for Windows alias origin here.

Finally –set-upstream and push to it to GitHub with git push -u origin master.


If you want to remove git's presence from a folder, then remove all .git files recursively (which I adjusted):

find . | grep /.git | xargs rm -rf

Undoing Things:

safely adding a plugin to vimfiles

My workflow for adding a plugin bundle from GitHub is this (using vim-sneak as an example):

  1. from Git Bash in my vimfiles\bundle, clone the project from GitHub: git clone
  2. move into vim-sneak sub-directory, and remove the vim-sneak project's .git files with find . | grep /.git | xargs rm -rf

My vimfiles repository, with the vim-sneak plugin added, can now be safely pushed to GitHub, but, on my Windows 7 netbook, I prefer to have this repository set to always convert to LF endings. So from my netbook, back in my vimfiles directory, I move forward just two steps - git add ., then a git commit - at which point I see a lot of warnings like this: CRLF will be replaced by LF in bundle/vim-sneak/, which is my cue to:

  1. Delete the (just installed) directory vimfiles\bundle\vim-sneak, because it contains files with CLRF line-endings
  2. back in my vimfiles root, bring back vimfiles\bundle\vim-sneak with line-endings corrected to LF by issuing git checkout-index -f -a

- voila, Git has brought me the plugin with ease, and converted it to LF line-endings. git status now informs me of the presence of unstaged vim-sneak, so I tidy that up with git add ., then git commit -m “vim-sneak line-endings corrected to LF”.

the hidden git files

gci -r .git | select fullname
gci -r .gitignore | select fullname

Converting .git/config to my GitHub preferences in gVim:



You'll need to edit your $HOME/.gitconfig - which on my netbook is C:\Users\jo\.gitconfig.

On MSWin: [include] # path = /e/Dropbox/Now/Technos/IT/Cross-platform/gitconfig ; fails # path = gitconfig ; works # path = E:\Dropbox\Now\Technos\IT\Cross-platform/gitconfig ; fails # path = E:/Dropbox/Now/Technos/IT/Cross-platform/gitconfig ; works

path = E:\\Dropbox\\Now\\Technos\\IT\\Cross-platform\\gitconfig ; works

merge in a smaller repository

- somewhere into a bigger one, and make it look like it's always been there.

  • D:\Dropbox\IT - my big repository, no remotes - it's just for my notes, lots of subdirectories
  • D:\Dropbox\egreg - a flat directory, containing just a few files and an active Git repository
  • D:\Dropbox\IT\Cross-platform\LaTeX\ the parent folder that egreg used to live under (but was temporarily moved out of while I made IT into a super-repository)

First, I prepare the smaller repository for the change of location, then, in the root of the big repository, I just pull in the smaller: git pull /d/dropbox/egreg.

prepare a repository to be integrated into another

Move the files to a subfolder, in this case, on MSWin (using Git Bash), to Cross-platform\LaTeX\egreg, and have them seem to've always been there:

  1. clear the working tree:
    • as all of my files are tracked by Git, I just:
      rm -r *
    • but if there were one or more non-tracked files, I'd have to deal with them first:
      1. remove the Git-tracked files:
        git ls-files | xargs rm -rf
      2. move what is left into the new subfolder location:
        mv * /d/Dropbox/IT/Cross-platform/LaTeX/egreg 
  2. reconstitute only the Git-indexed files:
    git checkout-index -f -a
  3. perform this weird maneuver: move the whole tree into a subdirectory:
    git filter-branch --index-filter \
      'git ls-files -s | sed "s#\t\"*#&Cross-platform\/LaTeX\/egreg/#" |
      GIT_INDEX_FILE=$ git update-index --index-info &&
      mv "$" "$GIT_INDEX_FILE"' HEAD
  4. check the results with:
    ls -a Cross-platform/LaTeX/egreg

- the repository is now ready to be git pull'd from another repository, it's history preserved.

MSWin line endings

The debate: What's the best CRLF handling strategy with git?

I began by following the counsel to set core.autocrlf, but it's not necessary if you have a .gitattributes file and you're using a text editor that handles the line endings transparently. When I directly Download ZIP of someone's GitHub repository to my Windows 7 netbook, I often get unix line endings, which my MSWin Vim installation handles transparently. I've no need to convert those files to dos line endings, and, because Git Bash's Vim doesn't handle dos line endings transparently, I've an incentive to leave unix line endings as they are. My only real concern is that my GitHub repositories for my system-independent scripts have the more universally-accepted unix line endings, which is handled by .gitattributes.

in the mixed bag of my vimfiles

My vimfiles have been partly built up on my Windows 7 netbook, partly on my Linux Mint box, and mostly through grabbing plugins that can be a vimball, or a GitHub repository. This creates a thorough mix of CRLF and LF line-endings. As my gVim can handle either transparently, and I want to be able to directly copy my vimfiles anywhere, I prefer that Git converts line-endings always towards LF, which is then simpler for Unix-based systems. Force LF eol in git repo and working copy has the answer - * text=auto in the repository's .gitattributes, along with these two commands issued once (in your repository):

git config core.eol lf
git config core.autocrlf input 
core.eol will make sure text files bear LF line endings on checkouts. core.autocrlf will ensure potential CRLF in text files (resulting from a copy/paste operation for instance) will be converted to LF in your repository.

Those two commands add these two lines to your repository's (hidden) .git\config, under the [core]] heading:

eol = lf
autocrlf = input


Thoroughly explained by GitHub's Timothy Clem

Dealing with line endings recommends

git config --global core.autocrlf true

- which appended two lines to my existing C:\Users\jo\.gitconfig:

	autocrlf = true

And Jim Weirich recommended also:

 git config --global core.safecrlf true 


safecrlf = true</code>

fatal: LF would be replaced by CRLF - easily cured by correcting the file's EOL setting.


This is what I have in my repositories of system-independent scripts:

# Auto detect text files and perform LF normalization:
* text=auto
# need to also run these commands in the repository:
# git config core.eol lf
# git config core.autocrlf input 

These won't correct existing (previously committed) CRLF files to LF-endings.


My vimfiles have been partially grabbed from other people's GitHub repositories, partly created by me, and some come from Vimballs. So on my netbook, some have CRLF, and some LF.

Without me having set any end-of-line preferences, when I git add * in my vimfiles folder, I get repeated: warning: LF will be replaced by CRLF. This is telling me that what would happen during a checkout, so this warning appears for files with unix line-endings in MSWin - they would be changed to MSWin line-endings on a checkout.

I can turn these warnings off in a repository with:

 git config core.safecrlf false 

Or everywhere by adding a key into my .gitconfig, with:

 git config --global core.safecrlf false 


git cat-file “Provide content or type and size information for repository objects”

git gc:

git-show - Show various types of objects Eg. git log to get some or all of a SHA-1 object name for a commit, then:

git-show <enough of the SHA-1 to be unique>

gitrevisions - or how to identify Git objects, such as a commit.


How to find the n largest files in git repository? pranithk's answer!

I accidentally (and unknowingly) permanently deleted a file named access.txt, which I discovered when I ran git status -u (thank you Git). The file was easy to recover with git checkout access.txt, which brought it back. This works even if the file was long-ago deleted.



gitcredentials: simplest method is, in a project:

git config credential.helper store

which, in my case, created C:\Users\jo\.git-credentials, a plain-text store containing just:

and, in each project in which I issue this command, (cat shows that) these two lines have been added to the project's .git/config:

        helper = store

- but I've moved on to using SSH keys.

Working with Remotes and Atlassian's guides

Pushing to a remote > (git-push):

git push origin master

If you're always pushing to the same remote, you can set the upstream tracking:

git push -u origin master

subsequently you can simply git push.

git push -u gh master

- created these lines in /mnt/WD2000JD/IT_stack/CompFilesRec/.git/config:

[branch "master"]
	remote = gh
	merge = refs/heads/master 



In a repository that has alias origin defined to a remote:

git branch -u origin/master

> Branch master set up to track remote branch master from origin. - and these lines are added to your repository's .git/config:

[branch "master"]
        remote = origin
        merge = refs/heads/master

Why do I need to do `--set-upstream` all the time?


git init –bare creates one, and it's what you get on GitHub.

non-bare repositories

If you want to locally check how your repository is transferring (as I was), it's easy:

  1. my repository is in D:\Dropbox\Git
  2. I create a new folder D:\Git, and open Git Bash in it:
    1. git init - creates an empty repository
    2. git remote add origin D:/Git (I've used the standard alias “origin” here.) Solidus (/) as path separator, this is Bash.
    3. git pull origin master - brings in the original repository to this new folder


  • git checkout upstream/master - would change your repository into a detached HEAD state, looking now at the upstream that you forked your project from. Get back your own files with git checkout master.


So you do:

git fetch upstream
git merge upstream/master 

- and you are moved into (master|MERGING) with:

error: 'merge' is not possible because you have unmerged files.

You need to now run git status

So now you look at the files that Git has told you have merge conflicts, and you will see that Git has written the conflict clearly into the files. Choose what you wish to accept, and remove what you don't. git add the now fixed conflicted files, then do a commit to get out of the MERGING state.

cross_platform/encoding/text-code/git.txt · Last modified: 2016/10/05 10:45 (external edit)