-
Notifications
You must be signed in to change notification settings - Fork 0
Branch
Here is how to create a branch out from the tip of the current branch (HEAD).
git branch my_branch
Here is how to create the branch named my_branch
that starts from the commit with the SHA-1 1234567
.
git branch my_branch 123467
Instead of a SHA-1, you can use any other commit reference for the starting point.
You can use for instance another branch name (origin/master
), or relative reference (HEAD~1
).
To remove a local branch (say my_branch) from my local git repository:
git branch -d my_branch
Git refuses to delete a local branch
which has not been merged into another branch.
To remove such a branch use the -D
option to bypass this safeguard.
git branch -D my_branch
To remove a branch from the remote repository. Say, for instance, I want to remove my_branch
from the remote repository named origin
:
git push --delete origin my_branch # if git version >= 1.7.0
If you are using git version < 1.7.0, then the previous command should not have worked saying the --delete
option is not supported, use the following command instead.
git push origin :my_branch # if git version < 1.7.0
Please note the colon :
preceding the name of the branch.
The colon acts as a separator in between the name of the local branch to push and the name of the remote branch where to push it to.
In the example above pushing nothing (no local branch) to the remote branch my_branch
has the effect of removing the remote branch my_branch
.
The below command list the local branches and gives you a hint about the branch you are currently sitting on.
git branch
* master
my_branch
There are 2 local branches master
and my_branch
.
The star (*
) next to a branch (master
in this example) indicates the current branch.
git branch
Cf. section List the Local Branches.
or
git rev-parse --abbrev-ref HEAD
The below command list the local branches without the star (*
) in front of the default branch.
git branch --format'%(refname:short)'
master
my_branch
This is useful to test if local branch is present like so:
git branch --format='%(refname:short)' | grep '^rainbow'
git branch -r
origin/batch-to-cassandra
origin/json-serialization-tests
origin/master
Each remote branch is prefixed with the remote name followed by a slash ('/').
git branch -a
* master
my_branch
origin/batch-to-cassandra
origin/json-serialization-tests
origin/master
To change the current branch and switch to the local and existing branch my_branch
:
git checkout my_branch
To go to the branch you were on previously (the branch before last you checked out).
git checkout -
This is in the same vein as cd -
in bash / zsh.
git checkout master
git checkout featureX
git checkout -
# You are now on the master branch
Here is how to create a local branch named my_branch
out of the remote one origin/my_branch
, configure it to track the remote, then jumps on the local branch.
Things are different depending on the version of git you are using.
- When using git version <
1.6.6
(Option 1)
git fetch
git checkout -b my_branch --track origin/my_branch
- When using git version >=
1.6.6
(Option 2)
If there is single remote with a branch named my_branch
:
git fetch
git checkout my_branch
Branch my_branch set up to track remote branch my_branch from origin.
Switched to a new branch 'my_branch'
If there are multiple remotes with a branch named my_branch
, git cannot guess the one you are talking about.
In this case, it will probably checkout the last commit of the remote branch my_branch
and won't create a local branch.
You will end-up in a detached HEAD state, ie on a specific commit instead of being on a newly created local branch.
Here is a 2 step fix, to leave the detached HEAD state and create the local branch.
First-off jump on another branch like master
for instance.
Then remove the ambiguity and specify the name of the local and remote branch so that git knows exactly where to check out the branch from and where to create it.
git checkout master`
git checkout -b my_branch --track origin/my_branch
When a remote branch that you previously pulled off, has been removed from the remote repository (say origin
in this example), your local remote cache contains a stale reference to a branch that no longer exists on the remote.
The branches patch-2
and 1.1.2
are stale because they no longer exist on the remote origin
.
git remote show origin
* remote origin
Fetch URL: git://github.com/ebouchut/rickshaw_rails.git
Push URL: git://github.com/ebouchut/rickshaw_rails.git
HEAD branch: master
Remote branches:
master tracked
patch-1 tracked
refs/remotes/origin/1.1.2 stale (use 'git remote prune' to remove)
refs/remotes/origin/patch-2 stale (use 'git remote prune' to remove)
typo-fix tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
To clean things up and remove all (local) stale branches for the remote origin
, use this:
git remote prune origin
You can also kill 2 birds with one stone, asking git to prune stale branches while fetching from a remote.
fetch -p origin
To rename the local branch old
to new
, proceed as follows:
git branch -m old new
Say you want to rename the branch old
to new
.
This branch also exists on the remote repository named origin
.
- Rename the local branch (old ➞ new)
git branch -m old new
- Delete the remote branch (old)
git push origin :old # if git version < 1.7.0
git push origin --delete old # if git version >= 1.7.0
No need to say that as this branch is public, this may cause problem if someone has cloned the repository and is working on this branch. Coordinate in advance with users working with this branch to reduce the impact"
- Push the renamed branch (new)
git push -u origin new
git checkout master
# Rename master to main
git branch -m master main
# Push main to origin/master
git push origin HEAD:master
# Push main to origin/main
git push origin HEAD
# Update all of your CI pipelines referencing master
# Rename the **default** branch main here:
# https://github.com/YOU/YOUR_PROJECT/settings/branches
# Remove the local branch master
git checkout main
git branch -D master
# Unset the removed upstream branch origin/master
git branch --unset-upstream
# Set the new upstream branch as origin/main
git push --set-upstream origin main
# Delete origin/master
git push origin --delete master
Sometimes you forgot to create a branch, and decide later on to create it after the fact.
-
First thing is to spot the commit you want to create the branch from and use its SHA-1 (say
a123456
for the sake of example) in the command below. -
Then create the branch
git branch my-branch
- And restore the state of the working directory and the staging area as of commit
a123456
(where you want the branchmy-branch
to start from)
git reset --hard a123456
Say I want to rebase the branch master
onto my_branch
.
# Jump on the (destination) branch you want to rebase onto
git checkout my_branch
# rebase the source branch (master) onto the current branch (my_branch)
git rebase master
There is another variant to do the same thing that works whatever the current branch.
git rebase --onto=my_branch master
Sources:
- Atlassian Rewriting History
- Pro-Git
- Visual demonstration of what a git rebase does (click git rebase)
When doing an interactive rebase of a feature branch you usually count how many commits before HEAD
where to start the interactive rebase.
For instance assuming you need to perform an interactive on the 4 most recent commits, you will do this:
git rebase -i HEAD~5 # interactive rebase on ] HEAD~4, HEAD]
This will rebase starting from commit HEAD~5
not included (ie. HEAD~4
) up to and including HEAD
.
Instead of counting each and every time the commits on which to perform an interactive rebase you can use instead this trick which always works whatever the number of commits.
If you are using the Git Flow workflow then your feature branch branched of the develop
branch
# Assuming, I'm on the feature "feature/XXX" (branched off develop like all git flow feature branches are)
git rebase -i develop
If you are using the Github flow instead, ie. you are on the feature branch named say XXX
branched off master:
# Assuming I'm on the feature "XXX" (branched off master)
git rebase -i master
Say you are on master
and merge in the feature branch my_branch
, like so:
git checkout master
git merge --no-ff my_branch
The commit at the tip of the master branch is a merge commit saying "Merge branch my_branch into master".
You now want to push your changes upstream (ie. push master up to origin/master).
But origin/master
has moved since the last time you pulled it off.
To be able to push, you first need to pull origin/master
.
But, if you do git pull --rebase
, you will notice the merge commit(s) gets removed.
This default behaviour is a bit annoying at first, here is the workaround to keep the merge commits.
Instead of git pull --rebase
you need to do this 2 steps process:
- fetch (origin/master)
- rebase master (against origin/master) using the magic incantation
-p
asking git to preserve the merge commit(s)
# git checkout master
git fetch
git rebase -p origin/master
As far as I know, there is no shorter way to do this.
Here is how to make the existing local branch my_branch
to track the remote branch origin/my_branch
,
depending on the version of git you are using:
- git version >= 1.8
# This is the shorter form
git branch -u origin/my_branch my_branch
# or the longer and more verbose form (which does the same thing)
git branch --set-upstream-to=origin/my_branch my_branch
- git version >= 1.7.0
git branch --set-upstream my_branch origin/my_branch
git branch -lvv # "lvv" as in list verbose verbose
* my_branch 479916b [origin/my_branch] Fix typo
master 6209803
The branch my_branch
is configured to track origin/my_branch
.
Assuming you no longer want to track the branch my_branch
from the remote origin
.
Here is how to do this depending on the version of git you are using.
# git version < 1.8
git config --unset branch.my_branch.remote
git config --unset branch.my_branch.merge
# git version >= 1.8
git branch --unset-upstream my_branch
You may also want to remove your local cache of the remote branch.
This does not delete my_branch
on the remote origin
.
git branch -d -r origin/my_branch
List the local branches that have been merged into origin/master
.
git branch --merged origin/master
List the remote branches that have been merged into origin/master
.
git branch -r --merged origin/master
List the local branches that have not been merged into origin/master
.
git branch --no-merged origin/master
List the remote branches that have not been merged into origin/master
.
git branch -r --no-merged origin/master
When you want to compare branches from different github repositories none of the repository being a fork of the other. I did not manage to find a way to do this using Github's UI. I needed to go back to git's CLI to do this and here is my recipe.
Say I need to compare the differences between branch branch1
from user1/repo1
and branch2
from user2/repo2
.
# Clone the user1/repo1 (assuming we have write permission on this one)
git clone [email protected]:user1/repo1.git
cd repo1
# Add a remote named repo2 pointing to user2/repo2
git remote add user2 https://github.com/user2/repo2.git
# Populate user2 the the local cache of the remote repository user2/repo2
git fetch user2
# Compare branches now.
# Changes in branch2 that are not in branch1
git log --oneline --decorate --graph origin/branch1..user2/branch2
# Changes in branch1 that are not in branch2
git log --oneline --decorate --graph origin/branch2..user2/branch1
You may end up with this error after attempting to create a local from a remote branch.
However if you use the wrong syntax, git branch origin/my_branch
instead of git branch my_branch origin/my_branch
.
# We intend to create a local branch "my_branch" out of the remote "origin/my_branch"
# But... we use the wrong syntax
git branch origin/my_branch
We end up with a local branch named origin/my_branch
.
From now on each time you interact with the remote (git push
, git pull
) you will see this error.
Git finds a local branch named origin/my_branch
which is an ambiguous name reference because of the remote branch with the same name origin/my_branch
.
I found 2 ways to find to spot the problem:
- branch -lvv
- git show-ref
git branch -lvv # Output: branch_name SHA-1 [tracked_remote_branch] latest_commit_message
* master bf3d207 [origin/master] Add postgres support
origin/my_branch abc1234 Fix Bug #12345
You can see the misnamed local branch origin/my_branch
does not track a remote branch (because there is no remote branch name in between square brackets).
You can also list all the references that contains origin/my_branch
.
git show-ref origin/my_branch
abc123493885415d89d70dcad55e561ccd0df417 commit refs/heads/origin/my_branch
aab15e599727918323b7fd7604df536cae316b2c commit refs/remotes/origin/my_branch
References of a:
-
local branch starts with
refs/heads/
-
remote branch (from the remote
origin
) starts withrefs/remotes/origin
Most of the time we do not use the full ref name of a branch refs/heads/master
but its shorter form master
.
This works as long as there is no ambiguity!
The shortcut origin/my_branch
is ambiguous here because it can refer to 2 full ref names:
refs/heads/origin/my_branch
-
refs/remotes/origin/my_branch
.
Using the full ref name of the branch like refs/remotes/origin/my_branch
is possible to remove ambiguity but is not a long term solution.
I see two options:
- You do not have modifications on this local branch:
In this case, remove it and recreate the branch this time using the correct syntax, like so:
git checkout master
git branch -D origin/my_branch
git branch my_branch origin/my_branch
- You have commits on the branch that are not yet pushed to
origin
In this case, rename the branch using its non ambiguous full name (the long ref name: refs/heads/origin/my_branch
)
git branch -m refs/heads/origin/my_branch my_branch
Sometimes you need to check what a merge would do without really doing it.
As git merge
does not provide the usual --dry-run
option, here is an alternative.
git merge --no-commit --no-ff my_branch
# Now, check things are as expected
git diff --cached
# Abort the merge
git merge --abort
This trick allows you to merge a branch you are not on, so that you do not need to jump on the branch you want to merge.
Say for instance:
- you are on a feature branch (
featureX
), you do not want to checkout any other branch - and you want to merge another branch,
origin/master
ontomaster
but without doing the usualgit checkout master
beforehand.
There are 2 possible options depending on whether merging origin/master
onto master
requires a fast forward merge or not.
- Fast Forward Merge
# When not on the master branch
git fetch origin master:master
- Non Fast Forward Merge
# When not on the master branch
git fetch origin +master:master
Note the plus sign (+
) before the remote branch name
To remove files -f
and directories -d
git does not track:
git clean -d -f
You can also use the -n
to let git make a dry-run where it says what it will remove without doing it.
git clean -d -f -n
First off, make sure you do successfully set aside your stuff in the current working directory using stash for instance. To do the equivalent of a force pull for the current branch which AFAIK does not exist. This will first-off clear the working directory and the cache/index then move the branch pointer to its remote counter part.
git fetch
git checkout my_branch
# Assuming you are on the branch my_branch
git reset --hard origin/my_branch
Here is how to show the content of the file CHANGELOG.md
on the branch origin/master
.
git show origin/master:CHANGELOG.md
Please do note:
- there is a colon (
:
) in between the branch name and the file path - the file path must be relative to the project's root directory
For instance to view the content of the file src/main/resources/config.properties
on the develop
branch:
git show develop:src/main/resources/config.properties
Here is how to test if a branch is up to date with its remote counterpart in a shell script.
Here we use bash
to test if develop
is up to date with origin/develop
.
The trick is to retrieve and compare the SHA1 of the tip of both the local and remote develop
branches.
If the SHA1s are different then the branch is not up to date.
git fetch
if [ $(git rev-parse develop) != $(git rev-parse develop@{u}) ]; then
# Branch develop is not up to date with origin.
fi
The shorthand reference develop@{u}
denotes the develop
branch on the upstream repository.
If develop
has been checked out from origin
, then this is equivalent to origin/develop
.
The command git flow release start
does not check if a remote release branch already exists before creating a local one. It only checks if one exists locally which is a pity!
Because of this you may end up with more than one release branch and this something that I want to avoid as it may prove very difficult to handle.
ℹ️Here comes git to the rescue with a handy git alias to list (local and remote) git flow release branch(es) not finished yet (ie. the ones not yet merged into master
).
git config --global alias.releases '!git fetch ; git branch -a --no-merged origin/master | grep "$(git config --local --get gitflow.prefix.release)" # List git flow releases not finished yet'
Once created, I can use the releases
git alias to see if there is a release branch underway so that I do not create a new one as long as the existing release branch is not finished, like so:
git releases
remotes/origin/release/1.10.0
In this example release 1.10.0
exists on origin
and is not finished.
I therefore now know that I must not create a new release up until this one is finished.
The command git flow hotfix start
does not check if a remote release branch already exists before creating a local one.
Because of this you may end up with more than one hotfix branches.
ℹ️Here comes git to the rescue with a handy git alias to list (local and remote) git flow hotfix branch(es) not finished yet (ie. the ones not yet merged into master
).
git config --global alias.hotfixes '!git fetch ; git branch -a --no-merged origin/master | grep "$(git config --local --get gitflow.prefix.hotfix)" # List git flow hotfixes not finished yet'
Once created, I can use the hotfixes
git alias to see if there is a hotfix branch underway so that I do not create a new one as long as the existing one not finished, like so:
git hotfixes
remotes/origin/hotfix/1.10.1
In this example hotfix 1.10.1
exists on origin
and is not finished.
Now I know that I must not create a new hotfix up until this one is finished.