GIT is a free and open source distributed version control system designed
to handle everything from small to very large projects with speed and efficiency.
It is complex and somewhat picky about who it appears friendly to. For a
friendly web interface, and shared hub see
GitHub:
https://github.com
Note: the following was written with msysgit on Windows, but it should apply to all versions and operating systems.
To turn an existing folder into a git repository (aka "repo"):
git init
git creates a hidden metadata folder to store information about the changes
made to files. This must be separate from the files, since only the currently
checked out version of the file data will be in the file. The prior versions
and branches will be in the hidden folder.
Note that files in the folder are NOT automatically committed to the repo,
nor will they be included in a commit. You have to stage files to
be tracked, and then commit them. Staged files are going
to be version tracked. Keeping them separate from other files provides a
way to focus tracking on only those files which need it.
Add files to the repo with
git add filename
you can remove files from tracking with
git reset filename
And then to commit those changes into the new repo (it doesn't automatically
do that when you init) use commit. To automatically stage all the changes to the files you have added, include the -a flag. You can add an optional message.
git commit -a
will open the default command line editor (e.g. nano) for the commit message, or you can including it on the command line with:
git commit -am "message"
(by convention, the message should be a command. E.g. "Add stuff" instead
of "Added stuff" or "Adding stuff"). If you choose not to include the message on
the command line, git will open an editor window with a default message and
expect you to edit that. By default, in Linux OSs, the editor used is vi.
vi is only friendly to some users. Move cursor with arrows, press the i key
to insert text, press Esc to stop inserting. Type :wq to save and
quit. If something goes wrong, type :q to quite without saving.
That is the : or colon key followed by q.
If you keep notes about your work in a separate text file, you can use those as the commit message by using the -F file option
Because it is important to ensure that each individual commit is a logical grouping of changes, it is sometimes useful to remove one or more files from tracking via the reset command before a commit, then re-add those files and make a second commit.
You can make a local copy of a remote repository (or repo)
with the command:
git clone URL
This copies in ALL the changes to the files, not just the current version.
By default, your local directory will show the head of the repo, usually
the master branch, and the files will be as they are currently in the repo.
If you are working from GitHub, the URL will be
https://github.com/ProfileName/repoName.git
Existing files from the remote repo are already staged, and any changes to them are ready for a git commit. Any new files in the local clone will need to be added to the stage before being committed.
To update the local from the remote, use:
git pull origin master
assuming the name of the remote is origin (which it is by default) and the
name of the local branch is master (which it is by default). See below for
more.
We can see a simple list of the past changes to a repo with the command:
git log
issued inside the repositories main folder. The list includes unique commit
ID's along with the data, author and comment about each entry.
Neat trick: Add this to .getconfig
[alias]
lg = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold cyan)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all(the line starting lg= is a single line and should not be wrapped as it is shown here) git lg will produce a nice graph of git branches.
To view the differences between two commit ID's use the command:
git diff commitID commitID
This will list each file that has changed, and the differences between the
files in diff -c format.
git diff by itself shows the difference between the working
files and the staging area (files which have been added, but not yet
committed)
git diff --staged shows the difference between the staging
area and the head commit.
git show commitID shows the difference between a commitID
and it's immediate "parent"... the commit just before it.
To go back to a prior version or branch, use
git checkout commitID
commitID can be "master" to return to the head.
We can quickly see the status of the repo, including which files are
not committed, by running
git status
This will list the current branch, the current commit, and which files are
not being tracked or have been changed.
Branches allow you to make completely separate versions, as opposed
to revisions, of your files which are tracked separately over time and which
you can switch between. It is always good to keep a known working branch,
Master is the default branch, and then experiment with a named branch
off the Master "trunk". Branches can also be used to allow multiple people
to work at the same time on the same code by creating a branch for each
person. Commits are only added to the branch you currently have checked out.
You can merge branches (usually back to the master) if the experiment works
out.
git branch
lists the current branches with a star next to the currently checked out
branch.
git branch branchName
makes a new branch but does not check it out.
git checkout branchName
checks out a branch. New commits will be added to this branch.
Note that git log shows commits along the branch that is currently checked out. So there may be other commitID's which are not listed if they are on another branch. Having a diagram that shows all the branches would be really nice...
Because branches are basically just names for commitID's, we can view the
differences between two branches with the command:
git diff branchName branchName
If you check out a commitID which is not at the end, or HEAD, of a branch,
and then commit new changes from that revision, you will be in "detached
HEAD" state. You are following a new, unnamed, path which is sprouting
off from one of the named branches. The commits you make will not show up
in logs after checking out a branch head, and will not be merged back into
the Master if those branches are merged. To make this twig a new branch,
use:
git checkout -b branchName
which both makes a new branch and then checks it out.
To merge branches back together, differences must be resolved. That can be difficult, but git can figure out most issues by itself by looking through the prior versions on each branch to see what was added or removed.
To start a merge, checkout the branch were you want to continue development
from in the future. Normally, this is the Master branch. Then issue the
command:
git merge branchName [branchName ...]
Note that you can specify as many other branches as you like, potentially
merging them all back into the current branch.
If there is a conflict which can not be resolved automatically, git will
report which files are in conflict and ask you to fix it. Note that the merge
operation has still been started. To abort the merge, use:
git merge --abort
then you can use diff to view the files in conflict, resolve the conflict,
add and commit those new file versions and try the merge again. Once possible
source of conflict is line ending differences between operating systems.
See:
https://help.github.com/articles/dealing-with-line-endings/#platform-all
To continue the merge, and work with git to resolve the conflicts, don't abort the merge, but instead edit the files git called out in the error message. You will find that git has edited those files to include tags marking areas of conflict:
Edit the file to combine the code, retaining all the features you want. Work
with others if you aren't sure what their changes accomplish. Be sure to
remove the lines git added to mark the conflict. When you are finished, use
git status
to verify the new file shows "both modified" (meaning it was changed
in both branches) and then use
git add filename
to mark the new version to be committed.
Once you have tested and compiled the files, finish by using
git commit
to complete the merge. The message git auto-generates will show what branches
were merged and which files had conflicts.
After a merge, all the commits in the merged branches will show in the log
in chronological order. As a result, the diff between commitID's may not
show only the changes made by the parent commit. Use:
git show commitID
to display the changes from that ID's parent.
After a merge, if the branch name that was merged into the current branch
is not wanted, it can be deleted with :
git branch -d branchName
GitHub.com is a web-based Git repository hosting service. It offers all of the distributed revision control and source code management (SCM) functionality of a standard remote Git repo server allowing multiple users to collaborate on a project through local Git repos. It provides access control and several collaboration features such as bug tracking, feature requests, task management, and wikis for every project.
You can make a local copy of a remote repository (or
repo) on github with the command:
git clone
https://github.com/ProfileName/repoName.git
To update the local from the remote, use:
git pull origin master
assuming the name of the remote is origin (which it is by default) and the
name of the local branch is master (which it is by default). See below for
more.
To make a remote copy of a local repo,
Troubleshooting. If it fails for user/pass without asking you for either, then there is a bad certificate helper installed. If it only asks for pass, the username may be pre-set. Those can be inherited from the global or default settings. Edit the local config file for the repo.
Conflicts must be resolved manually: There is no system for automatically sycronizing repos because too many conflicts require human review to resolve. Googles collaborative documents avoid this problem (for the most part) by re-syncronizing so quickly and constantly that conflicts don't have a chance to develop... but that causes conflicts between programmers making incompatible changes in the code all at the same time, and it moves a lot of data around, increasing overhead.
Fork at the Remote Repo: Even if you are going to clone a remote repo to work on it locally, when you are collaborating or want to extend or change code written by someone else, it's best to "Fork" that code on the remote so that there is a record of the source, and the possibility for the original author to pull your changes back into the main project. See: GitHub:Fork for detailed instructions.
Locals may be out of sync with Remotes. If changes are made by you
in the local repo, and different, but non-conflicting changes are made
by someone else to the remote repo, then there is no problem, just use the
pull command to merge them back into your local repo:
git pull remoteName branchName
Resolve Conflicts: If there is a conflict, you will have to resolve it in several steps.
It's best to collaborate on a branch off of master. When you are collaborating on a project, other people may need to clone and use the master branch for testing or just getting work done. It should be stable and the lead author probably only wants known working code in there. So if you are going to make changes, especially if they are complex, and involved changes in several files, it's best to fork, create a branch, make your changes on that branch (pulling to your local repo, editing, add, commit, push as needed or edit online) and then generate a pull request for the new branch. This gives the lead an opportunity to look at your branch on their local system without changing master.
However, it does make it more difficult to incorporate changes into your
branch which are made to master during the period you are working on your
branch. Rather than simply pulling and pushing, you need to
git pull
their changes into your local master branch, merge the local master into
your branch with
git merge master branchName
resolve conflicts,
git commit
then push your branch to the remote
git push origin branchName
before your branch can be merged into master, either locally or on GitHub.
If you you decide that everything you tried is wrong, and you just want to toss it and go back to where you were at your last commit, you can issue
git reset --hard
and that will put all the tracked files back to their prior state. It will not
remove any new files unless they were added to the staging area.
See also: