Top branch Questions

List of Tags
905
Pat Notz

I know how to make a new branch that tracks remote branches. But how do I make an existing branch track a remote branch. I know I can just edit the .git/config file, but it seems there should be an easier way.

It looks like this can't currently be done in a convenient way with the current (1.6.1.x) version of Git.

Git version >= 1.7.0 supports this. See the accepted answer.

Answered By: Dan Moulding ( 1162)

Given a branch foo and a remote upstream:

As of Git 1.8.0:

git branch -u upstream/foo

Or, if local branch foo is not the current branch:

git branch -u upstream/foo foo

Or, if you like to type longer commands, these are equivalent to the above two:

git branch --set-upstream-to=upstream/foo

git branch --set-upstream-to=upstream/foo foo

As of Git 1.7.0:

git branch --set-upstream foo upstream/foo

Notes:

All of the above commands will cause local branch foo to track remote branch foo from remote upstream. The old (1.7.x) syntax is deprecated in favor of the new (1.8+) syntax. The new syntax is intended to be more intuitive and easier to remember.


See also: Git: Why do I need to do `--set-upstream` all the time?

547
Jesper Rønn-Jensen

I created a local branch which I want to 'push' upstream. There is a similar question here on Stackoverflow on how to track a newly created remote branch.

However, my workflow is slightly different. FIRST I want to create a local branch. And I will only push it upstream when I'm satisfied and want to share my branch.

How would I do that? (my google searches did not seem to come up with anything)

And how would I tell my colleagues to pull it from the upstream repository?

Answered By: Ikke ( 629)

The branch is automatically created when you push it to the remote server. So when you feel for it, you can just do

git push <remote-name> <branch-name>

Your colleagues would then just pull that branch, and it's automatically created locally.

Note however that formally, the format is:

git push <remote-name> <local-branch-name>:<remote-branch-name>

But when you omit one, it assumes both names are the same.

From a comment below:

You might want to use git push -u <remote-name> <branch-name> instead, so that a subsequent git pull will know what to do.

Bart Schuller

The -u option sets-up a upstream branch:

For every branch that is up to date or successfully pushed, add upstream (tracking) reference, used by argument-less git-pull(1) and other commands.

522
grapefrukt

I've seen these words a lot around Subversion (and I guess general repository) discussions. I have been using SVN for my projects the last few years, but I've never grasped the complete concept of these directories.

What do they mean?

Answered By: Jon Limjap ( 407)

Hmm, not sure I agree with Nick re tag being similar to a branch. A tag is just a marker

  • Trunk would be the main body of development, originating from the start of the project until the present.

  • Branch will be a copy of code derived from a certain point in the trunk that is used for applying major changes to the code while preserving the integrity of the code in the trunk. If the major changes work according to plan, they are usually merged back into the trunk.

  • Tag will be a point in time on the trunk or a branch that you wish to preserve. The two main reasons for preservation would be that either this is a major release of the software, whether alpha, beta, RC or RTM, or this is the most stable point of the software before major revisions on the trunk were applied.

In open source projects, major branches that are not accepted into the trunk by the project stakeholders can become the bases for forks -- e.g., totally separate projects that share a common origin with other source code.

407
johannix

I want to merge two branches that have been separated for a while and wanted to know which files have been modified.

Came across this link: http://linux.yyz.us/git-howto.html which was quite useful.

The tools to compare branches I've come across are:

  • git diff master..branch
  • git log master..branch
  • git shortlog master..branch

Was wondering if there's something like "git status master..branch" to only see those files that are different between the two branches.

Without creating a new tool, I think this is the closest you can get to do that now (which of course will show repeats if a file was modified more than once):

  • git diff master..branch | grep "^diff"

Was wondering if there's something I missed...

Answered By: JasonSmith ( 492)

Try

$ git diff --name-status master..branch

That should do what you need, if I understand you correctly.

293
Nocturne

I use the following command to push to my remote branch:

git push origin sandbox

If I say

git push origin

Does that push changes in my other branches too, or does it only update my current branch? (I have three branches: master, production and sandbox).

(The git push documentation is not very clear about this, so I'd like to clarify this for good)

What branches/remotes do the following git push commands exactly update?

git push 
git push origin

("origin" above is a remote)

(I understand that "git push [remote] [branch]" will push only that branch to the remote)

Answered By: baudtack ( 138)

git push origin will push all changes on the local branches that have matching remote branches at origin As for git push

Works like git push <remote>, where <remote> is the current branch's remote (or origin, if no remote is configured for the current branch).

From the Examples section of the git-push man page

286
David Joyner

I'm using git on a new project that has two parallel -- but currently experimental -- development branches:

  • master: import of existing codebase plus a few mods that I'm generally sure of
  • exp1: experimental branch #1
  • exp2: experimental branch #2

exp1 and exp2 represent two very different architectural approaches. Until I get further along I have no way of knowing which one (if either) will work. As I make progress in one branch I sometimes have edits that would be useful in the other branch and would like to merge just those.

What is the best way to merge selective files from one development branch to another while leaving behind everything else?

Approaches I've considered:

  1. git merge --no-commit followed by manual unstaging of a large number of edits that I don't want to make common between the branches.

  2. Manual copying of common files into a temp directory followed by git checkout to move to the other branch and then more manual copying out of the temp directory into the working tree.

  3. A variation on the above. Abandon the exp branches for now and use two additional local repositories for experimentation. This makes the manual copying of files much more straightforward.

All three of these approaches seem tedious and error-prone. I'm hoping there is a better approach; something akin to a filter path parameter that would make git-merge more selective.

Answered By: 1800 INFORMATION ( 103)

You use the cherry-pick command to get individual commits from one branch.

If the change(s) you want are not in individual commits, then use the method shown here to split the commit into individual commits. Roughly speaking, you use git rebase -i to get the original commit to edit, then git reset HEAD^ to selectively revert changes, then git commit to commit that bit as a new commit in the history.

There is another nice method here in Red Hat Magazine, where they use git add --patch or possibly git add --interactive which allows you to add just parts of a hunk, if you want to split different changes to an individual file (search in that page for "split").

Having split the changes, you can now cherry-pick just the ones you want.

247
Florian Pilz

Coming from mercurial, I'm using branches to organize features. Naturally I want to see this work-flow in my history as well.

I started my new project using git and finished my first feature. While merging the feature I realized that git uses fast-forward, i.e. applies my changes directly to the master branch if possible and forgets about my branch.

So to think into the future: I'm the only one working on this project. If I use the default approach of git (fast-forward merging) my history would result in one giant master branch. Nobody knows that I used a separate branch for every feature, because in the end I only have that giant master branch. Doesn't that look unprofessional?

Due to this reasoning I don't want fast-forward merging as the default behaviour of git and can't see a good reason why it is the default. Maybe there are reasons, but what's so striking about it, that it has to be the default action?

Answered By: VonC ( 321)

Fast-forward merging makes sense for short-lived branches, but in a more complex history, non-fast-forward merging may make the history easier to understand, and make it easier to revert a group of commits.

alt text
(From nvie.com, Vincent Driessen, post "A successful Git branching model")

Incorporating a finished feature on develop

Finished features may be merged into the develop branch to add them to the upcoming release:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature.


The fast-forward is the default because:

  • short-lived branches are very easy to create and use in Git
  • short-lived branches often isolate many commits that can be reorganized freely within that branch
  • those commits are actually part of the main branch: once reorganized, the main branch is fast-forwarded to include them.

But if you anticipate an iterative workflow on one topic/feature branch (i.e., I merge, then I go back to this feature branch and add some more commits), then it is useful to include only the merge in the main branch, rather than all the intermediate commits of the feature branch.

In this case, you can end up setting this kind of config file:

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

The OP adds in the comments:

I see some sense in fast-forward for [short-lived] branches, but making it the default action means that git assumes you... often have [short-lived] branches. Reasonable?

Jefromi answers:

I think the lifetime of branches varies greatly from user to user. Among experienced users, though, there's probably a tendency to have far more short-lived branches.

To me, a short-lived branch is one that I create in order to make a certain operation easier (rebasing, likely, or quick patching and testing), and then immediately delete once I'm done.
That means it likely should be absorbed into the topic branch it forked from, and the topic branch will be merged as one branch. No one needs to know what I did internally in order to create the series of commits implementing that given feature.

More generally, I add:

it really depends on your development workflow:

  • if it is linear, one branch makes sense.
  • If you need to isolate features and work on them for a long period of time and repeatedly merge them, several branches make sense.

See "When should you branch?"

Actually, when you consider the Mercurial branch model, it is at its core one branch per repository (even though you can create anonymous heads, bookmarks and even named branches)
See "Git and Mercurial - Compare and Contrast".

Mercurial, by default, uses anonymous lightweight codelines, which in its terminology are called "heads".
Git uses lightweight named branches, with injective mapping to map names of branches in remote repository to names of remote-tracking branches.
Git "forces" you to name branches (well, with the exception of a single unnamed branch, which is a situation called a "detached HEAD"), but I think this works better with branch-heavy workflows such as topic branch workflow, meaning multiple branches in a single repository paradigm.

190
Casey

In my current repo I have the following output:

$ git branch -a
* master
  remotes/origin/master
  remotes/public/master

I want to delete 'remotes/public/master' from the branch list:

$ git branch -d remotes/public/master
error: branch 'remotes/public/master' not found.

Also, the output of 'git remote' is strange, since it does not list 'public':

$ git remote show 
origin

How can I delete 'remotes/public/master' from the branch list?

Update, tried the 'git push' command:

$ git push public :master
fatal: 'public' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

Solution: The accepted answer had the solution at the bottom!

git gc --prune=now
Answered By: Kent Fredric ( 184)

You might be needing a cleanup

git gc --prune=now

or you might be needing a prune

git remote prune public

   prune
       Deletes all stale tracking branches under <name>. These stale branches have already been removed from
       the remote repository referenced by <name>, but are still locally available in "remotes/<name>".

       With --dry-run option, report what branches will be pruned, but do no actually prune them.

However, it appears these should have been cleaned up earlier with

git remote rm public 

   rm
       Remove the remote named <name>. All remote tracking branches and configuration settings for the remote
       are removed.

So it might be you hand-edited your config file and this did not occur, or you have privilege problems.

Maybe run that again and see what happens.

Advice Context

If you take a look in the revision logs, you'll note I suggested more "correct" techniques, which for whatever reason didn't want to work on their repository.

I suspected the OP had done something that left their tree in an inconsistent state that caused it to behave a bit strangely, and git gc was required to fix up the left behind cruft.

Usually git branch -rd origin/badbranch is sufficient for nuking a local tracking branch , or git push origin :badbranch for nuking a remote branch, and usually you will never need to call git gc

177
jakopanda

Can someone help me understand the difference between a branch, a fork and a clone in Git?

Similarly what does it mean when I do a git fetch as opposed to a git pull.

Also what does rebase mean in comparison to merge ?

How can I squash individual commits themselves together?

How are they used, why are they used and what do they represent?

How does github figure in?

Answered By: siride ( 181)

A clone is simply a copy of a repository. On the surface, its result is equivalent to svn checkout, where you download source code from some other repository. The difference between centralized VCS like Subversion and DVCSs like Git is that in Git, when you clone, you are actually copying the entire source repository, including all the history and branches. You now have a new repository on your machine and any commits you make go into that repository. Nobody will see any changes until you push those commits to another repository (or the original one) or until someone pulls commits from your repository, if it is publicly accessible.

A branch is something that is within a repository. Conceptually, it represents a thread of development. You usually have a master branch, but you may also have a branch where you are working on some feature xyz, and another one to fix bug abc. When you have checked out a branch, any commits you make will stay on that branch and not be shared with other branches until you merge them with or rebase them onto the branch in question. Of course, Git seems a little weird when it comes to branches until you look at the underlying model of how branches are implemented. Rather than explain it myself (I've already said too much, methinks), I'll link to the "computer science" explanation of how Git models branches and commits, taken from the Git website:

http://eagain.net/articles/git-for-computer-scientists/

A fork isn't a Git concept really, it's more a political/social idea. That is, if some people aren't happy with the way a project is going, they can take the source code and work on it themselves separate from the original developers. That would be considered a fork. Git makes forking easy because everyone already has their own "master" copy of the source code, so it's as simple as cutting ties with the original project developers and doesn't require exporting history from a shared repository like you might have to do with SVN.

EDIT: since I was not aware of the modern definition of "fork" as used by sites such as GitHub, please take a look at the comments and also Michael Durrant's answer below mine for more information.

168
Frank

I'm kind of a git Noob and somehow I got my master and my origin/master branch to diverge. I actually don't want them to be diverged. How can I view these differences and 'merge' them?

Answered By: VonC ( 268)

You can review the differences with a:

git log HEAD..origin/master

before pulling it (fetch + merge) (see also "How do you get git to always pull from a specific branch?")


When you have a message like:

"Your branch and 'origin/master' have diverged, # and have 1 and 1 different commit(s) each, respectively."

, check if you need to update origin. If origin is up-to-date, then some commits have been pushed to origin from another repo while you made your own commits locally.

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \
                    C  master (your work)

You based commit C on commit A because that was the latest work you had fetched from upstream at the time.
However, before you tried to push back to origin someone else pushed commit B.
Development history has diverged into separate paths.

You can then merge or rebase. See this FAQ for instance:

Merge

Use the git merge command:

$ git merge origin/master

This tells Git to integrate the changes from origin/master into your work and create a merge commit.
The graph of history now looks like this:

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \      \
                    C ---- M  master (your work)

The new merge commit M has two parents, each representing one path of development that led to the content stored in the commit.

Note that the history behind M is now non-linear.
We have chosen (for now) to disallow non-linear history in cmake.org/cmake.git so an attempt to push M into our repository will fail.
Until this restriction is lifted, please rebase your work instead.

Rebase

Use the git rebase command:

$ git rebase origin/master

This tells Git to replay commit C (your work) as if you had based it on commit B instead of A.
CVS and Subversion users routinely rebase their local changes on top of upstream work when they update before commit.
Git just adds explicit separation between the commit and rebase steps.

The graph of history now looks like this:

... o ---- o ---- A ---- B  origin/master (upstream work)
                          \
                           C'  master (your work)

Commit C' is a new commit created by the git rebase command.
It is different from C in two ways:

  1. It has a different history: B instead of A.
  2. It's content accounts for changes in both B and C: it is the same as M from the merge example.

Note that the history behind C' is still linear.
We have chosen (for now) to allow only linear history in cmake.org/cmake.git.
This approach preserves the CVS-based workflow used previously and may ease the transition.
An attempt to push C' into our repository will work (assuming you have permissions and no one has pushed while you were rebasing).

The git pull command provides a shorthand way to fetch from origin and rebase local work on it:

$ git pull --rebase

This combines the above fetch and rebase steps into one command.