Git svn fetch check if no commit left to merge - git-svn

I have cloned a svn project repo using git-svn. When I fetch commits, how do I check that there are no commits to be merged left for all branches from the fetch I did?

You could, for a given branch, diff between the HEAd of that branch and what you have fetched:
git diff ..remotes/git-svn
or if you just want the file names:
git diff ..remotes/git-svn --name-status
with, as an example, git-svn the name of the remote svn repo.

Related

git-svn: how to change the svn username on dcommit?

I cloned a SVN repository into a git repository using git svn clone. At that point in time, I did not have a username at that site and hence didn't use the --username option of clone. As I can now commit to the SVN repository with my new username, I would like to add that username. Without it, dcommit simply fails:
% LANG=C git svn dcommit
Committing to <THE URL> ...
RA layer request failed: Server sent unexpected return value (405 Method Not Allowed) in response to MKACTIVITY request for '/svn/!svn/act/0ceca4c5-f7b4-4432-94be-0485559a6040' at /usr/lib/git-core/git-svn line 945.
Is there a way to tell git about a new username? The git-svn manual doesn't seem to help: adding a username is only allowed on init and branch. I don't know how git works with SVN internally, but I guess there should be a way to add a username afterwards.
Note that I am using SVN over http.
You can specify the username in the dcommit command, e.g.
git svn dcommit --username=isapir
I think you can use this procedure (from the git svn manpage) to create a clone of your existing svn repository, but change the git svn init step so that it specifies a username. Your new git-svn repository will then have a username.
# Clone locally - make sure the refs/remotes/ space matches the server
mkdir project
cd project
git init
git remote add origin server:/pub/project
git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
git fetch
# Prevent fetch/pull from remote git server in the future,
# we only want to use git svn for future updates
git config --remove-section remote.origin
# Create a local branch from one of the branches just fetched
git checkout -b master FETCH_HEAD
# Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
git svn init --username my_new_name http://svn.example.com/project
# Pull the latest changes from Subversion
git svn rebase
Note that if you specify a username, you would not be able to dcommit a merge commit, not before Git 2.16.x/2.17 (Q1 2018).
That is because "git svn dcommit" did not take into account the fact that a
svn+ssh:// URL with a username# (typically used for pushing) refers
to the same SVN repository without the username# and failed when
svn.pushmergeinfo option is set.
See commit 8aaed89 (15 Sep 2017) by Jason Merrill (jwmerrill).
(Merged by Jason Merrill -- jwmerrill -- in commit 8aaed89, 17 Sep 2017)
git-svn: fix svn.pushmergeinfo handling of svn+ssh usernames.
Previously, svn dcommit of a merge with svn.pushmergeinfo set would
get error messages like
merge parent <X> for <Y> is on branch svn+ssh://gcc.gnu.org/svn/gcc/trunk,
which is not under the git-svn root svn+ssh://jason#gcc.gnu.org/svn/gcc!"
So, let's call remove_username (as we do for svn info) before comparing
rooturl to branchurl.

git rebase --onto causes conflict — why?

I'm trying a
git rebase --onto master myremote/master~21 myremote/master
to add the latest 21 commits from a remote repository on mine.
What git tells me is that there's a conflict — but how's that possible?
In my understanding it's just taking that 21 commits and applying them on top of my master. How can there be conflicts?
Thanks for help!
I'm doing that btw because somehow I messed up my git-svn repository (the remote), and there's 21 commits which I don't manage to commit to subversion. So I'm trying with a fresh git-svn clone, in which I'm adding those 21 commits.
There is conflict if:
master has commit that are not in myremote/master.
those commits include common files/changes with one the last 21 myremote/master commits.
If somehow the fresh git-svn clone has different SHA1 than the previous git-svn repo, then there is no close common ancestors, and the chances of conflicts are that much higher.
See "How to identify conflicting commits by hash during git rebase?" for illustrations of conflicts during a rebase.
One way to reset your local master to myremote/master would be to:
git checkout -b tmp myremote/master # local tmp branch from myremote/master HEAD.
git merge -s ours master # ignore completely master content
git checkout master
git merge tmp # fast-forward to tmp HEAD
If you hadn't made any changes in your local master before fetching myremote/master, this should work.

git svn fetch does not fetch a Subversion commit message modified after initial clone

I cloned a large SVN repository (nearly 8,000 commits) and it seems to be OK.
Since then, the commit messages of about 20 Subversion commit messages have been changed to correct a typo. This was done legitimately. However, git svn fetch does not pull the updated commit messages. It still displays the old outdated commit message.
Is there a way to fix this? Preferably in a clean way and without hacking my local git repository too much?
I've tried git svn fetch -r 1234 (where 1234 is a known revision number). But no luck.
from http://git-scm.com/docs/git-svn:
git svn reset
Undoes the effects of fetch back to the specified revision. This allows
you to re-fetch an SVN revision.
[...]
Follow reset with a fetch and then git
reset or git rebase to move local
branches onto the new tree.
So in your case, if revision 1234 is the first one that had its commit message changed, you would do
$ git svn reset -p 1234
$ git svn fetch
If anything is different, including the commit message, then the new commit is a totally different object, with a new SHA1, so as it says, you'll need to rebase any branches you might have onto the appropriate rewritten commit.

Why does git-svn dcommit leave duplicate commits in my git repo? Can I stop it doing that?

My typical git-svn workflow is:
git checkout -b story-xyz
git commit -a -m "work"
git commit -a -m "more work"
git checkout master
git svn fetch
git merge remotes/trunk
git checkout story-xyz
git rebase master (sometimes with -i)
git checkout master
git merge story-xyz
At this point I have my master and story-xyz branches pointing to the same commit, one or more commits ahead of remotes/trunk. Everything since remotes/trunk is in one linear history.
last svn commit [remotes/trunk] <--- work <--- more work [master, story-xyz]
I then run
git svn dcommit
I expected to see the commits between remotes/trunk and master become Subversion revisions, and end up with a single linear history with remotes/trunk, master and story-xyz all pointing to the latest revision, like so:
last svn commit <--- work <--- more work [master, story-xyz, remotes/trunk]
My Subversion revisions go in fine, but I end up with a two-branched structure. The common root of the branch is the Subversion HEAD before I committed. Both branches contain the same series of commits, in the sense that they contain the same diffs. The branch story-xyz is at the head of one branch, remotes/trunk and master at the other:
last svn commit <--- work <--- more work [master, remotes/trunk]
|
\- work <--- more work [story-xyz]
The git commits that I had before running git svn dcommit are on the lower branch (story-xyz), with my git commit messages, git user name and email, and git commit timestamps. The commits on the upper branch are new git commits. They use my Subversion username, the timestamp when I ran the dcommit, and the commit messages have the git-svn-id field appended to them.
This is all OK, and I can carry on working. The problem is that I look in gitk and see what looks like an unmerged branch story-xyz. It's pretty hard to tell the difference between a story branch that I have merged back into master, and one that I haven't. The most obvious way to spot it is the duplicate commit messages. I could delete the story-xyz branch, but that feels like I'm not using git properly and I've lost some of my history.
Am I missing something that would stop git-svn from doing this? Or is this just one of the ways that interacting with Subversion dilutes the power and freedom of git?
I don't think you're really missing anything. You might be doing some unnecessary work, though. In this case, you have two pointers to the "more work" commit, and you are asking git-svn to move one of them. The other one still stays where it is.
You don't really need the master branch. Git-svn doesn't care about what branch you are dcommiting. IIRC, it uses the first svn-remote it can find among the ancestors of the current commit.
I'll offer another version of the workflow:
git checkout -b story-xyz remotes/trunk
git commit -a -m "work"
git commit -a -m "more work"
git svn fetch
git rebase remotes/trunk (with -i, perhaps)
git svn dcommit
This should give you a tree without the extra branch. You need to be careful with fast-forward merges, though.

How do you view the status of your svn-git repo?

I understand how to initialize a git-svn repo, create a branch, do some work, merge branch, then use git svn rebase and git svn dcommit to push back to the svn repo. But between these two commands, how can you get a status of what is different between the two repos? Something like a git status that tells you that you have x number of files that have been changed.
Just do a diff between your branch and upstream.
git diff --stat git-svn/master..master
Obviously, you'll have to change the branch names to whatever's applicable for your setup.
The only real way I know is to run 'git svn dcommit -n' (or git svn dcommit --dry-run) which will usually give you output like this:
$git svn dcommit --dry-run
Committing to http://yourserver.com/trunk ...
diff-tree bc923cb54847fa340d094c3da1ebd66b8fb0e63e~1 bc923cb54847fa340d094c3da1ebd66b8fb0e63e
diff-tree a05c8be4af7f82dc4de5b4778e2b58203c75eebd~1 a05c8be4af7f82dc4de5b4778e2b58203c75eebd
And then you can 'git show bc923cb54847fa340d094c3da1ebd66b8fb0e63e' to view that diff.