Git Course 0%

Publish, track, update from main

Intermediate Git CLI VS Code UI IntelliJ UI GitLab UI GitHub UI ≈ 12 min

What you will learn

  • What the first push of a branch does and why it needs -u
  • What a tracking branch buys you in status, pull and push
  • Two ways to bring main's newer commits into your branch, and when to use each

After this lesson you can

  • I can publish a branch so colleagues and the pipeline can see it
  • I can keep a branch current with main and know which method my team prefers

Why this matters

A branch on your computer is invisible: no colleague can review it, no pipeline can test it, and a broken laptop takes it with them. Publishing costs one command. The second half of this lesson solves the problem that follows: while you work, main moves on, and a branch that ignores that drift turns into a painful merge later.

Publishing a branch

The first push of a new branch needs to say where it goes. Without that, Git stops and tells you exactly what to type:

Terminal
$ git push
fatal: The current branch docs/12-windows-install-steps has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin docs/12-windows-install-steps

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

-u is the short form of --set-upstream. It pushes and links the two branches in one step:

Terminal
$ git push -u origin docs/12-windows-install-steps
To https://gitlab.com/northwind-trails/trailguide.git
 * [new branch]      docs/12-windows-install-steps -> docs/12-windows-install-steps
branch 'docs/12-windows-install-steps' set up to track 'origin/docs/12-windows-install-steps'.

Two things happened: a branch of that name now exists on the remote, and your local branch became a tracking branch. If you set push.autoSetupRemote true in lesson 3.5, a plain git push does all of this for you.

What tracking gives you

Local, remote-tracking and remote branches Three columns. Your computer, local branches: main and docs/12, the labels you commit on. Your computer, remote-tracking branches: origin/main and origin/docs/12, bookmarks of the remote updated by fetch, pull and push. The remote on GitLab or GitHub: main and docs/12, the shared branches. Arrows: git push -u origin docs/12 creates the remote branch and links the local branch to it; fetch updates the bookmarks; pull updates bookmarks and the local branch. YOUR COMPUTER (.git) GITLAB / GITHUB Local branches you commit here main docs/12 Remote-tracking bookmarks of the remote origin/main origin/docs/12 Remote branches what the team shares main docs/12 tracks tracks fetch / push fetch / push git push -u origin docs/12 creates the remote branch, the bookmark, and the "tracks" link in one go. git status compares the local branch with its bookmark: "ahead 1" / "behind 2" / "up to date" — as of the last fetch.
Local branches, their remote-tracking bookmarks, and the remote branches they follow.

The link shows up in three places. In the short status:

Terminal
$ git status -sb
## docs/12-windows-install-steps...origin/docs/12-windows-install-steps

In the branch list with -vv:

Terminal
$ git branch -vv
* docs/12-windows-install-steps 510f1e0 [origin/docs/12-windows-install-steps] docs: add Windows steps to installation guide (#12)
  main                          8fa922e [origin/main] Initial import of trailguide

And in the ahead/behind line of the full git status, which is the one you read every day. Remember from lesson 2.5 that the comparison is against your local bookmark origin/…, which only fetch, pull and push update.

Updating your branch from main

Your branch started at a commit on main. Days later main has moved:

Terminal
$ git switch main
$ git pull
From https://gitlab.com/northwind-trails/trailguide
   8fa922e..1a01760  main       -> origin/main
Updating 8fa922e..1a01760
Fast-forward
 data/trails.csv | 1 +
 1 file changed, 1 insertion(+)

Now your branch is missing that commit. Two ways to fix it, and the difference is the shape of the history.

Merge main into your branch. Safe, always available, works after the branch has been pushed and shared:

Terminal
$ git switch docs/12-windows-install-steps
$ git merge main
Merge made by the 'ort' strategy.
 data/trails.csv | 1 +
 1 file changed, 1 insertion(+)
Terminal
$ git log --oneline --graph --all --decorate
*   34f6699 (HEAD -> docs/12-windows-install-steps) Merge branch 'main' into docs/12-windows-install-steps
|\  
| * 1a01760 (origin/main, origin/HEAD, main) feat: add Coast Walk trail (#29)
* | 510f1e0 (origin/docs/12-windows-install-steps) docs: add Windows steps to installation guide (#12)
|/  
* 8fa922e (tag: v1.2.0) Initial import of trailguide

The |\ and |/ marks are the merge: your branch now contains both lines of work, joined by a commit that does nothing but join them.

Rebase your branch onto main. Replays your commits on top of the newer main, so the history stays a straight line:

Terminal
$ git rebase main
Successfully rebased and updated refs/heads/docs/12-windows-install-steps.
Terminal
$ git log --oneline --graph --all --decorate
* 5f181fc (HEAD -> docs/12-windows-install-steps) docs: add Windows steps to installation guide (#12)
* 1a01760 (origin/main, origin/HEAD, main) feat: add Coast Walk trail (#29)
| * 510f1e0 (origin/docs/12-windows-install-steps) docs: add Windows steps to installation guide (#12)
|/  
* 8fa922e (tag: v1.2.0) Initial import of trailguide

Look closely: 5f181fc and 510f1e0 have the same message but different hashes. Rebase re-created your commit on the new base, and the old one is still on the remote. That is rewriting history, and it is why the next push is refused until you force it. Lesson 6.7 covers rebase properly, including that force push.

Merge main into your branch Rebase your branch onto main
History Keeps the true shape, adds a merge commit Straight line, no merge commit
Hashes Your commits keep theirs Your commits are re-created with new ones
After pushing the branch Safe, just push Needs --force-with-lease
If someone else works on the branch Safe Disruptive; do not
Conflicts Resolved once Possibly once per commit

Neither is wrong. Teams that squash on merge often prefer rebase for a tidy branch; teams that value the exact history prefer merge. Read your CONTRIBUTING file, and when in doubt, merge: it cannot surprise anyone.

How to do it

Terminal
$ git push -u origin docs/12-windows-install-steps
$ git switch main && git pull
$ git switch docs/12-windows-install-steps
$ git merge main
$ git push

Publish once, then keep the branch current whenever main moves. git merge main is the safe default.

Do and don't

Do

  • Push a new branch as soon as it has one real commit; it is a backup and it lets colleagues help.
  • Update from main at least every couple of days, and always before asking for review.
  • Prefer git merge main while learning: it never rewrites anything.

Don't

  • Don't rebase a branch that a colleague has also checked out.
  • Don't let a branch run for weeks without updating; the conflicts compound.
  • Don't force-push to "fix" a rejected push before reading lesson 6.7; the rejection may mean a colleague pushed.

Common mistakes

  • fatal: The current branch … has no upstream branch. The first push needs -u origin <branch>; Git prints the exact line to copy.
  • git status shows no ahead/behind line. The branch has no upstream yet. Push with -u.
  • Pushing a rebased branch and seeing rejected. Expected: the remote still has the old commits. --force-with-lease, and only on a branch that is yours (lesson 6.7).
  • Merging main into a branch and calling it "merging the branch". This direction brings main's work into your branch. The other direction, which puts your work into main, is lesson 6.6 and normally happens through a merge request.

Try it yourself

Goal: publish a branch, watch it fall behind, and bring it up to date.

  1. From an up-to-date main, create docs/practice-publish, add a line to docs/faq.md, commit.
  2. Publish it: git push -u origin docs/practice-publish. Read the two output lines.
  3. Make main move: git switch main, add a line to README.md, commit, push.
  4. Go back to the branch and check the shape: git log --oneline --graph --all --decorate -4.
  5. Bring main in: git merge main. Look at the graph again.

Expected result: step 2 prints * [new branch] and set up to track; after step 3 the graph forks; after step 5 a merge commit joins the two lines and your branch contains the README change.

Show solution

Terminal
$ git switch -c docs/practice-publish
$ printf '\n## Practice\n\nA line.\n' >> docs/faq.md
$ git commit -am "docs: practice publish"
$ git push -u origin docs/practice-publish
$ git switch main
$ printf '\nA line on main.\n' >> README.md
$ git commit -am "docs: move main forward"
$ git push
$ git switch docs/practice-publish
$ git merge main
Clean up when finished: git switch main, git branch -D docs/practice-publish, git push origin --delete docs/practice-publish (lesson 6.8).

Check yourself

1. git push on a new branch answers "has no upstream branch". What does that mean?
2. You ran git merge main while on your feature branch. What happened?
3. After git rebase main, your commit has a different hash than the one on the remote. Why?

Key terms

Push Tracking branch (upstream) Remote-tracking branch origin Merge main