7

I'm not exactly a new git user but I have never used any of its advanced features such as tags, branches, merging and others. I haven't even used anything equivalent features from other VCS software. My projects have been so simple that I have only needed commits and sometimes diffs.

Now I'm planning to open-source a server project of mine which probably will get a lot bigger and it probably needs to be organized better. Git can probably help me with that but how?

The development methods are scrum and TDD if that matters.

3
  • Sounds you were working alone in the past?
    – Doc Brown
    Commented Jan 17, 2012 at 22:30
  • @DocBrown: Sadly,yes. But hopefully not in the future! :)
    – RCE
    Commented Jan 17, 2012 at 22:43
  • If you're on linux grab some decent tools to. Personally, I use gitk (with the command gitk --all to view all branches at once) to navigate the tree. Forget doing cherrypicks and complex resets and merging on the command line. For general staging/committing git-cola makes life a lot easier. Commented Jan 17, 2012 at 23:01

5 Answers 5

12

tags, branches, merging

IMO these are basic functions of any decent VCS, not particularly advanced features of Git.

I suggest reading some of the excellent online guides such as:

3
  • 2
    Yeah, I couldn't see branching and merging being considered "advanced" features. They are common in all version control and pretty common in use. Not that git doesn't have some advanced features...
    – rlperez
    Commented Jan 17, 2012 at 13:55
  • 1
    +1 for gitimmersion.com . Excellent tutorial from the same folks who created RubyKoans. Commented Jan 17, 2012 at 13:55
  • Because I haven't used anything beyond commits and diffs, I referred to everything else as advanced because they are a bit more advanced than those. Feel free to replace 'advanced' with something more appropriate. :)
    – RCE
    Commented Jan 17, 2012 at 21:36
7

Learn the core first:

If you take the time to understand how git works, then you will be able to easily understand all of the advanced things you can do with it. But let me emphasis: if you do not learn the core structure of git, all of the advanced things will be "black boxish" and confusing for a long time.

A brief explanation:

At the core of git is a database of objects. For the purpose of this discussion, I will describe the three most fundamental objects in git:

blob: Just data. The contents of a file, for example. The ID of the blob is generated using the SHA1() hash of the content. In this way, if any of the content of the file changes, a new blob object will be created.

tree: Just a list of blobs and trees. A tree is used to reference other blobs and trees, effectively creating a directory structure. The ID of the tree is generated using the SHA1() of the IDs that it refers to (roughly). In this way, if any of the blob IDs or tree IDs referenced change, then a whole new tree object is created.

commit: A commit contains a date, who, tree ID, commit message, comment, parent commit IDs, and maybe some other misc. info. The ID of the commit is generated by the SHA1() hash of its content. Therefore, if the exact same commit was made at a different time of day, it would actually be a different commit.


So a commit object points to a tree which points to other trees and blobs. That way, from a given commit, you can tell exactly what files were present, in what directories, and the exact content of the files.

People call git a version control system, and while it can do that, it is better to think of it as a snapshot management system. Git is really good at knowing, at each commit, what the contents of the repository were.

In fact, the only thing that creates a "history" is the fact that each git commit embeds what it's parent commit(s) were. In reality, git couldn't care less, but from a human perspective, this is really important to be able to know how the software evolved over time. It also forms the basis for a lot of features in git.


Understanding that a git commit ID is ultimately based on the contents of the entire repository at that point in time, then it also makes sense that the commit ID is not changeable (eg, immutable). Furthermore, the entire history is immutable as well, because a given commit ID is ALSO based on the Parent Commit ID, and so on and so forth.

This embodies the best of two worlds... One is the ability to know that your history has never been messed with, and cannot have been. The other is to know that you can rewrite history seamlessly with git, but you will get a new set of Commit IDs, etc...


Branches: In git, branches are very lightweight. In fact, if you look in .git/refs/heads/master, you will likely find a 41 byte file which refers simply to a commit ID. Strange? No... Just a human friendly reference to a given point in time in the repository. Rather like using a domain name instead of an IP address.

When you switch branches, git simply looks up the commit ID for the new branch, looks at the tree ID embedded in that commit, and goes through the actual working copy -- adding/removing/updating the files on disk until it matches everything specified by the tree and sub-trees and blobs, which were ultimately referenced by that new branch.

For example:

Branch 444 -> Commit 323 -> Tree 232 -> Subtree 343 -> Blob 454 -> File code.php

git commit --amend: If you make a mistake and commit your work, but wish to replace that commit, then you can use this command to replace that commit with a new one. But keep in mind, that the old one still exists. It has a different ID, and a different content, but it is still "hanging" around in your database (git reflog). These dangling objects are cleaned up from time to time with garbage collection.


I hope this helps give you a firm direction on the core of git. It will take some time and playing and research to really understand the guts of it, but if you do that, the rest will be really easy.

3
  • I hate this answer, because it's right, and because it is valuable to learn these things. I wish there were better abstractions than blob/tree/commit/ref so things were more intuitive. +1 Commented Jan 17, 2012 at 19:15
  • You don't need to learn blob and tree in order to use Git effectively. At most, you might need to learn that a branch is really just a (movable) pointer to a commit.
    – Kyralessa
    Commented Jan 18, 2012 at 1:27
  • This doesn't directly what I asked but this explanation is definitely worth an upvote. Git just became a lot more understandable!
    – RCE
    Commented Jan 20, 2012 at 0:43
3

In addition to the basic useful commands others have mentioned, I'll mention some others, perhaps a little less well-known git commands:

git commit --amend

Allows you to change the very last commit in your history. Use it if you for instance want to add additional fixes to the previously made commit.

git cherry-pick commit_id

You can grab just a specific changeset and apply it to your history; no need to merge the entire branch.

git reflog

Reflog is a mechanism to record when the tip of branches are updated. In other words this can be extremely useful to use when you want to for instance rollback to a specific state through the use of e.g. git reset --hard commit_id .

git stash

Not ready to commit yet but need to change gears and make a quick change for someone else? Save your working copy in a temporary place, and then use git stash pop to get it back.

git pull --rebase

This command will save any commits you might have in a temporary place, grab any new ones you might be missing from your tracking branch and stick yours back on the end. Keep the history clean and say goodbye to those merge commits.

1
  • 2
    I presume it should be understood as ref-log rather than re-flog? Commented Jan 17, 2012 at 15:44
2

Here's my short-list cheat sheet I use for OSS development

Day-to-day commands


# Update the working copy from the trunk
git pull --rebase

If you aren't the project owner you will use this command more than anything. Basically, pull the latest changes and change to the current version all in one step.

# Goes back one commit in case something was forgotten
git reset --soft HEAD^

Unless you write perfect code with 0 conflicts (don't worry, you don't) you'll need to go back and resolve issues. This drops back one revision so you can add whatever you forgot.

# Reverts the working copy back to the trunk revision
git reset HEAD~

Resets the repository to the HEAD revision. If there are multiple users working on the same codebase, it saves a lot of headaches to save away your changes and pull the latest commit before committing. The key is to keep the tree as clean as possible to cut down on the amount of conflicts/issues/headaches.

# Gives a summary of a commit without executing it
git commit -a --dry-run

Doing a dry run on a commit will let you know where conflicts exist without actually committing the code. Resolving conflicts before the actual commit is easier than after.

Making sure your commits go in clean is essential to maintaining a clean revision tree. especially when there are multiple devs working on a project in parallel.

# Amend the log from the last commit
git commit --amend

Nothing special but extremely useful. It lets you edit the last commit. If you're working on a team project, making good notes about commits is essential. This saves from having to go through all the effort of a soft reset to make the change.

# Saves the uncommited changes
git stash save

# Shows a listing of the saved stashes
git stash list

# Applies the stash @ ID 0
git stash apply stash@{0}

# Removes a stash @ ID 0
git stash drop stash@{0}

Sometimes you need the latest revision but your current branch isn't complete enough to save away as a commit. The quick-and-easy approach is to stash those changes away. It's also useful if you're just doing a few throwaway experiments that don't justify the creation of another branch.

Branching


# Lists the branches
git branch

# Creates a branch
git branch <branchname>

# Deletes a branch (branch must be merged with HEAD)
git branch -d <branchname>

# Deletes a branch (Irrespective of its merged status)
git branch -D <branchname>

# Checks out a branch
git checkout <branch>

# Creates a branch and then checks it out
git checkout -b <branch_name>

If there is more than one dev working on a code base then you should both be working on your own branches. The master should contain the current revision of the code with nothing extra. Changes to the master should be minimized because that's what the other devs are going to pull before they merge/rebase/push their new changes.

I repeat, any code that is in flux should remain on a separate branch. This is git not SVN we're talking about. It's not like it's hard to use branches.

Patching


If you're sane, you'll restrict push access to the repository to only the most skilled/trusted developers. If a dev steps in and wants to commit some changes ask them to submit a patch (or patches). Review them closely before committing.

# Creates a patch from the last commit
git format-patch -1

# Creates a patch from the last commit
git format-patch -o ../_patch/ --start-number 0 -1

# Applies and commits a patch
git am ../_patch/*

# Applies and commits all the patches in a specified directory
git am --directory=../_patch/*

All these are convenient variations of 'git format-patch' and 'git am'. The first is obvious, the second makes is so you can create multiple patches in one shot and output them to a different folder. If you change the -1 to a different number to specify the number of commits that will be changed into patches.

Remoting


Lets say that you've been collaborating with another developer who is submitting a ton of commits but you still don't want to grant push access. Well, branching gets to be a serious pain after a while. Isn't git supposed to be capable of using branches from multiple repositories. Yes, it is and here's how.

First create a remote repository (I used to use Gitorious but YMMV). To track the link to that repository you'll need to create a remote. Think of a remote as a web link to another repository.

# Create a remote
git remote add <remoteName> <remote_url>

# Cleans the remotes
git remote prune <remoteName>

First you want to update your listing of branches so you fetch the status of the remote branches.

# Updates the status of the remote branch
git fetch

Looking at remote branches is nice but you want to make changes to those branches so you should create a remote tracking branch.

# Creates a remote tracking branch
git branch --track <remote> <branch>

When you work with a remote tracking branch it's like working with the master/origin branch. It's linked to a remote server so you can push/pull changes except it can point to a completely different repository.

The workflow for a developer using a side-repository for mainstream development is to create the remote repository. Develop/commit/push his/her changes to that repository. Then the project owner/maintainer can also checkout the same remote tracking branches to pull/QC/test those changes before merging/rebasing them into the master branch.

This is how forking a project works. A subset of the development team breaks off of the main branch and creates their own independent line of development. They may selectively pull commits from the parent project (by keeping a remote tracking branch for the master branch of the parent repository) and the parent project may selectively pull commits from the child project (by keeping a remote tracking branch for the master branch of the child repository).

The concept of local commits and the ease of branching (and remote branching) make forking a tree of development as easy as typing in a few commands.

The hardest part about git is the sucky documentation.

Note: After reading a few of the replies, I realized that I have been under-utilizing the 'fetch' command. While my old workflow was based on pulling the latest on always merging/rebasing onto a clean master branch, I can see how updating the master and doing some dry runs before merging/rebasing would save time correcting conflicts.

1

since you're open sourcing a server project, you need to know the following commands

  • remote
  • push
  • pull
  • fetch

link http://gitref.org/remotes/

@Joonas' link to resources are good enough, though I added these commands since you'll need them in an open source development.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.