Tag: git

  • Creating a Grunt plugin on Windows in MINGW

    I’ve been working with grunt a bit lately, and have found the need for a task that there doesn’t seem to be in the expansive list of existing plugins. So I thought I’d create my own. Fortunately, grunt has a great and simple page on doing this (http://gruntjs.com/creating-plugins).

    Unfortunately, I ran into some issues.

    I usually like to work in the Git Bash shell that comes with MINGW. Trouble is, this was causing some pathing issues. Specifically, with these two commands:

    1. Install the gruntplugin template with git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin(%USERPROFILE%\.grunt-init\gruntplugin on Windows).
    2. Run grunt-init gruntplugin in an empty directory.

    Apparently MINGW, or at least my version, has some issues resolving %USERPROFILE%. So I ended up with a cloned git repo in my local directory called %USERPROFILE%.grunt-initgruntplugin. After fixing that and moving it to my root user profile I kept geting an “EINVAL” issue on the next command. I figured this had to be a pathing issue too. So I dropped out of MINGW into a cmd shell by typing cmd. Except that didn’t quite do it. Maybe MINGW was intercepting input and filtering it in an unexpected way, but my problems became even worse. So my fix?:

    1. Add git to your OS Path variable (C:\Program Files\Git\bin)
    2. Run a regular command shell (cmd outside of MINGW)

    With those two small changes, everything worked flawlessly.

  • Determining the version of MINGW

    As a Windows developer who uses git and gcc, I found it easiest to install MINGW to help work in a console (Git Bash here is a fantastic shell extension!). Unfortunately, it’s been a while since I installed it and I forget the version I’m using. After a bit of googling, it seems someone figured out years ago how to figure this out in a shell script (stahta01)

    http://forums.codeblocks.org/index.php?topic=9054.0

    Just so I don’t have to go searching again for it, I’ve copied his/her script and included it below:

    @echo off
    REM version-of-mingw.bat
    REM credit to Peter Ward work in ReactOS Build Environment RosBE.cmd it gave me a starting point that I edited.
    ::
    :: Display the current version of GCC, ld, make and others.
    ::
    
    REM %CD% works in Windows XP, not sure when it was added to Windows
    set MINGWBASEDIR=C:\MinGW
    REM set MINGWBASEDIR=%CD%
    ECHO MINGWBASEDIR=%MINGWBASEDIR%
    SET PATH=%MINGWBASEDIR%\bin;%SystemRoot%\system32
    if exist %MINGWBASEDIR%\bin\gcc.exe (gcc -v 2>&1 | find "gcc version")
    REM if exist %MINGWBASEDIR%\bin\gcc.exe gcc -print-search-dirs
    if exist %MINGWBASEDIR%\bin\c++.exe (c++ -v 2>&1 | find "gcc version")
    if exist %MINGWBASEDIR%\bin\gcc-sjlj.exe (gcc-sjlj.exe -v 2>&1 | find "gcc version")
    if exist %MINGWBASEDIR%\bin\gcc-dw2.exe (gcc-dw2.exe -v 2>&1 | find "gcc version")
    if exist %MINGWBASEDIR%\bin\gdb.exe (gdb.exe -v | find "GNU gdb")
    if exist %MINGWBASEDIR%\bin\nasm.exe (nasm -v)
    if exist %MINGWBASEDIR%\bin\ld.exe (ld -v)
    if exist %MINGWBASEDIR%\bin\windres.exe (windres --version | find "GNU windres")
    if exist %MINGWBASEDIR%\bin\dlltool.exe (dlltool --version | find "GNU dlltool")
    if exist %MINGWBASEDIR%\bin\pexports.exe (pexports | find "PExports" )
    if exist %MINGWBASEDIR%\bin\mingw32-make.exe (mingw32-make -v | find "GNU Make")
    if exist %MINGWBASEDIR%\bin\make.exe (ECHO It is not recommended to have make.exe in mingw/bin)
    REM ECHO "The minGW runtime version is the same as __MINGW32_VERSION"
    if exist "%MINGWBASEDIR%\include\_mingw.h" (type "%MINGWBASEDIR%\include\_mingw.h" | find "__MINGW32_VERSION" | find "#define")
    if exist "%MINGWBASEDIR%\include\w32api.h" (type "%MINGWBASEDIR%\include\w32api.h" | find "__W32API_VERSION")
    
    :_end
    PAUSE
    

    On my machine, it outputs exactly what I needed:

    MINGWBASEDIR=C:\MinGW
    gcc version 4.8.1 (GCC) 
    gcc version 4.8.1 (GCC) 
    GNU gdb (GDB) 7.6.1
    GNU ld (GNU Binutils) 2.24
    GNU windres (GNU Binutils) 2.24
    GNU dlltool (GNU Binutils) 2.24
    GNU Make 3.82.90
    #define __MINGW32_VERSION           3.20
    #define __W32API_VERSION 3.17
    Press any key to continue . . . 
    
  • Combining Git Commits: Git Squash

    I often work by committing small, incrementally stable portions of my work to my working branch, then pushing the entire thing when it’s done. While great for working, this makes for a very cluttered commit history. Not only that, but it also makes it more difficult for peer reviewers to know what changes you’re trying to commit and contribute. To address this, I did the lazy (yet ironically more work) step of making a copy of my files, making a clean working branch, and applying my accumulation of changes in one copy-paste operation. In other words, I was manually squashing my many commits into one.

    Turns out git has this capacity built in. I knew of it, but I never bothered to look into it. Turns out, it was simple, and could’ve saved me a lot of time. This blog post outlines the process:

    git rebase -i HEAD~4

    With that command to begin interactively picking and squashing the last 4 commits. This is done by changing the commit log from picking the last four commits separately to squashing three onto the most recent. So in the interactive editor, this:

    pick 01d1124 Adding license
    pick 6340aaa Moving license into its own file
    pick ebfd367 Jekyll has become self-aware.
    pick 30e0ccb Changed the tagline in the binary, too.

    Becomes this:

    pick 01d1124 Adding license
    squash 6340aaa Moving license into its own file
    squash ebfd367 Jekyll has become self-aware.
    squash 30e0ccb Changed the tagline in the binary, too.

    Just save that, adjust the rebased commit message, and all is well.

  • Git ate my code: Remoting and the “Gotchas”

    Git is  a powerful tool. You can commit saved work never to be lost again, branch and merge with ease, and manage source code changes without a care in the world. And all this from your local machine without so much as a 14.4k modem. But what if you want to share your work or build off of some else’s? This is where remoting comes in.

    Remoting involves the management of remote repositories and syncing of code to be in line with your own. Remoting is not about directly working with code in a remote repository however. Rather, it is usually involves the movement of code to your local machine where it is then managed and pushed back to a publicly-accessible repository.

    The first step is retrieving code from the public repository. If you’re just creating your project this is done by using the clone command:

    git clone remoteUri localRepo

    This command will pull all commits from the repository remoteUri and recreate them in a repository named localRepo on your local machine. What it also does is store that remoteUri under an alias (origin by default) so that you can put code back in the remote repository later. You can register other remote repositories for your repo by using the add flag for the remote command:

    git remote add alias remoteUri

    Here, alias is the short name for the uri (origin, remote-master, it can be anything!) and remoteUri is once again the location of the remote repo. These aliases will be used when moving code to and from the repository. You can verify that the repository was entered by specifying the -v flag on the remote command:

    git remote -v

    Ah yes, moving code around. You can bring code to your machine by using the pull or fetch commands. Both are similar, though pull will perform an automatic merge while fetch will not. The following command sets are equivalent:

    git pull origin branchName

    git fetch origin
    git merge origin/branchName

    Either of the above will bring code into your current working copy and merge the contents with your work. After putting your two cents in and fixing bugs or adding (undocumented) features it’s time to put the code back into the public repository using the push command:

    git push origin

    There we go, simple simple. Why bring the code to the local machine though, why not just work off the remote repo directly? A few days ago I tried this:

    git checkout origin/master

    I though “I’ll just work off a remote branch, fix a bug and commit my changes without having to push/pull”. Here’s where I learned the true nature of a branch. A branch is simply a pointer to a commit (with a commit being an accumulation of the changes, or a diff, since the last commit). A commit also contains a record to the commit before it, building a chain of changes that allow for the determination of a file’s contents. The thing about pointers is… they’re only local! By checking out a remote branch I began working in what git warned me was a detached HEAD state, which meant that my changes were effectively being written off somewhere in space with no knowledge of what commit on your local machine to use as the basis for the next commit (somewhere on a remote machine was anyone’s guess).

    Now git is great and user friendly but if you ignore the 10-line warning message like I did you may put in lots of time, commit your work, change branches and then wonder where your work went. Even though the changes won’t be reflected in any of your named branches, git never eats commited code. Every commit results in a hash code key to act as the identifier for that commit. All you have to do is use the hash code as the branch name (“git checkout 123ea4123a3aef8bd87ae”).

    But who wants to type in THAT each time. Since branches are just pointers to these commits, you can create a branch on that commit and then can reference it much easier:

    git checkout 123ea4123a3aef8bd87ae
    git branch rescuedBranch

    From here we can either continue to work on it like a normal branch or merge it back to another branch on your local machine. How to get this hash code though? Simple, we go through git’s logs. If you are still on the detached branch, simply call the reflog command to retrieve a list of recent commits and their hashes:

    git reflog

    If you committed and then switched to another branch it will take a little bit more work. The log command outputs a history of commits made and if you specify the –all option you can see everything. For some extra flair, the –graph option outputs a graph showing the various branches and merges that occurred as well:

    git log --all --graph

    Like any good Linux-inspired tool, git work great with other utilities such as grep if you know a bit more information about the commit like the Date, commit messages or Author. For an explanation of that though, I’ll defer to a git professional.

  • Advanced Git: Branching

    In continuing exploration into Git, Dave has explained a bit more about the architecture of it. It seems quite different from the SVN I’m used to, but luckily he pointed out a great e-resource. Beyond simple commiting, Git (like any good source control tool) has the ability to branch. All changes are logged incrementally, with a branch representing a pointer to the change log. There is always a branch in Git, even master is a branch. Each branch may have many commits to it, with the latest commit for the current working branch being designated as HEAD. Multiple commits to a branch form a chain of changes dating back not to the beginning of the branch but the beginning of the repo. This is because the beginning of the branch can be thought of as the accumulation of all changes on the trunk up until that point.

    Each commit points to one before (backward looking list, results in “tree” when viewed graphically. Commit typically have one parent but in the case of a merge they will have n parents (with n being the number of branches merged in that change set). As a result, a graph of commits in a repo form a web of pointers across many change sets. Here’s a relatively mild visualization (courtesy of progit):

    A web of commit pointers charting changesets
    Commit Pointer Web

    It’s easy to get the hang of so long as one remembers the commands. Here are a few commonly used ones:

    // Create branch, stay on working copy (be sure to be on copy you wish to branch from)
    git branch branchName

    // Merge from branchName into current branch
    git merge branchName

    // View all branches
    git branch

    // Switch to other branch (failure to commit changes from last branch will cause error.
    // Failure to stage changes from last branch before switching may accidentally affect moved-to branch)
    git checkout branchName

    // Create and checkout new branch
    git checkout -b branchName

    // Shows current branch as well as status of modified/staged/committed
    git status

    This is great, almost there (the last piece of the puzzle being remoting). That’s coming up soon!

  • Gettin’ into Git and PHP Process Control

    After my last foray with Mercurial, I’m now beginning to work with the distributed source control tool Git. And I like it. Like Hg, it seems it’s used for many projects including the Canvas 3D JS Library C3DL. Like SVN it provides source control, but unlike SVN it is great for its decentralized attitude and being able to run entirely locally if necessary. The learning curve is great too (almost linear) thanks to documentation like kernel.org’s 20 Everyday Git Commands.

    Of course Git isn’t enough to get any development done. I’ve been delving into PHP and how to issue commands to OS shells and receive output. Seems there are a lot of different options depending on what you want to do. The basic operations can be used via the system or exec functions, each of which return data back to the calling PHP script for further work. These two differ in two ways:

    • system() allows an array to be filled with all lines of the script output
    • exec() returns the entire output as a string rather than just the first line of output

    In situations where the above isn’t enough or when dealing with binary output, the passthru function does the job nicely. This function seems to be the best of the lot: piping the script output directly back to the request stream rather than into PHP (which then goes to the stream) saves a ton of overhead if no additional formatting is required before displaying script output to the user.

    As great as these functions are, the entire branch of PHP dealing with process control and program execution require PHP safe mode to be turned off. So it’s easy to use, just some configuration required.