开发者

Git. Checkout feature branch between merge commits

It's kind weird, but I can't fulfill a pretty common operation with git. Basically what I want is to checkout a feature branch, not using it's head but using SHA id. This SHA points between merges from master branch.

The problem is that all I get is just master branch without a commits from feature branch. Currently I'm trying to fix a regression introduced earlier in master branch.

Just to be more descriptive, I crafted a small bash script to recreate a problem repository:

#!/bin/bash

rm -rf ./.git
git init

echo "test1" > test1.txt
git add test1.txt
git commit -m "test1" -a

git checkout -b patches master

echo "test2" > test2.txt
git add 开发者_如何学Pythontest2.txt
git commit -m "test2" -a

git checkout master

echo "test3" > test3.txt
git add test3.txt
git commit -m "test3" -a

echo "test4" > test4.txt
git add test4.txt
git commit -m "test4" -a

echo "test5" > test5.txt
git add test5.txt
git commit -m "test5" -a

git checkout patches
git merge master    

#Now how to get a branch having all commits from patches + test3.txt + test4.txt - test5.txt ???

Basically all I want is just to checkout branch "patches" with files 1-4, but not including test5.txt.

Doing: git checkout [sha_where_test4.txt_entered]

... just gives a branch with test1,test3,test4, but excluding test2.txt

More complex example:

#!/bin/bash

rm -rf ./.git
git init

echo "test1" > test1.txt
git add test1.txt
git commit -m "test1" -a

git checkout -b patches master

echo "test2" > test2.txt
git add test2.txt
git commit -m "test2" -a

git checkout master

echo "test3" > test3.txt
git add test3.txt
git commit -m "test3" -a

echo "test4" > test4.txt
git add test4.txt
git commit -m "test4" -a

echo "test5" > test5.txt
git add test5.txt
git commit -m "test5" -a

git checkout patches
git merge master

echo "test6" > test6.txt
git add test6.txt
git commit -m "test6" -a

#Now how to get a branch having all commits from patches + test3.txt + test4.txt - test5.txt ???
git log --topo-order | cat

# Now I need something to help me going back to history 
# without manually calculating that patches~2 sha's
git checkout -b patches.tmp master~1
git merge patches~2

Thanks.


Regarding your first example, you need to replay test3 and 4 on top of test2: this is a classic case of rebase --onto:

Start from:

alt text http://img169.imageshack.us/img169/2255/gitr1.png

Mark the current patches emplacement, and move the patches branch where you would like to end (test4):

C:\Prog\Git\tests\rep\main>git checkout patches
Switched to branch 'patches'

C:\Prog\Git\tests\rep\main>git checkout -b tmp
Switched to a new branch 'tmp'

C:\Prog\Git\tests\rep\main>git checkout patches
Switched to branch 'patches'

C:\Prog\Git\tests\rep\main>git reset --hard master~1
HEAD is now at 8448d0f test4

That gives you:

alt text http://img169.imageshack.us/img169/4826/gitr2.png

And just rebase onto what you want the correct sequence of commits:

C:\Prog\Git\tests\rep\main>git checkout tmp
Switched to branch 'tmp'

C:\Prog\Git\tests\rep\main>git rebase --onto tmp tmp~1 patches
First, rewinding head to replay your work on top of it...
Applying: test3
Applying: test4

Which gives:

alt text http://img52.imageshack.us/img52/372/gitr3.png

That only works for linear set of commits to be moved around.


There is no such point. You have two parallel paths of development here, one containing the files test1 and test2, the other containing files test1, test3, test4 and test5. You can create such a point with a merge, though.

Check out the SHA1 for the commit that adds test4, and merge with the commit that adds test2. For example, after running your script my repository looks like this:

*   b054987 (HEAD, patches) Merge branch 'master' into patches
|\  
* | 5ae790f test2
| * f2a3dac (master) test5
| * 70e8cd2 test4
| * c4102ed test3
|/  
* d448eaa test1

On this, run:

% git checkout 70e8c
% git merge 5ae79

The result is a HEAD which contains files 1-4:

*   bcc8f7a (HEAD) Merge commit '5ae79' into HEAD
|\  
| | *   b054987 (patches) Merge branch 'master' into patches
| | |\  
| |/ /  
| * | 5ae790f test2
| | * f2a3dac (master) test5
| |/  
|/|   
* | 70e8cd2 test4
* | c4102ed test3
|/  
* d448eaa test1

% ls
test1.txt   test2.txt   test3.txt   test4.txt

You can now create a branch from this point of you like.


A git merge operation doesn't go back and change history, rather it creates a new commit pointing to the two histories that it came from. So, in pictures, what you have is something like this:

  2-----------\
 /             \
1---3---4---5---M (HEAD)

When you rewind history to go back to revision 4, you get files 1, 3, and 4 but not 2.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜