4

Simplyfiing I have a created a git branch structure like this:

enter image description here

Generated from:

git init
echo "Hello World" > file1.txt
git add file1.txt
git commit -m "Hello world"
git checkout -b A
echo "This is from A branch" > file2.txt
git add file2.txt
git commit -m "from A branch"
git checkout -b B
echo "This is from B branch" >> file2.txt
git commit -a -m "from B branch"

Now I clone this structure and synchronize master, A and B branches:

git clone /path-to-source/
git checkout -b master remotes/origin/master
git checkout -b A remotes/origin/A

and the cloned repository reflects the source hierarchy:

enter image description here

Now I return to source folder and add something to master and rebase A and B:

cd /path-to-source/
git checkout master
echo "more files" > file3.txt
git add file3.txt
git commit -m "Improved master"
git checkout A
git rebase master
git checkout B
git rebase A

enter image description here

The problem comes when I return to the cloned repository and try to keep this structure. If I just pull the master branch, I get this:

enter image description here

I can go to every branch and update:

git checkout A
git pull

but I get branch trees like this:

enter image description here

The question is, how to keep a clean clone of the repository? It is, I want to obtain this (manipulated graphic) in the cloned repository:

enter image description here

Bonus: If possible, I would like to find a way to keep also commits in the A or B branches like this:

enter image description here

generated from these commands in the source repository:

git checkout A
echo "something" > other.txt
git add other.txt
git commit -m "Other A commit"
git checkout B
git rebase A

NOTE 1: If that helps, cloned repository NEVER commits NOTE 2: You can assume that there is only 1 user commiting to source repository

Ivan
  • 14,692
  • 17
  • 59
  • 96
  • Not 100% sure, but pull should work on non-checked-out branches if they're set up as tracking the remote branches (read the manpage of git branch or git checkout to find more about tracking branches) – Nevik Rehnel Jan 26 '13 at 20:23
  • May be, but I need to do it in already checked out branches (the branch hierarchy is important in my project) – Ivan Jan 26 '13 at 20:40
  • 3
    As a general note: Never rebase commits once they have been published. – poke Jan 26 '13 at 20:42

1 Answers1

5

Rebasing means changing the SHA1, so your branch A in the clone is no longer valid.

You can follow "How do I recover/resynchronise after someone pushes a rebase or a reset to a published branch?" to restore the cloned branch A (inspired from the "RECOVERING FROM UPSTREAM REBASE" section).

But if:

  • those rebases are a frequent occurrence,
  • you don't have any new commit on the clone for branch A and branch B

You might want to simply reset those branches (on the clone) based on their origin/A and origin/B: you reset branch A HEAD to origin/A.

git branch -f origin/A
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Why "if those rebases are a frequent occurrence"? Performing issues may be? Anyway commits in the A branch are rare, but occour and the idea is to automatize all this in a shell script. Reading your reference.. thanks – Ivan Jan 26 '13 at 20:44
  • 1
    @Ivan no performance, just that the way to recover is a bit cumbersome, and useful only if you did some commits in the branch on the clone, that you need to replay on top of `origin/A` once you are fetching the new `A` history (because `A` was rebased in the upstream repo). But, if you didn't do anything on `A` in the clone, then the solution is straightforward: simply reset your `A` to `origin/A`. – VonC Jan 26 '13 at 21:00
  • 1
    @Ivan and considering your notes, the `git branch -f A origin/A` could be your very simple automation right there. – VonC Jan 26 '13 at 21:03
  • Perfect, it works. But just a question: why not `git checkout A` + `git rebase origin/A`? – Ivan Jan 26 '13 at 21:10
  • 1
    @Ivan Because `A` (in the clone) contains the same commits than `origin/A` (except with different SHA1), and the rebase would simply ignore those identical commits when replaying `A` on top of `origin/A`. The end result would be the same as directly resetting `A` HEAD to `origin/A`. – VonC Jan 26 '13 at 21:35