GIT Quick Guide

From Bitnami MediaWiki
Jump to navigation Jump to search

This is a quick guide for new developers or managers who need to learn how to use Git. This section is based on Windows, Azure DevOps (as an example Git host), and is opinionated by the sole use of the Git CLI (i.e. command line) rather than showing how to use Git via a GUI.

A repository (or repo for short) is a special folder that typically holds the source code files of a software project (although it can hold any type of file) with the purpose of keeping the entire history of all the source code changes in the project, sharing the project with other developers for collaboration, and serving as a file backup. Each git repo have a special .git folder.

A commit is a single set of changes to the source code that have been recorded in the repo (src). If you’re familiar with relational databases, an analogy to a source code commit is a database transacton that has been committed.

Git is a distributed version control system where you can create repositories on your local computer and commit source code to the repo without requiring a network connection to a central server. This is in contrast with other version control systems such as SVN which requires a network connection to a central server to commit any changes.

Git and GitHub are two different things: Git is the actual version control program while GitHub is a Git host which is a hosting service for hosting Git repositories originally designed for open-source software collaboration (but private repos are allowed now). You may have heard of a feature called a pull request but that is not a feature of Git, but is a feature in GitHub so will not be explained in this guide.

Open a terminal such as PowerShell. To check if Git is installed, you can try running git --version which will display the current version of Git if installed.

Configure username and email. Run git config --global user.name "First Last" and run git config --global user.email first.last@example.com. Can check the configuration by running git config --global --list.

Azure DevOps Services is an online service from Microsoft that provides issue tracking, project management, Git hosting for projects, and much more.

You can find the link to download a Git project by copying the link and running git clone <link> in the terminal. Sign in to your organization’s Azure DevOps e.g. https://dev.azure.com/myorganization/, click on a Azure DevOps project, click Repos on the left, select a Git repo on the navigation breadcrumb at the top by clicking on the down arrow e.g. FooProject / Repos / Files / <Git-repo>, click Clone button near the top right, copy the HTTPS link, and in the terminal run e.g. git clone https://myorganization@dev.azure.com/myorganization/FooProject/_git/git-repo. This creates a local copy of the remote repo. Run ls (or dir in Command Line) and you should see the folder of the Git repo.

Make code changes. The working directory refers to the directory of the Git repo and the current state of local source code files. After making some code changes by modifying the local source code files, you can examine what has changed by running git status. If you get an error, ensure that your terminal’s current directory is within the Git repo as most Git commands require being inside the folder of the Git repo.

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/views/HomeView.vue
        deleted:    src/views/FooView.vue

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/views/BarView.vue

In the above example output, you can see that one file was modified, another file was deleted, and there’s an untracked file which means that it’s a new file that the Git repo has never seen before. To restore the modified or deleted file, run git restore <path>. To remove the untracked file, simply delete the file from the local filesystem.

Commit some changes. At some point, you will have a bunch of uncommitted changes to the source code and you may want to commit the changes to the Git repo. In the terminal run git add <path> where it can refer to a file or folder that contains changes or new files. Run git add -A to add all changes and any new files. When you use the git add command, the files are copied to a staging area, and the files are not pushed to the remote repo yet (how changes are pushed to the remote repo will be explained later). To check what files are currently in the staging area, run git status e.g.

Changes to be committed:

  (use “git restore --staged <file>..." to unstage)
        modified:   src/views/HomeView.vue
        deleted:    src/views/FooView.vue
        new file:   src/views/BarView.vue

To commit the staged files, run git commit.

Git commit message. After running git commit, the vim editor appears. Press i to enter edit mode where you can start typing a commit message. Write good Git commit messages like below (src):

<summary_line>

<optional_commit_content>

<work_item>

For example, the summary line should be 50 characters max, and if you’re using an issue tracking system like JIRA or Azure DevOps, put the work item number at the bottom. A good Git commit message allows your future self and other developers to understand why something was changed e.g.

Clarify the "highlighted rows" message

That is the only thing we need to do to solve the "There is nothing to process" error.

bug-456

After that, press Esc key (to exit out of edit mode) and press colon key (:) and then w and q, then press Enter key. The w means write and q means quit. At this point the commit is written to the commit history. Note that the changes still have not been pushed to the remote repo and the commit is recorded only in the local repo on your computer. This is why Git is a distributed version control system—because commits can be recorded on a local copy of the remote.

Tip: to remove files from the staging area, run git reset which will remove all the files from staging area. To remove a single file from the staging area, run git reset <path>.

Tip: to cancel out of a git commit, press colon key and then c and q, then press Enter key.

Push code changes to remote by running git push. After this is done, the changes are now saved in the remote and other developers can see your changes.

Modifying staged files. Note that if you staged a file, then modify the same file in the working directory, the version inside the staging area is not modified because the staged file is a copy of the file at the moment that it was staged. This can be seen by running git status:

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   src/views/HomeView.vue

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/views/HomeView.vue

You can stage the modifications by running the git add command again.

Tip: commit early, commit often (src).

A branch is an independent line of commits in the commit history. The commit history is a directed acyclic graph, like a tree with branches that can be merged back into other branches or back into the trunk of the tree. You usually want to create a branch when a feature may require multiple commits to work properly. That kind of branch is known as a feature branch.

To know what is the current branch that the local Git repo is on, run git status which will output “On branch <branch>” at the top. For most common commands, they affect the current branch e.g. any code committed will be committed to the current branch.

Tip: to reset all local file modifications of the working directory back to the latest commit of the current branch and to also clear the staging area, run git reset --hard. If any files were deleted, they will come back.

Any untracked files that weren’t staged would still be there. To remove all untracked files and folders, run git clean -fd.

Creating and checking out branches. The default branch of any new Git repo is the master branch (or the main branch). To create a branch, run git branch <branch> e.g. git branch bug-457. The name of the branch is usually a name of a new feature or the work item in the issue tracking system.

To check out a branch is to switch to that branch and that is done by running git checkout <branch>. There is a way to create a new branch and check it out at the same time and that is done by running git checkout -b <branch>.

If you made changes in the working directory and then try to switch to a different branch, it can switch to the other branch while keeping your changes in the working directory only if the same source code in the other branch does not have any changes relative to the latest common ancestor commit of both branches (i.e. both branches are not divergent). Otherwise if the other branch does have changes in those same source code files that you have modified locally then you will not be able to switch.

Merging branches. You may want to merge a branch into another branch e.g. back to master branch. Run the following:

git checkout master
git merge --no-ff --no-commit my-new-branch

This checks out the master branch and then merges the code from the my-new-branch branch into master. The --no-ff option means no fast-forward merges and will add a merge commit to the Git history (this may not make sense right now but it’s a complicated topic). The --no-commit option allows you to double-check the work before committing since git merge automatically commits by default.

After running git merge, there could be merge conflicts. A merge conflict is a situation where a file you have updated was also updated upstream by another developer or even by a different branch you have merged before, and Git wasn’t able to merge the two versions of the file automatically due to the same lines in the source code being changed. Run git status to see what files have merge conflicts e.g.

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   src/views/BarView.vue
        deleted by us:   src/views/BazView.vue
        deleted by them: src/views/QuxView.vue

The “both modified” means that the current branch you’re merging into (the current branch displayed by git status) and the branch you’re merging in (the branch specified in the git merge command), have modified the same parts in the file.

Inside files with merge conflicts, you will see sections separated by conflict markers where one section is code in the current branch and the other section is code in the branch you’re trying to merge in:

<<<<<<
code in the current branch
======
code in the branch you're merging in
>>>>>>

How you resolve the merge conflict depends on the logic of the code. Remove the conflict markers <<<<<<, ======, and >>>>>>. Run git add on the file to mark the merge conflict as resolved.

Besides merge conflicts, the two branches may have deleted files that were modified by the other. The “deleted by us” means that there was a commit on the current branch that deleted the file, but on the branch you’re merging in, it had modified the file (src). In most cases, a file being deleted means that the project does not need that file anymore, so you can just run git rm <file> to remove it. The “deleted by them” means the opposite, the current branch has commits that have modified the file, but on the branch you’re merging in, it had deleted the file.

Commit merge. If there are no unmerged files (e.g. no merge conflicts or if all the conflicts have been resolved), then you can run git commit to commit the merge. This opens vim with a commit message already added: “Merge branch 'my-new-branch' into master” and you can just press Esc key and press colon key (:) and then w and q, then press Enter key.

Pushing local branch to remote repo. The Git repo that you’re working on most likely originates from a remote Git repo such as Azure DevOps. For any new Git branch, the remote will not have this branch. The first push of any new branch is to be done by running git push -u origin <branch> e.g. git push -u origin my-new-branch where the -u option links the branch to the remote branch, and you only need to do this once for every new branch. For subsequent changes on the local branch, you must run git push if you want to keep the remote branch up to date.

Getting code updates from the remote. You can see the list of remote branches by running git branch -r. You can refresh the local Git repo’s list of remote branches by running git fetch. After that, to check out a local copy of a remote branch, run git checkout <remote_branch>. If another developer has pushed some changes to the same branch, you can get the upstream changes by running git pull.

Note that if you have changes in the same branch locally that haven’t been pushed, and there are upstream changes, and then you run git pull, Git will attempt to merge the code.

The commit history can be viewed by running git log which shows a list of commits that were committed to the repo in descending order with the top commit being the latest commit of the current branch. Each commit entry looks like the below, where angle brackets mean that part is always shown and square brackets mean that part is optional:

commit <commit_hash> [(<pointers>)]
[Merge: <merge_into_commit> <merging_commit>]
Author: <author> <author_email>
Date:   <day> <month> <date> <24_hour>:<minute>:<second> <year> <offset>

    <commit_message>

The commit hash is a unique ID for the commit.

The <pointers> is an optional area where it shows where different pointers are currently at. For example, if you see HEAD -> master, it means you’re currently on master branch and you’re at the latest commit of your local master branch. If there are no upstream changes and no new local commits, the origin/master pointer will also be part of the list, or if you have new local commits that you haven’t pushed to remote yet, the origin/master pointer may be earlier in the history, or if upstream does have changes, you won’t see the origin/master pointer because your local copy of the branch is behind.

If it is a merge commit, the “Merge: …” text will be displayed. The <merge_into_commit> is the commit hash of the branch that was being merged into, the <merging_commit> is the latest commit of the branch that was being merged in, at the moment the merge command was executed.

You can navigate up and down the log. Press q to exit out of the log.

Commit history diagram and how merging really works. Below is the master branch with commits a1, a2, a3, a4, and a5, and a foo-123 that was branched off from a3 commit of master, and foo-123 has commits b1 and b2, and the question mark (?) is where the my-new-branch is being merged into master:

master --a1--a2--a3--a4--a5--?
                   \        /
foo-123             -b1--b2-

As you can see, the commit history is a directed acyclic graph.

A different example below demonstrates another level of branching where a foo-123-experiment branch was branched off from foo-123:

master --a1--a2--a3--a4--a5---------?
                   \               /
foo-123             b1--b2        /
                          \      /
foo-123-experiment         c1--c2

When merging foo-123-experiment into master, it will also include the commits (e.g. b1 and b2) from foo-123 because it’s part of the same line of commits since the common ancestor commit between foo-123-experiment and master which is commit a3. But actually, the real reason is because the master branch does not have commits with those commit hashses that are in foo-123-experiment. After the branch is merged, if you try to merge foo-123 or foo-123-experiment to master again, nothing will happen because there are no new commits to merge, but if you then add a new commit b3 on foo-123, then merging foo-123 to master will result in b3 being merged into master.

A branching model (aka branching strategy or branching workflow) is a set of steps and rules on when to create branches. The Gitflow workflow is a branching model.

Git is complicated (src), but that is because source control is a complicated topic and a lot of the complexity is unavoidable (src), but hopefully this quick guide serves as a good starting point for more exploration e.g. Git hosts such as GitHub, pull requests, renaming files, detached HEAD, fast-forward merges, how to undo/revert commits, the git stash command, the git cherry-pick command, the git rebase command, more on remotes, etc.


Return to Novus