The major difference between Git and any other VCS (Subversion and friends included) is the way Git thinks about its data. Conceptually, most other systems store information as a list of file-based changes. These systems (CVS, Subversion, Perforce, Bazaar, and so on) think of the information they keep as a set of files and the changes made to each file over time.
Git doesn’t think of or store its data this way. Instead, Git thinks of its data more like a set of snapshots of a miniature filesystem. Every time you commit, or save the state of your project in Git, it basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. To be efficient, if files have not changed, Git doesn’t store the file again, just a link to the previous identical file it has already stored. Git thinks about its data more like a stream of snapshots.
Most operations in Git only need local files and resources to operate – generally no information is needed from another computer on your network.
Everything in Git is check-summed before it is stored and is then referred to by that checksum.
The mechanism that Git uses for this checksumming is called a SHA-1 hash.
When you do actions in Git, nearly all of them only add data to the Git database. It is hard to get the system to do anything that is not undoable or to make it erase data in any way.
Git has three main states that your files can reside in: committed, modified, and staged. Committed means that the data is safely stored in your local database. Modified means that you have changed the file but have not committed it to your database yet. Staged means that you have marked a modified file in its current version to go into your next commit snapshot.
The installer includes a command line version of Git as well as the GUI. It also works well with Powershell, and sets up solid credential caching and sane CRLF settings. We’ll learn more about those things a little later, but suffice it to say they’re things you want. You can download this from the GitHub for Windows website, at http://windows.github.com.
On Windows systems, Git looks for the .gitconfig file in the $HOME directory (C:\Users\$USER for most people).
The first thing you should do when you install Git is to set your user name and email address. This is important because every Git commit uses this information, and it’s immutably baked into the commits you start creating:
$ git config --global user.name "John Doe" $ git config --global user.email email@example.com
$ git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe'
If you want to check your settings, you can use the git config --list command to list all the settings Git can find at that point
$ git config --list
If you ever need help while using Git, there are three ways to get the manual page (manpage) help for any of the Git commands:
$ git help $ git --help $ man git-
If you’re starting to track an existing project in Git, you need to go to the project’s directory. If you’ve never done this, it looks a little different depending on which system you’re running:
$ cd /c/user/your_repository $ git init
This creates a new subdirectory named .git that contains all of your necessary repository files – a Git repository skeleton. At this point, nothing in your project is tracked yet.
If you want to start version-controlling existing files (as opposed to an empty directory), you should probably begin tracking those files and do an initial commit. You can accomplish that with a few git add commands that specify the files you want to track, followed by a git commit:
$ git add *.c $ git add LICENSE $ git commit -m 'initial project version'
If you want to get a copy of an existing Git repository – for example, a project you’d like to contribute to – the command you need is git clone.
You clone a repository with git clone [url]. For example, if you want to clone the Git linkable library called libgit2, you can do so like this:
$ git clone https://github.com/libgit2/libgit2
That creates a directory named “libgit2”, initializes a .git directory inside it, pulls down all the data for that repository, and checks out a working copy of the latest version.
If you want to clone the repository into a directory named something other than “libgit2”, you can specify that as the next command-line option:
$ git clone https://github.com/libgit2/libgit2 mylibgit
That command does the same thing as the previous one, but the target directory is called mylibgit.
Git has a number of different transfer protocols you can use. The previous example uses the https:// protocol, but you may also see git:// or user@server:path/to/repo.git, which uses the SSH transfer protocol.
The main tool you use to determine which files are in which state is the git status command.
> git status
On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean
In order to begin tracking a new file, you use the command git add. To begin tracking the README file, you can run this:
$ git add README
Let’s change a file that was already tracked. If you change a previously tracked file called CONTRIBUTING.md and then run your git status command again, you get something that looks like this:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD ..." to unstage) new file: README Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: CONTRIBUTING.md
To stage it, you run the git add command. git add is a multipurpose command – you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved. It may be helpful to think of it more as “add this content to the next commit” rather than “add this file to the project”. Let’s run git add now to stage the CONTRIBUTING.md file, and then run git status again:
$ git add CONTRIBUTING.md $ git status
While the git status output is pretty comprehensive, it’s also quite wordy. Git also has a short status flag so you can see your changes in a more compact way. If you run git status -s or git status --short you get a far more simplified output from the command:
$ git status -s
Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. These are generally automatically generated files such as log files or files produced by your build system. In such cases, you can create a file listing patterns to match them named .gitignore. Here is an example .gitignore file:
$ cat .gitignore *.[oa]
If the git status command is too vague for you – you want to know exactly what you changed, not just which files were changed – you can use the git diff command.
To see what you’ve changed but not yet staged, type git diff with no other arguments:
$ git diff
Now you can use git diff to see what is still unstaged:
$ git diff
and git diff --cached to see what you’ve staged so far (--staged and --cached are synonyms):
$ git diff --cached
Now that your staging area is set up the way you want it, you can commit your changes. Remember that anything that is still unstaged – any files you have created or modified that you haven’t run git add on since you edited them – won’t go into this commit. They will stay as modified files on your disk. In this case, let’s say that the last time you ran git status, you saw that everything was staged, so you’re ready to commit your changes. The simplest way to commit is to type git commit:
$ git commit
Doing so launches your editor of choice to enter commit comment.
Alternatively, you can type your commit message inline with the commit command by specifying it after a -m flag, like this:
$ git commit -m "Story 182: Fix benchmarks for speed"
Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow. If you want to skip the staging area, Git provides a simple shortcut. Adding the -a option to the git commit command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the git add part:
$ git commit -a -m 'added new benchmarks'
To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit. The git rm command does that, and also removes the file from your working directory so you don’t see it as an untracked file the next time around.
If you simply remove the file from your working directory, it shows up under the “Changed but not updated” (that is, unstaged) area of your git status output:
$ rm PROJECTS.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add/rm ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) deleted: PROJECTS.md no changes added to commit (use "git add" and/or "git commit -a")
Then, if you run git rm, it stages the file’s removal:
$ git rm PROJECTS.md
Another useful thing you may want to do is to keep the file in your working tree but remove it from your staging area. In other words, you may want to keep the file on your hard drive but not have Git track it anymore. This is particularly useful if you forgot to add something to your .gitignore file and accidentally staged it, like a large log file or a bunch of .a compiled files. To do this, use the --cached option:
$ git rm --cached README
You can pass files, directories, and file-glob patterns to the git rm command. That means you can do things such as:
$ git rm log/\*.log
Note the backslash (\) in front of the *. This is necessary because Git does its own filename expansion in addition to your shell’s filename expansion. This command removes all files that have the .log extension in the log/ directory. Or, you can do something like this:
$ git rm \*~
This command removes all files whose names end with a ~.
Unlike many other VCS systems, Git doesn’t explicitly track file movement. If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file. However, Git is pretty smart about figuring that out after the fact – we’ll deal with detecting file movement a bit later.
Thus it’s a bit confusing that Git has a mv command. If you want to rename a file in Git, you can run something like:
$ git mv file_from file_to
and it works fine. In fact, if you run something like this and look at the status, you’ll see that Git considers it a renamed file:
$ git mv README.md README $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD ..." to unstage) renamed: README.md -> README
However, this is equivalent to running something like this:
$ mv README.md README $ git rm README.md $ git add README
After you have created several commits, or if you have cloned a repository with an existing commit history, you’ll probably want to look back to see what has happened. The most basic and powerful tool to do this is the git log command.
$ git log
One of the more helpful options is -p, which shows the difference introduced in each commit. You can also use -2, which limits the output to only the last two entries:
$ git log -p -2
If you want to see some abbreviated stats for each commit, you can use the --stat option:
$ git log –stat
The oneline option prints each commit on a single line, which is useful if you’re looking at a lot of commits. In addition, the short, full, and fuller options show the output in roughly the same format but with less or more information, respectively:
$ git log –pretty=oneline
Useful options for git log --pretty=format lists some of the more useful options that format takes.
The oneline and format options are particularly useful with another log option called --graph. This option adds a nice little ASCII graph showing your branch and merge history:
$ git log --pretty=format:"%h %s" –graph
In addition to output-formatting options, git log takes a number of useful limiting options – that is, options that let you show only a subset of commits.
However, the time-limiting options such as --since and --until are very useful. For example, this command gets the list of commits made in the last two weeks:
$ git log --since=2.weeks
At any stage, you may want to undo something. Here, we’ll review a few basic tools for undoing changes that you’ve made. Be careful, because you can’t always undo some of these undos. This is one of the few areas in Git where you may lose some work if you do it wrong.
One of the common undos takes place when you commit too early and possibly forget to add some files, or you mess up your commit message. If you want to try that commit again, you can run commit with the --amend option:
$ git commit --amend
The next two sections demonstrate how to work with your staging area and working directory changes.
$ git add * $ git status On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) renamed: README.md -> README modified: CONTRIBUTING.md
Right below the “Changes to be committed” text, it says use git reset HEAD ... to unstage. So, let’s use that advice to unstage the CONTRIBUTING.md file:
$ git reset HEAD CONTRIBUTING.md
What if you realize that you don’t want to keep your changes to the CONTRIBUTING.md file? How can you easily unmodify it – revert it back to what it looked like when you last committed (or initially cloned, or however you got it into your working directory)? Luckily, git status tells you how to do that, too. In the last example output, the unstaged area looks like this:
Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: CONTRIBUTING.md
It tells you pretty explicitly how to discard the changes you’ve made. Let’s do what it says:
$ git checkout -- CONTRIBUTING.md $ git status
To see which remote servers you have configured, you can run the git remote command.
$ git remote
You can also specify -v, which shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote:
$ git remote -v
We’ve mentioned and given some demonstrations of how the clone command implicitly adds the origin remote for you. Here’s how to add a new remote explicitly. To add a new remote Git repository as a shortname you can reference easily, run git remote add :
$ git remote $ git remote add pb https://github.com/
Now you can use the string pb on the command line in lieu of the whole URL. For example, if you want to fetch all the information that Paul has but that you don’t yet have in your repository, you can run git fetch pb:
$ git fetch pb
As you just saw, to get data from your remote projects, you can run:
$ git fetch [remote-name]
It’s important to note that the git fetch command only downloads the data to your local repository – it doesn’t automatically merge it with any of your work or modify what you’re currently working on. You have to merge it manually into your work when you’re ready.
If your current branch is set up to track a remote branch (see the next section and Git Branching for more information), you can use the git pull command to automatically fetch and then merge that remote branch into your current branch.
When you have your project at a point that you want to share, you have to push it upstream. The command for this is simple: git push [remote-name] [branch-name]. If you want to push your master branch to your origin server (again, cloning generally sets up both of those names for you automatically), then you can run this to push any commits you’ve done back up to the server:
$ git push origin master
If you want to see more information about a particular remote, you can use the git remote show [remote-name] command. If you run this command with a particular shortname, such as origin, you get something like this:
$ git remote show origin
You can run git remote rename to change a remote’s shortname. For instance, if you want to rename pb to paul, you can do so with git remote rename:
$ git remote rename pb paul $ git remote origin paul
It’s worth mentioning that this changes all your remote-tracking branch names, too. What used to be referenced at pb/master is now at paul/master.
If you want to remove a remote for some reason – you’ve moved the server or are no longer using a particular mirror, or perhaps a contributor isn’t contributing anymore – you can either use git remote remove or git remote rm:
$ git remote remove paul $ git remote origin
Like most VCSs, Git has the ability to tag specific points in history as being important. Typically people use this functionality to mark release points (v1.0, and so on). In this section, you’ll learn how to list the available tags, how to create new tags, and what the different types of tags are.
$ git tag
Git uses two main types of tags: lightweight and annotated.
A lightweight tag is very much like a branch that doesn’t change – it’s just a pointer to a specific commit.
Annotated tags, however, are stored as full objects in the Git database.
Creating an annotated tag in Git is simple. The easiest way is to specify -a when you run the tag command:
$ git tag -a v1.4 -m "my version 1.4" $ git tag v0.1 v1.3 v1.4
The -m specifies a tagging message, which is stored with the tag. If you don’t specify a message for an annotated tag, Git launches your editor so you can type it in.
You can see the tag data along with the commit that was tagged by using the git show command:
$ git show v1.4
That shows the tagger information, the date the commit was tagged, and the annotation message before showing the commit information.
Another way to tag commits is with a lightweight tag. This is basically the commit checksum stored in a file – no other information is kept. To create a lightweight tag, don’t supply the -a, -s, or -m option:
$ git tag v1.4-lw $ git tag v0.1 v1.3 v1.4 v1.4-lw v1.5
This time, if you run git show on the tag, you don’t see the extra tag information. The command just shows the commit:
$ git show v1.4-lw commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number
You can also tag commits after you’ve moved past them. Suppose your commit history looks like this:
$ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support 0d52aaab4479697da7686c15f77a3d64d9165190 one more thing 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment' 0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function 4682c3261057305bdd616e23b64b0857d832627b added a todo file 166ae0c4d3f420721acbb115cc33848dfcc2121a started write support 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
Now, suppose you forgot to tag the project at v1.2, which was at the “updated rakefile” commit. You can add it after the fact. To tag that commit, you specify the commit checksum (or part of it) at the end of the command:
$ git tag -a v1.2 9fceb02
By default, the git push command doesn’t transfer tags to remote servers. You will have to explicitly push tags to a shared server after you have created them. This process is just like sharing remote branches – you can run git push origin [tagname].
$ git push origin v1.5
If you have a lot of tags that you want to push up at once, you can also use the --tags option to the git push command. This will transfer all of your tags to the remote server that are not already there.
$ git push origin --tags
Now, when someone else clones or pulls from your repository, they will get all your tags as well.
You can’t really check out a tag in Git, since they can’t be moved around. If you want to put a version of your repository in your working directory that looks like a specific tag, you can create a new branch at a specific tag with git checkout -b [branchname] [tagname]:
$ git checkout -b version2 v2.0.0 Switched to a new branch 'version2'
Of course if you do this and do a commit, your version2 branch will be slightly different than your v2.0.0 tag since it will move forward with your new changes, so do be careful.
Use the branch command with a name to create a new branch with that name.
$ git branch * develop master
Use -a flag to check also remote branches
git branch -a * develop master remotes/origin/develop remotes/origin/master
$ git branch new_issue $ git branch * develop master new_issue $ git branch -a * develop master new_issue remotes/origin/develop remotes/origin/master
Switch over to the branch "new_issue" when you want to add new commits to it.
Use the checkout command to switch branch.
$ git checkout new_issue Switched to branch 'new_issue'
By passing in the -b option when executing the checkout command, a new branch will be created and you will be switched over after that.
$ git checkout -b new_issue2 Switched to a new branch 'new_issue2'
If the branch already exists, an error is raised
$ git checkout -b new_issue fatal: A branch named 'new_issue' already exists.
Once you are on the "new_issue" branch, you can start adding commits to it.
Create a new file new_issue_file.txt
$ git status On branch new_issue Untracked files: (use "git add ..." to include in what will be committed) new_issue_file.txt nothing added to commit but untracked files present (use "git add" to track)
$ git add new_issue_file.txt $ git status On branch new_issue Changes to be committed: (use "git reset HEAD ..." to unstage) new file: new_issue_file.txt
$ git commit -m "Add new_issue_file" [new_issue2 57736d7] Add new_issue_file 1 file changed, 2 insertions(+) create mode 100644 D8/scripts/asm/new_issue_file.txt
$ git log --graph --oneline --all
* 57736d7 (HEAD -> new_issue2) Add new_issue2_file * 49ce8cf (origin/develop, new_issue, develop) Add asm scripts * 2e5c8a2 Rename ReadMe.txt * c601f03 Merge remote-tracking branch 'origin/develop' into develop |\ | | * a6abcee (origin/master, master) Merge remote-tracking branch 'origin/master' | | |\ | |/ / |/| / | |/ | * 92c2dbc Create ReadMe.txt * 07665d1 initial commit
Use the merge command to merge branches.
$ git merge
By running the command above, the specified commit will be merged to the current active branch.
$ git checkout master Already on 'master' Your branch is ahead of 'origin/master' by 4 commits. (use "git push" to publish your local commits) $ git merge new_issue2 Merge made by the 'recursive' strategy. D8/scripts/asm/new_issue2_file.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 D8/scripts/asm/new_issue2_file.txt
$ git log --graph --oneline --all
* 59814f0 (HEAD -> master) Merge branch 'new_issue2' |\ | * 57736d7 (new_issue2) Add new_issue2_file * | 6225a13 Merge branch 'new_issue' |\ \ | |/ ...
Now that "new_issue2" has been successfully merged with "master", we can delete it.
We can delete a branch by calling the branch command and passing in the -d option, followed by the branch name.
$ git branch -d
$ git branch -d new_issue2 Deleted branch new_issue2 (was 57736d7).
$ git branch develop * master
Branching allows us to work in multiple parallel workspaces.
Let's create two branches. Create one with the name "new_issue2" and another with the name"new_issue3", then switch over to "new_issue2".
$ git branch new_issue2 $ git branch new_issue3 $ git checkout new_issue2 Switched to branch 'new_issue2' $ git branch develop master * new_issue2 new_issue3
Add the bold text below to new_issue2_file.txt and commit the change.
Git commands even a monkey can understand add: Register a change in an indexcommit: Save the index status
$ git status On branch new_issue2 Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: new_issue2_file.txtno changes added to commit (use "git add" and/or "git commit -a") $ git add new_issue2_file.txt $ git commit -m "Save the index status" [new_issue2 2c4d9bc] Save the index status 1 file changed, 2 insertions(+), 1 deletion(-)
A fast-forward merge (Git simply moves the commit pointer forward) has now been executed.
Now switch to "new_issue3" branch.
$ git checkout new_issue3 Switched to branch 'new_issue3'
"new_issue3" currently has the same history/content as the master branch. It will not include the recent change that we have just made. This is because the recent change has been commited to the "new_issue2" branch.
Add the bold text below to new_issue2_file.txt and commit the change.
Git commands even a monkey can understand add: Register a change in an indexpull: Get remote content
$ git add new_issue2_file.txt $ git commit -m "Get remote content" [new_issue3 58c5f07] Get remote content 1 file changed, 2 insertions(+), 1 deletion(-)
Now let's merge branches "new_issue2" and "new_issue3" into the master branch.
We will switch over to "master" and merge "new_issue2" with it and then "new_issue3"
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 6 commits. (use "git push" to publish your local commits) $ git merge new_issue2 Updating 59814f0..2c4d9bc Fast-forward D8/scripts/asm/new_issue2_file.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) $ git merge new_issue3 Auto-merging D8/scripts/asm/new_issue2_file.txt CONFLICT (content): Merge conflict in D8/scripts/asm/new_issue2_file.txt Automatic merge failed; fix conflicts and then commit the result.
Git has identified a conflict and will not allow you to automatically merge "new_issue3" with "master". The conflict here pertains to the same line on new_issue2_file.txtt with different content on both branches. Due to the conflict during the attempt to merge, new_issue2_file.txt will look something like this.
Git commands even a monkey can understand add: Register a change in an index <<<<<<< HEAD commit: Save the index status ======= pull: Get remote content >>>>>>> new_issue3
Update the file like this
Git commands even a monkey can understand add: Register a change in an index commit: Save the index status pull: Get remote content
$ git status On branch master Your branch is ahead of 'origin/master' by 7 commits. (use "git push" to publish your local commits) You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add ..." to mark resolution) both modified: new_issue2_file.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add new_issue2_file.txt $ git commit -m "new_issue3 branch merge" [master d143a7b] new_issue3 branch merge
The revision history will now look like the one below. A new merge commit has been created as a result of the conflict resolution. The master branch is now pointing to the latest merge commit.
This is a non fast-forward merge.
$ git log --graph --oneline --all * d143a7b (HEAD -> master) new_issue3 branch merge |\ | * 58c5f07 (new_issue3) Get remote content * | 2c4d9bc (new_issue2) Save the index status |/ * 59814f0 Merge branch 'new_issue2'
Another approach we can take to integrate "issue3" branch into the master branch is by using the rebase command. Using rebase, we can streamline and clean our history tree just like how we have described earlier.
Let's start by undoing the previous merge.
$ git reset --hard HEAD~ HEAD is now at 2c4d9bc Save the index status $ git log --graph --oneline --all * 58c5f07 (new_issue3) Get remote content | * 2c4d9bc (HEAD -> master, new_issue2) Save the index status |/ * 59814f0 Merge branch 'new_issue2'
Switch over to "new_issue3" branch and rebase onto the master branch.
$ git checkout new_issue3 Switched to branch 'new_issue3' $ git rebase master First, rewinding head to replay your work on top of it... Applying: Get remote content Using index info to reconstruct a base tree... M D8/scripts/asm/new_issue2_file.txt Falling back to patching base and 3-way merge... Auto-merging D8/scripts/asm/new_issue2_file.txt CONFLICT (content): Merge conflict in D8/scripts/asm/new_issue2_file.txt error: Failed to merge in the changes. hint: Use 'git am --show-current-patch' to see the failed patch Patch failed at 0001 Get remote content Resolve all conflicts manually, mark them as resolved with "git add/rm ", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort".
When a conflict occurs during the rebase, you will have to resolve it immediately in order to resume the rebase operation.
Git commands even a monkey can understand add: Register a change in an index <<<<<<< HEAD commit: Save the index status ======= pull: Get remote content >>>>>>> Get remote content
$ git status rebase in progress; onto 2c4d9bc You are currently rebasing branch 'new_issue3' on '2c4d9bc'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git reset HEAD ..." to unstage) (use "git add ..." to mark resolution) both modified: new_issue2_file.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add new_issue2_file.txt $ git rebase --continue
With the "new_issue3" branch rebased onto "master", we can now issue a fast-forward merge.
Switch over to the master branch and merge "new_issue3" with "master".
$ git status On branch new_issue3 nothing to commit, working tree clean $ git log --graph --oneline --all * 48c3600 (HEAD -> new_issue3) Get remote content * 2c4d9bc (new_issue2, master) Save the index status * 59814f0 Merge branch 'new_issue2' |\ | * 57736d7 Add new_issue2_file * | 6225a13 Merge branch 'new_issue' ... $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 7 commits. (use "git push" to publish your local commits) $ git merge new_issue3 Updating 2c4d9bc..48c3600 Fast-forward D8/scripts/asm/new_issue2_file.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) $ git log --graph --oneline --all * 48c3600 (HEAD -> master, new_issue3) Get remote content * 2c4d9bc (new_issue2) Save the index status * 59814f0 Merge branch 'new_issue2' |\ | * 57736d7 Add new_issue2_file * | 6225a13 Merge branch 'new_issue' ...