Git branch: Difference between revisions
No edit summary |
|||
(104 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* [[Git Commands#Branch_Operations|Git Commands]] | * [[Git Commands#Branch_Operations|Git Commands]] | ||
* [[Git_Concepts#Branch|Git Concepts]] | |||
=Overview= | =Overview= | ||
[[#Overview|git branch]] is used to perform branch-related operations: listing existing branches, creating new local and remote branches, renaming branches, deleting branches. | [[#Overview|git branch]] is used to perform branch-related operations: [[#List_Existing_Branches|listing existing branches]], creating new local and remote branches, renaming branches and deleting branches. | ||
Use [[git checkout]] to check out the content of a branch in the local work area. | |||
For a description of the concepts behind Git branches, see: {{Internal|Git_Concepts#Branch|Git Concepts - Branches}} | |||
=List Existing Branches= | |||
The [[Git_Concepts#Local_.28Topic.29_Branch|local (topic) branches]] in the repository are displayed by executing [[#Overview|git branch]] without any argument, or with the default --list argument: | |||
git branch [--list] | |||
The output of the command reflects the content of the .git/refs/heads/ directory. | |||
The [[Git_Concepts#Tracking_Branch|tracking branches]] are displayed by executing: | |||
git branch -r | |||
The output of the command reflects the content of the .git/refs/remotes/<''remote-name''> directories. | |||
To display both local and tracking branches, use: | |||
git branch -a | |||
=List the Currently Checked Out Branch= | |||
List the currently checked out branch in the current work tree: | |||
[[Git_rev-parse#Currently_Checked_Out_Branch|git rev-parse --abbrev-ref HEAD]] | |||
=Branch Details= | |||
[[git show-branch]] | |||
=<span id='Check_out_a_Branch'></span>Check Out a Branch= | |||
[[Git_checkout#Check_Out_the_HEAD_of_a_Branch|git checkout]] <''local-branch-name''> | |||
=Create and Check Out a New Branch in One Operation= | |||
This creates a new branch rooted in the HEAD of the current branch and also checks out that branch, making it current: | |||
[[Git_checkout#Create_and_Check_Out_a_New_Branch_in_One_Operation|git checkout]] -b <''new-local-branch-name''> | |||
=Create a New Local Branch= | |||
A new [[Git_Concepts#Local_.28Topic.29_Branch|local branch]] can be created with | |||
git branch <''new-branch-name''> | |||
This creates a new local topic branch ''new-branch-name'' rooted in the HEAD of the current branch, so the default behavior is to create a branch right at the point where you're working right now. An alternate starting commit can be provided by specifying the commit hash. | |||
git branch <''new-branch-name''> [''starting-commit''] | |||
Immediately after creation, the branch exists just as a name in the local repository. It does not change the working directory to ''use'' the new branch. From an implementation point of view, the only effect is that a new refs/heads/<new-branch-name>> ref appears. If you want to use the newly created branch, you need to check it out (switch to it) with [[Git_checkout#Check_Out_the_HEAD_of_a_Branch|git checkout]] or [[git switch]]. | |||
The newly created branch is not shared by default with any remote repository. | |||
==What Happens if There Are Work Tree Changes at the Time of New Branch Creation?== | |||
If you start modifying local files and then decide to create a new branch for those modifications, you can simply go ahead and create the branch, check out the new branch and commit the changes on the new branch - the changes will be transferred to the new branch without any complications. | |||
==Create a New Local Branch at a Specific Commit== | |||
git checkout <branch-that-contains-the-commit> | |||
git branch <new-branch-name-which-should-probably-include-a-sha-fragment> <commit-sha> | |||
git checkout <new-branch-name-which-should-probably-include-a-sha-fragment> | |||
=Publish a Local Branch in a Remote Repository= | |||
{{Note|This sections was written with the assumption that the value of 'push.default' is "simple". This is the recommended value, which leads to a more deterministic behavior. For more details see <code>[[Git_Configuration#push.default|push.default]]</code>.}} | |||
==Create the Remote Branch and its Local Remote-Tracking Branch== | |||
We assume that at this stage, a new [[Git_Concepts#Local_.28Topic.29_Branch|local branch]] exists, created with the procedure described in [[#Create_a_New_Local_Branch|Create a New Local Branch]]. | |||
To create a corresponding [[Git_Concepts#Remote_Branch|remote branch]], with the same name, and its [[Git_Concepts#Tracking_Branch|local remote-tracking branch]], execute: | |||
git push <''remote-name''> <''local-branch-name''> | |||
Example: | |||
git push origin reference-implementation | |||
In the above example, <''local-branch-name''> is a degenerate form of ''+source:destination'' [[Git_Concepts#Refspec|refspec]] where only the source [[Git_Concepts#Ref|ref]] is specified. | |||
Note that you don't have to be on the branch being pushed while executing the command. | |||
The effect of the command is the creation of a local branch with the specified name (<''local-branch-name''>) in the remote repository indicated by <''remote-name''>, the transfer of the refs and objects corresponding to the local branch into the remote repository and the creation of a local tracking-branch, as reflected in the content of the .git/refs/remotes/<''remote-name''>: a new file with the same name as the local branch appears. The tracking branch is ''implicitly created''. | |||
At this stage, the newly published branch can be tracked: if somebody else clones the upstream repository and updates the newly published branch back in the repository, we're going to get the updates on the tracking branch by running [[git fetch]], which will synchronize the local tracking-branch state with the state of the remote branch, in the remote -> local direction. | |||
git checkout <''local-branch-name''> | |||
git fetch | |||
However, [[git fetch]] will only update the local tracking branch. [[git pull]] won't work because even if the tracking branch exists, we did not create yet a link between the local topic branch and the tracking branch so we can merge updates back into the local branch. | |||
git pull | |||
There is no tracking information for the current branch. | |||
Please specify which branch you want to '''merge''' with. | |||
... | |||
[[git push]] does not work, so the state of the local branch cannot be automatically pushed to the remote repository. | |||
git push | |||
fatal: The current branch reference-implementation has no upstream branch. | |||
This behavior is a consequence of the <code>[[Git_Configuration#push.default|push.default=simple]]</code> setting. | |||
The local branch can be linked to the tracking branch as [[#Link_the_Local_Branch_its_Tracking_Branch|follows]]. | |||
===Different Remote Branch Name=== | |||
If you want to create a remote branch with a name that differs from the name of the local branch, use the more generic syntax: | |||
git push <''remote-name''> <''refspec''> | |||
Example: | |||
git push origin A:B | |||
This will create a remote branch "B" with the content of our local "A" branch and as a side effect a local tracking branch refs/remotes/origin/B. | |||
==Link the Local Branch to its Tracking Branch== | |||
The local branch can be linked to its remote-tracking branch, so both [[git pull]] and [[git push]] work, as follows: | |||
git branch --set-upstream-to=<''remote-name''>/<''remote-branch-name''> [''local-branch-name''] | |||
If already on the local branch, specifying local-branch-name is optional. | |||
Example: | |||
git branch --set-upstream-to=origin/reference-implementation reference-implementation | |||
Branch reference-implementation set up to track remote branch reference-implementation from origin. | |||
Note that you don't have to be on the branch being pushed while executing the command. | |||
The effect of the command is new configuration in [[.git/config#.5Bbranch.5D|.git/config]]: | |||
<syntaxhighlight lang='yaml'> | |||
... | |||
[branch "reference-implementation"] | |||
remote = origin | |||
merge = refs/heads/reference-implementation | |||
</syntaxhighlight> | |||
==Push an Link in the Same Operations== | |||
This is the compressed version: | |||
git push --set-upstream origin <''local-branch-name''> | |||
==Access the Branch form a Different Repository== | |||
Now that the branch was published in the upstream repository, any of its downstream repositories can see and interact with it. From a second repository, you can learn the branch exists by running: | |||
git fetch <remote-name> | |||
This will fetch updates, among them the new branch information, and it will create the tracking branch .git/refs/remotes/origin/<''branch-name''>. Then the branch can be displayed with: | |||
git branch -r | |||
To checkout the new branch: | |||
git checkout <''remote-branch-name''> | |||
This will create the local topic branch with the same name ''and'' will setup the link between the local branch and the local tracking branch by adding to [[.git/config]] a section similar to: | |||
<syntaxhighlight lang='yaml'> | |||
[branch "dev"] | |||
remote = origin | |||
merge = refs/heads/dev | |||
</syntaxhighlight> | |||
Now you can fully interact with the branch from the second repository too, with no-argument [[git push]] and [[git pull]]. | |||
=Rename a Branch= | |||
==Rename the Local Branch== | |||
If the branch exists only in the local repository - does not track a remote branch - then the branch can be simply renamed with the command specified below, without taking any other precautions. However, if the branch was published in a remote repository and you want that branch to be renamed as well, see [[#Rename_Both_the_Local_Branch_and_the_Remote_Branch|Rename Both the Local Branch and the Remote Branch]]. | |||
Use -m (or -M to force the move if the new branch name already exists): | |||
git branch -m <''old-branch-name''> <''new-branch-name''> | |||
==Rename Both the Local Branch and the Remote Branch== | |||
To rename a remote branch, first make sure that other developers do not rely on it. If they do, the renaming must be coordinated with them. Assuming that this aspect has been taken care of, the renaming sequence consists in synchronizing the local branch with the remote one, severing the upstream relationship and renaming the local branch, deleting the remote branch, and pushing the renamed branch into the remote repository, while recreating the upstream relationship. | |||
===Sever the Upstream Relationship of the Local Branch=== | |||
git branch --unset-upstream <''branch-to-be-renamed''> | |||
git branch --unset-upstream task/unfashionable | |||
===Rename Locally=== | |||
Follow the procedure described in [[#Rename_the_Local_Branch|Rename the Local Branch]] section, above. | |||
git branch -m <''old-branch-name''> <''new-branch-name''> | |||
This will update both the local branch name and add a new tracking branch (and update the corresponding .git/config configuration). It leaves the old tracking branch in place. | |||
git branch -m task/unfashionable task/interesting | |||
===Rename Remote=== | |||
Start by deleting the remote branch, as described in [[#Delete_the_Remote_Branch|Delete the Remote Branch]]. Essentially is: | |||
git push <''remote-name''> :<''old-name''> | |||
git push origin :task/unfashionable | |||
At this point, your remote branch is gone. | |||
===Re-Publish and Re-Link the New Branch=== | |||
git push --set-upstream <''remote-name''> <''branch-new-name''> | |||
git push --set-upstream origin task/interesting | |||
===Notify Other Developers=== | |||
At this point, other developers that were tracking the old branch are left stranded, because an attempt to pull. | |||
git pull | |||
... | |||
Your configuration specifies to merge with the ref 'fax' | |||
from the remote, but no such ref was fetched. | |||
Even more troublesome, an attempt to push recreates the old branch, so you need to tell them to delete the old branch locally, and get the new one: | |||
git branch -d <''old-branch-name''> | |||
git fetch <''remote-name''> | |||
git checkout <''new-branch-name''> | |||
=Delete a Branch= | |||
==Delete the Local Branch== | |||
Git does not maintain any form of historical record of branch names being created, removed, manipulated, merged or deleted. Once a branch name has been removed, it is gone. | |||
To delete a local branch: | |||
git branch -d <''local-branch-name''> | |||
Example: | |||
git branch -d reference-implementation | |||
Deleted branch reference-implementation (was 6ac4990). | |||
Note that the user cannot delete a branch currently checked out. A user cannot delete a branch that contains commits that are not present on the current branch. In that case, the message is: | |||
error: The branch 'ofeodorov/16167943' is not fully merged. | |||
If you are sure you want to delete it, run 'git branch -D ofeodorov/16167943'. | |||
This safety measure can be overridden with -D (instead of -d). | |||
==Delete the Remote Branch== | |||
The remote branch can be removed by using the following syntax: | |||
git push <''remote-name''> :<''old-branch-name''> | |||
Example: | |||
git push origin :reference-implementation | |||
To https://ofeodoro@github.com:example/api.git | |||
- [deleted] reference-implementation | |||
In the above generic example <''old-branch-name''> is a degenerate form of the ''+source:destination'' refspec where only the destination ref (no source ref) is specified. | |||
Remotely, this removes the old branch ref - but does not delete anything else (objects such as commits, etc.). | |||
Locally, this removes the old tracking branch from refs/remotes/''remote-name'' directory. Trying to use the new branch locally at this point gives a warning: | |||
Your branch is based on 'origin/<old-name>', but the upstream is gone. | |||
It does not remove the link between the local branch and the local tracking branch from [[.git/config#.5Bbranch.5D|.git/config]]. | |||
==Prune Remote Branches== | |||
Remote tracking branches may accumulate under <code>.git/refs/remotes/<remote-name></code> even the corresponding branches have been deleted locally and remotely. To clean up those hanging references run: | |||
<syntaxhighlight lang='text'> | |||
git remote prune <remote-name> | |||
</syntaxhighlight> | |||
<syntaxhighlight lang='text'> | |||
git remote prune origin | |||
</syntaxhighlight> | |||
Also see: {{Internal|Git_remote#prune|<tt>git remote prune</tt>}} | |||
=Options= | |||
==--unset-upstream== | |||
git branch --unset-upstream <''branch-to-be-renamed''|''branch-to-be-deleted''> | |||
=Getting the Current Branch= | |||
{{Internal|Getting the Current Git Branch|Getting the Current Git Branch}} | |||
=Find Branches a Given Commit Belongs To= | |||
<syntaxhighlight lang='bash'> | |||
git branch --contains <commit-id> | |||
</syntaxhighlight> | |||
The command list all branches the given commit belongs to (it is among the ancestors of the branch heads), if any. | |||
=Find whether a Given Commit Belongs to a Specific Branch= | |||
<syntaxhighlight lang='bash'> | |||
git branch <branch-name> --contains <commit-id> | |||
</syntaxhighlight> | |||
If exists: | |||
<syntaxhighlight lang='bash'> | |||
git branch develop --contains ce1659602216895aa88a935203aafac3817deb78 | |||
+ develop | |||
</syntaxhighlight> | |||
If it does not exist: | |||
<syntaxhighlight lang='bash'> | |||
git branch feature/A --contains ce1659602216895aa88a935203aafac3817deb78 | |||
</syntaxhighlight> | |||
returns empty string. |
Latest revision as of 22:30, 9 January 2024
Internal
Overview
git branch is used to perform branch-related operations: listing existing branches, creating new local and remote branches, renaming branches and deleting branches.
Use git checkout to check out the content of a branch in the local work area.
For a description of the concepts behind Git branches, see:
List Existing Branches
The local (topic) branches in the repository are displayed by executing git branch without any argument, or with the default --list argument:
git branch [--list]
The output of the command reflects the content of the .git/refs/heads/ directory.
The tracking branches are displayed by executing:
git branch -r
The output of the command reflects the content of the .git/refs/remotes/<remote-name> directories.
To display both local and tracking branches, use:
git branch -a
List the Currently Checked Out Branch
List the currently checked out branch in the current work tree:
git rev-parse --abbrev-ref HEAD
Branch Details
git show-branch
Check Out a Branch
git checkout <local-branch-name>
Create and Check Out a New Branch in One Operation
This creates a new branch rooted in the HEAD of the current branch and also checks out that branch, making it current:
git checkout -b <new-local-branch-name>
Create a New Local Branch
A new local branch can be created with
git branch <new-branch-name>
This creates a new local topic branch new-branch-name rooted in the HEAD of the current branch, so the default behavior is to create a branch right at the point where you're working right now. An alternate starting commit can be provided by specifying the commit hash.
git branch <new-branch-name> [starting-commit]
Immediately after creation, the branch exists just as a name in the local repository. It does not change the working directory to use the new branch. From an implementation point of view, the only effect is that a new refs/heads/<new-branch-name>> ref appears. If you want to use the newly created branch, you need to check it out (switch to it) with git checkout or git switch.
The newly created branch is not shared by default with any remote repository.
What Happens if There Are Work Tree Changes at the Time of New Branch Creation?
If you start modifying local files and then decide to create a new branch for those modifications, you can simply go ahead and create the branch, check out the new branch and commit the changes on the new branch - the changes will be transferred to the new branch without any complications.
Create a New Local Branch at a Specific Commit
git checkout <branch-that-contains-the-commit> git branch <new-branch-name-which-should-probably-include-a-sha-fragment> <commit-sha> git checkout <new-branch-name-which-should-probably-include-a-sha-fragment>
Publish a Local Branch in a Remote Repository
This sections was written with the assumption that the value of 'push.default' is "simple". This is the recommended value, which leads to a more deterministic behavior. For more details seepush.default
.
Create the Remote Branch and its Local Remote-Tracking Branch
We assume that at this stage, a new local branch exists, created with the procedure described in Create a New Local Branch.
To create a corresponding remote branch, with the same name, and its local remote-tracking branch, execute:
git push <remote-name> <local-branch-name>
Example:
git push origin reference-implementation
In the above example, <local-branch-name> is a degenerate form of +source:destination refspec where only the source ref is specified.
Note that you don't have to be on the branch being pushed while executing the command.
The effect of the command is the creation of a local branch with the specified name (<local-branch-name>) in the remote repository indicated by <remote-name>, the transfer of the refs and objects corresponding to the local branch into the remote repository and the creation of a local tracking-branch, as reflected in the content of the .git/refs/remotes/<remote-name>: a new file with the same name as the local branch appears. The tracking branch is implicitly created.
At this stage, the newly published branch can be tracked: if somebody else clones the upstream repository and updates the newly published branch back in the repository, we're going to get the updates on the tracking branch by running git fetch, which will synchronize the local tracking-branch state with the state of the remote branch, in the remote -> local direction.
git checkout <local-branch-name> git fetch
However, git fetch will only update the local tracking branch. git pull won't work because even if the tracking branch exists, we did not create yet a link between the local topic branch and the tracking branch so we can merge updates back into the local branch.
git pull There is no tracking information for the current branch. Please specify which branch you want to merge with. ...
git push does not work, so the state of the local branch cannot be automatically pushed to the remote repository.
git push fatal: The current branch reference-implementation has no upstream branch.
This behavior is a consequence of the push.default=simple
setting.
The local branch can be linked to the tracking branch as follows.
Different Remote Branch Name
If you want to create a remote branch with a name that differs from the name of the local branch, use the more generic syntax:
git push <remote-name> <refspec>
Example:
git push origin A:B
This will create a remote branch "B" with the content of our local "A" branch and as a side effect a local tracking branch refs/remotes/origin/B.
Link the Local Branch to its Tracking Branch
The local branch can be linked to its remote-tracking branch, so both git pull and git push work, as follows:
git branch --set-upstream-to=<remote-name>/<remote-branch-name> [local-branch-name]
If already on the local branch, specifying local-branch-name is optional.
Example:
git branch --set-upstream-to=origin/reference-implementation reference-implementation Branch reference-implementation set up to track remote branch reference-implementation from origin.
Note that you don't have to be on the branch being pushed while executing the command.
The effect of the command is new configuration in .git/config:
...
[branch "reference-implementation"]
remote = origin
merge = refs/heads/reference-implementation
Push an Link in the Same Operations
This is the compressed version:
git push --set-upstream origin <local-branch-name>
Access the Branch form a Different Repository
Now that the branch was published in the upstream repository, any of its downstream repositories can see and interact with it. From a second repository, you can learn the branch exists by running:
git fetch <remote-name>
This will fetch updates, among them the new branch information, and it will create the tracking branch .git/refs/remotes/origin/<branch-name>. Then the branch can be displayed with:
git branch -r
To checkout the new branch:
git checkout <remote-branch-name>
This will create the local topic branch with the same name and will setup the link between the local branch and the local tracking branch by adding to .git/config a section similar to:
[branch "dev"]
remote = origin
merge = refs/heads/dev
Now you can fully interact with the branch from the second repository too, with no-argument git push and git pull.
Rename a Branch
Rename the Local Branch
If the branch exists only in the local repository - does not track a remote branch - then the branch can be simply renamed with the command specified below, without taking any other precautions. However, if the branch was published in a remote repository and you want that branch to be renamed as well, see Rename Both the Local Branch and the Remote Branch.
Use -m (or -M to force the move if the new branch name already exists):
git branch -m <old-branch-name> <new-branch-name>
Rename Both the Local Branch and the Remote Branch
To rename a remote branch, first make sure that other developers do not rely on it. If they do, the renaming must be coordinated with them. Assuming that this aspect has been taken care of, the renaming sequence consists in synchronizing the local branch with the remote one, severing the upstream relationship and renaming the local branch, deleting the remote branch, and pushing the renamed branch into the remote repository, while recreating the upstream relationship.
Sever the Upstream Relationship of the Local Branch
git branch --unset-upstream <branch-to-be-renamed>
git branch --unset-upstream task/unfashionable
Rename Locally
Follow the procedure described in Rename the Local Branch section, above.
git branch -m <old-branch-name> <new-branch-name>
This will update both the local branch name and add a new tracking branch (and update the corresponding .git/config configuration). It leaves the old tracking branch in place.
git branch -m task/unfashionable task/interesting
Rename Remote
Start by deleting the remote branch, as described in Delete the Remote Branch. Essentially is:
git push <remote-name> :<old-name>
git push origin :task/unfashionable
At this point, your remote branch is gone.
Re-Publish and Re-Link the New Branch
git push --set-upstream <remote-name> <branch-new-name>
git push --set-upstream origin task/interesting
Notify Other Developers
At this point, other developers that were tracking the old branch are left stranded, because an attempt to pull.
git pull ... Your configuration specifies to merge with the ref 'fax' from the remote, but no such ref was fetched.
Even more troublesome, an attempt to push recreates the old branch, so you need to tell them to delete the old branch locally, and get the new one:
git branch -d <old-branch-name> git fetch <remote-name> git checkout <new-branch-name>
Delete a Branch
Delete the Local Branch
Git does not maintain any form of historical record of branch names being created, removed, manipulated, merged or deleted. Once a branch name has been removed, it is gone.
To delete a local branch:
git branch -d <local-branch-name>
Example:
git branch -d reference-implementation Deleted branch reference-implementation (was 6ac4990).
Note that the user cannot delete a branch currently checked out. A user cannot delete a branch that contains commits that are not present on the current branch. In that case, the message is:
error: The branch 'ofeodorov/16167943' is not fully merged. If you are sure you want to delete it, run 'git branch -D ofeodorov/16167943'.
This safety measure can be overridden with -D (instead of -d).
Delete the Remote Branch
The remote branch can be removed by using the following syntax:
git push <remote-name> :<old-branch-name>
Example:
git push origin :reference-implementation To https://ofeodoro@github.com:example/api.git - [deleted] reference-implementation
In the above generic example <old-branch-name> is a degenerate form of the +source:destination refspec where only the destination ref (no source ref) is specified.
Remotely, this removes the old branch ref - but does not delete anything else (objects such as commits, etc.).
Locally, this removes the old tracking branch from refs/remotes/remote-name directory. Trying to use the new branch locally at this point gives a warning:
Your branch is based on 'origin/<old-name>', but the upstream is gone.
It does not remove the link between the local branch and the local tracking branch from .git/config.
Prune Remote Branches
Remote tracking branches may accumulate under .git/refs/remotes/<remote-name>
even the corresponding branches have been deleted locally and remotely. To clean up those hanging references run:
git remote prune <remote-name>
git remote prune origin
Also see:
Options
--unset-upstream
git branch --unset-upstream <branch-to-be-renamed|branch-to-be-deleted>
Getting the Current Branch
Find Branches a Given Commit Belongs To
git branch --contains <commit-id>
The command list all branches the given commit belongs to (it is among the ancestors of the branch heads), if any.
Find whether a Given Commit Belongs to a Specific Branch
git branch <branch-name> --contains <commit-id>
If exists:
git branch develop --contains ce1659602216895aa88a935203aafac3817deb78
+ develop
If it does not exist:
git branch feature/A --contains ce1659602216895aa88a935203aafac3817deb78
returns empty string.