GIT is the new Drupal version control system. It's not just for Drupal.Org, though. You can use it on your own modules, even if you don't plan to contribute them.
GIT is complex. It can zombify you. Strange terms, commands, switches, workflows. Your brain can overload, and stop altogether. Zombie!
But learning a little GIT can be a good thing. Let's say you're writing the next Great Module. It will analyze zombie flocking behavior, looking for signs of sentient zombie leaders. Flocking data is flocking hard to analyze. You'll need to try different mathematical methods, parameterized in different ways.
You want to be able to experiment with your code, keep the stuff that works, throw away what doesn't. GIT can help. You can be a Fearless Experimenter, adding, changing, and deleting code all over the place. GIT has your back.
You don't have to learn all of GIT to get most of its benefits. A little dab'll do ya.
Let's see how GIT can help make it safe for you to experiment. With code, that is. We won't use any command line stuff. All GUI, all the way.
A warning: I'm not a GIT expert. The instructions below work for me. But there may be better ways.
Snapshots, commits, and other GITty words
The first word is a "revision." It's a copy of all of your files at a point in time. Like making a zip file of everything, and storing it away. If zombies smash your code, you can always grab the last revision, or the revision before that.
I prefer the word "snapshot." The word evokes an image of something captured in time.
At any moment, the code you're working on is a combination of (1) the code in a snapshot, and (2) changes you have made since the snapshot was made. When you make a new snapshot, you fold those two together.

Figure 1. Snapshots
The changes in Figure 1 are called "commits" in GITese. When you commit, you create a new snapshot.
A note for people used to older systems, like CVS: in GIT, "commit" does not mean "send changes to a central repository." GIT separates committing (creating a new snapshot) from pushing (sending changes to another repository).
The collection of shapshots for a project is a "repository," or "repo."

Figure 2. Repository
The most recent snapshot is often called "head," or "HEAD." That stands for "hierarchically expressed application data." ... No, I made that up. It doesn't stand for anything.
Example: I'm so over pirates vs. ninjas
"Pirates or ninjas?" was an important question last year. Not so much anymore. The new question is: "Plants or zombies?"
Let's write a module that replaces the old question with the new. It won't change the content in the database, but will affect the way it's rendered.
Setting up the files
To start, we'll do a fresh Drupal 7 install, and throw in admin_menu and devel modules. Then add a directory for the module, and .info and .module files. Here are the files we'll start with:

Figure 3. Files
This screen shot is from Netbeans, my IDE of choice. It has a GIT plugin.
Here's the .info file:
- name = Pirates to plants
- description = From pirates vs ninjas, to plants vs zombies.
- package = Drupal Zombie
- core = 7.x
- files[] = pirates_to_plants.module
Here's the .module:
- <?php
- function pirates_to_plants_node_view_alter(&$build) {
- drupal_set_message('Plants, not pirates');
- }
hook_node_view_alter() lets a module change a node before it is rendered.
Enable the module, create an article, and see:

Figure 4. Message
The module is working! Yay!
But it's GITless. Let's add version control.
Creating a repository
Select a file, like pirates_to_plants.info, and click the menu item Team | Git | Initialize:

Figure 5. Create repository
Netbeans likes to GIT entire projects, not just directories inside them. It's possible to GIT just our module, but for now let Netbeans' GIT plugin do what it wants.
Here's what we get:


Figure 6. Initial state
NetBeans' GIT plugin color codes stuff:
- Green means "new."
- Blue means "changed."
- Red means something has been removed.
When a file name is green, it's a new file, not stored in the last revision. A blue icon on a directory means files in the directory have uncommitted changes. In the code, the green bar shows the code is new, and has not yet been committed.
Commit
Let's commit everything so far. This will be our first snapshot.

Figure 7. First commit
A dialog appears. Enter a comment about the commit, and click the Commit button:

Figure 8. Committing
Netbeans' GIT plugin does its thing. The green goes away. The files look like this:

Figure 3 (again). Files
The code window:

Figure 9. No uncommitted code
Everything's green-free.
Team | Repository browser opens a new window:

Figure 10. Repository browser
master is the name of a "branch." Branching will be the subject of a future article. Maybe. If all the planets align.
That strange hexadecimal stuff (4032c66...) is the "object name" of the revision. It's a hash, that is, the value is computed from the contents of the files at this point.
Exploring a NAD
Recall that we're using hook_node_view_alter(). It fires before a node is rendered. Here's the function's signature:
hook_node_view(&$build)
$build: A renderable array representing the node's content.
Notice the & in front of the parameter. It means "pass by reference." That means we can change $build, and the changes will be passed back to the caller.
We need to grab content from $build, so we can change the text, changing "pirate" to "plant," and "ninja" to "zombie." We'll only mess with two fields for now: the title and the body.
$build is, of course, a Nested Array of Doom (NAD). That's the Drupal way. How do we figure out where in $build the content is? The dpm() function can help:
- <?php
- function pirates_to_plants_node_view_alter(&$build) {
- drupal_set_message('Plants, not pirates');
- dpm($build);
- }
dpm() will output an array in a friendly form, so we can find the pieces we need to change.
The code window looks like this:

Figure 11. Code window
The green shows that this is new code.
The project window shows:

Figure 12. File changed
The .module file is blue. Blue means that the file has changed.
Drupal outputs $build:

Figure 13. dpm() output
I had to hunt and experiment for quite a while to find the right elements. $build['body']['#object']->title has the title. The body is in $build['body'][0]['#markup'].
Ooo! Exciting! Let's commit now (even though I don't really need the dpm() call any more). Select the project, then Team | Commit:


Figure 14. Commit
A dialog appears. Enter a commit message and click the Commit button:

Figure 15. Commit message
Here's the repository browser:

Figure 16. New object name
Notice that the object name is different. It used to start with "4032c66." Now it starts with "8eda4a." Recall that the object name is a hash, computed from the contents of the files. Since one of the files has changed, we get a new value.
History and diff
The NetBeans GIT plugin can show the commit history:

Figure 17. Commit history
There are the two snapshots. The commit messages show up, too; they're cut off in this screen shot.
The "Diff" link lets us compare the code in the snapshots.

Figure 18. Graphical diff
As usual, green means "new stuff."
There are two tabs at the top of Figure 18: Graphical, and Textual. Figure 18 shows the graphical view. Here's the textual view:

Figure 19. Textual diff
This is a "patch file." The Unix patch command can use this to make changes to code. You sometimes see patch files in Drupal issue queues. For example, Views has the issue Custom Date format ajax support. One person asked for a new feature, and another person wrote a patch for it. To apply patches in NetBeans, use Tools | Apply diff patch.
Let's say I want to restore the old version of the .module file, from the original. Looking at the menus, you might think to use the revert command. That makes sense, but isn't right. Revert undoes changes that have not been committed yet. But we want to restore a file that has already been committed.
To restore a file from a snapshot, use "checkout." It doesn't sound right, but it is. Right-click on the .module file in the project window, and select GIT | Checkout Files.
The checkout command is used for a couple of different things, so there are some options we have to set. First, check the Update Index checkbox, so GIT knows you want to restore from a previous snapshot (aka revision):

Figure 20. Restore from a previous shapshot
Now click the Select button (cut off in Figure 20), and choose the snapshot you want to restore from:

Figure 21. Select snapshot
Click a couple of "OK, go do it" buttons. NetBean's GIT plugin will restore the file, the original version without dpm(). The file will be different from the latest shapshot (which has dpm()), so NetBeans will show the usual change indicators.


Figure 22. Showing changes
Remember that red means something has been deleted. In this case, a call to dpm().
The right NAD elements?
OK, time to write some module code. First, grab the title and body, and show them, to make sure that we're accessing the right NAD pieces:
- function pirates_to_plants_node_view($node, $view_mode) {
- drupal_set_message('Title:' . $node->title);
- drupal_set_message('Body: ' . $build['body'][0]['#markup']);
- }
Here's what we get:

Figure 23. Title and body
Hooray! I'm so excited that I'm going to commit the changes, so I won't lose this code:


Figure 14 (again). Commit
My commit message: Showing the right NAD components.
First try
Let's use the PHP function str_replace(). Here's what the documentation says:
mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
This function returns a string or an array with all occurrences of search in subject replaced with the given replace value.
Seems easy enough. We'll just do the title for now. Here's my new code:
- function pirates_to_plants_node_view_alter(&$build) {
- $title = $build['body']['#object']->title;
- $title = str_replace('pirate', 'plant', $title);
- $title = str_replace('ninja', 'zombie', $title);
- $build['body']['#object']->title = $title;
- }
Line 2 grabs the title from the NAD. Line 3 replaces "pirate" with "plant." Line 4 replaces "ninja" with "zombie." Line 5 puts the new title back into the NAD.
Here's what the result looks like:

Figure 24. Title partly right
Wait. It's supposed to be "Plants or zombies," not "Pirates or zombies." What's the deal?
(Think, think.)
Oh. "Pirates" and "pirates" are different. I need to use str_ireplace(), a case-insensitive version of str_replace().
Thing is, I'm not sure about this change. Let's commit before we edit, so we can easily undo everything.
Use Team | Commit, with a message of "Title partly right."
OK, that code is saved in a snapshot.
Time to experiment. Change to str_ireplace().

Figure 25. Testing a code change
Recall that blue means that the lines have changed.
Save the file and run:

Figure 26. The result
Argh! (No, I'm not turning into a pirate.) Lost the capital P in Plants! That didn't work.
We don't want to commit the last set of changes. We want to get rid of them, roll back the code to the last snapshot.
That's what the "revert" command does. Revert restores files to what they were in the last snapshot. Only the last snapshot. Not an earlier one. You cannot revert changes that have been committed. You need to use "checkout" to go further back.
Let's make sure we know the difference between revert and checkout. Revert returns files to the last snapshot:

Figure 27. Revert
Pat changed some code, but didn't commit. She tested, and the code didn't work. She decided to use a different approach. She reverted, and all the files went back to what they had been at the last snapshot.
Here's checkout:

Figure 28. Checkout
Pat committed. She did some coding, and committed again. Then she realized that she didn't mean to commit the changes to one of the files. Revert says, "Too late, they were already committed." Checkout says, "Nuh uh, not too late." Pat can checkout from any snapshot, but revert from the last one.
OK, is that straight? Back to reverting the last change to our program.
Select the project:

Figure 29. Select project
Then the Team | Revert Modifications command. It shows a dialog:

Figure 30. Revert dialog
Leave the first one selected. (We don't care about the others now.) Click Revert.

Figure 31. Reverted code
The code it back to str_replace(). It's i-less.
Now what?
(Think, write, test, write, test, document.)
OK, got it.
- <?php
- /*
- * Implements hook_node_view_alter.
- */
- function pirates_to_plants_node_view_alter(&$build) {
- //Get the title from the NAD.
- $title = $build['body']['#object']->title;
- //Replace words.
- $title = pirates_to_plants_str_replace('pirate', 'plant', $title);
- $title = pirates_to_plants_str_replace('ninja', 'zombie', $title);
- //Back into the NAD.
- $build['body']['#object']->title = $title;
- //Get the body from the NAD.
- $body = $build['body'][0]['#markup'];
- //Replace words.
- $body = pirates_to_plants_str_replace('pirate', 'plant', $body);
- $body = pirates_to_plants_str_replace('ninja', 'zombie', $body);
- //Back into the NAD.
- $build['body'][0]['#markup'] = $body;
- }
- /**
- * Replace $find in $subject with $replace_with. For each instance of
- * $find in $subject, maintain the case of the first character
- * of the piece of $subject that is to be replaced.
- *
- * @param string $find The string to be replaced.
- * @param string $replace_with The string to replace it with.
- * @param string $subject The string to be changed.
- * @return string The result.
- */
- function pirates_to_plants_str_replace($find, $replace_with, $subject) {
- $replace_with = strtolower($replace_with);
- while ( stripos($subject, $find) !== FALSE ) {
- $pos = stripos($subject, $find);
- //Break subject into components.
- $left = substr($subject, 0, $pos);
- $to_replace = substr($subject, $pos, strlen($find));
- $right = substr($subject, $pos + strlen($find));
- //Set case of replacement.
- $replacement = $replace_with;
- $first_char = substr($to_replace, 0, 1);
- if ( $first_char >= 'A' && $first_char <= 'Z') {
- $replacement = ucfirst($replacement);
- }
- else if ( $first_char >= 'a' && $first_char <= 'z') {
- $replacement = lcfirst($replacement);
- }
- $subject = $left . $replacement . $right;
- } //End while
- return $subject;
- }
Here's the result:

Figure 32. Finished!
There. Now nobody would know the page was originally about pirates and ninjas.
Commit the changes. We're done!
Move along, nothing more to see
This article has introduced some of the simplest uses of GIT. You'll also want to know about branching, merging, and pushing and pulling from a remote repository.
Not now, though. Time for Borderlands.

Add a comment