Determining update/merge/current state of a workspace

2014-02-02 Thread Stephen Leake
I'm working on the DVC Emacs front-end for git
(http://www.emacswiki.org/emacs/DistributedVersionControl), adding
features similar to the ones I added for monotone
(http://www.monotone.ca). I'm used to monotone and new to git, so this
may seem like an odd workflow.

I always do 'fetch' and 'merge' separately, never 'pull'. So after a
'fetch', the DVC Emacs front end must determine what needs to happen
next. I think there are three cases:

1) 'fetch' did not retrieve any revisions from remote; the last local
   commit is the head of the branch.

The workspace is up to date (it may need to be comitted).

2) 'fetch' retrieved revisions, and there were no local commits since
   the previous fetch.

The last fetch is the head of the branch; if not equal to HEAD, the
workspace needs to be updated (via 'merge').

3) fetch retrieved revisions, and there were local commits since
   the previous fetch.

   There are two heads for the branch (the two described above), they
   need to be merged, then the workspace updated.

I'm not sure how 'git fetch' handles case 3); I have not tested that
case yet.

The question I have is:

What git queries can I run to determine which of the three states the
current workspace is in?

'rev-parse HEAD' gives the last workspace commit.

'rev-parse refs/remotes/remote/branch' gives the head of the branch
in the remote repository as of the most recent fetch.

But to distinguish among the cases, I need to determine if one of these
two revs is a child of the other or not. I don't see a git query to
determine that directly.

I could try parsing a 'log' output; I have not investigated that.

This is easy in monotone; there is a command 'mtn heads' that gives this
result directly (it returns either one or two revs), and another command
'mtn automate toposort' that orders revs topologically (by parent/child
relationships).

-- 
-- Stephe
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Determining update/merge/current state of a workspace

2014-02-02 Thread Jeff King
On Sun, Feb 02, 2014 at 04:15:09PM -0600, Stephen Leake wrote:

 I always do 'fetch' and 'merge' separately, never 'pull'. So after a
 'fetch', the DVC Emacs front end must determine what needs to happen
 next. I think there are three cases:

Doing the two steps separately is common in git, too. The cases you
mention are also something people commonly care about. Both git
checkout and git status will print out the relationship between the
current branch and its upstream. These are sometimes referred to as
ahead/behind messages in the manual (because they are of the form You
are N commits ahead of origin/master, etc).

 3) fetch retrieved revisions, and there were local commits since
the previous fetch.
 
There are two heads for the branch (the two described above), they
need to be merged, then the workspace updated.
 
 I'm not sure how 'git fetch' handles case 3); I have not tested that
 case yet.

Git's fetch does not have to care about this case. It is responsible
only for updating the ref that keeps track of the remote side (e.g.,
refs/remotes/origin/master). Unlike in some other DVCSs, there is no
global concept of a branch in git. The ref refs/heads/master refers
to your local branch named master, and the ref refs/remotes/origin/master
refers to some remote's branch with the same name. You can reconcile
them whenever and however you like, and do not have to do so immediately
(or at all).

 The question I have is:
 
 What git queries can I run to determine which of the three states the
 current workspace is in?

If you want to know the relationship between two (or more) commits, you
can use `git rev-list` to enumerate them. You can use the symmetric
difference operator (...) to walk both sides down to their merge-base.
The `--left-right` option will label them according to which side each
commit comes from. So try:

  git rev-list --left-right @{upstream}...HEAD

to see the commits, or just:

  git rev-list --left-right --count @{upstream}...HEAD

to just get the counts on each side. Note that I used @{upstream}
there instead of naming the branch specifically. The default remote
branch with which a local branch will merge can be configured, and does
not have to have the same name (or even be a remote branch).

 But to distinguish among the cases, I need to determine if one of these
 two revs is a child of the other or not. I don't see a git query to
 determine that directly.

I think what I gave above matches what you are looking for most
directly. But as you may have already guessed, you can also use rev-list
to find whether one rev is a child of the other (e.g., git rev-list
--count a..b != 0).

 I could try parsing a 'log' output; I have not investigated that.

Don't do that. As you might expect, `git log` is built on top of the
traversals done by `rev-list`. The latter is preferred as a building
block, because it is plumbing whose output is guaranteed not to change
in later git versions.

I hope that helps,

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Determining update/merge/current state of a workspace

2014-02-02 Thread David Aguilar
On Sun, Feb 02, 2014 at 04:15:09PM -0600, Stephen Leake wrote:
 I'm working on the DVC Emacs front-end for git
 (http://www.emacswiki.org/emacs/DistributedVersionControl), adding
 features similar to the ones I added for monotone
 (http://www.monotone.ca). I'm used to monotone and new to git, so this
 may seem like an odd workflow.
 
 I always do 'fetch' and 'merge' separately, never 'pull'. So after a
 'fetch', the DVC Emacs front end must determine what needs to happen
 next. I think there are three cases:
 
 1) 'fetch' did not retrieve any revisions from remote; the last local
commit is the head of the branch.
 
 The workspace is up to date (it may need to be comitted).
 
 2) 'fetch' retrieved revisions, and there were no local commits since
the previous fetch.
 
 The last fetch is the head of the branch; if not equal to HEAD, the
 workspace needs to be updated (via 'merge').
 
 3) fetch retrieved revisions, and there were local commits since
the previous fetch.
 
There are two heads for the branch (the two described above), they
need to be merged, then the workspace updated.
 
 I'm not sure how 'git fetch' handles case 3); I have not tested that
 case yet.

Fetch updates your cached origin/master ref to match the remote.
Your local master branch and worktree are left as-is.

 The question I have is:
 
 What git queries can I run to determine which of the three states the
 current workspace is in?
 
 'rev-parse HEAD' gives the last workspace commit.
 
 'rev-parse refs/remotes/remote/branch' gives the head of the branch
 in the remote repository as of the most recent fetch.
 
 But to distinguish among the cases, I need to determine if one of these
 two revs is a child of the other or not. I don't see a git query to
 determine that directly.

I think you're looking for git merge-base.

If you do `git merge-base HEAD origin/master`
and its result is equal to `git rev-parse HEAD`
then you know that master is an ancestor of origin/master
and can be trivially fast-forwarded to origin/master.

If you get a SHA-1 that is not equal then there are probably[*]
local commits that have happened on master and it should probably
be rebased (or merged).

[*] other possibilities: someone rebased your upstream, etc.


People have differing opinions on how to resolve the diverging
history. Topic branches are the gitty approach.

Another popular approach to resolving the divergence is what
git pull --rebase would have done.

(No one really likes what git pull would have done by default
 when there are local commits)

To implement the rebase workflow, do git rebase --autostash origin/master.
after fetching.  That workflow is probably the simplest for
folks who eschew branching or are expats from other vcs.

If you're writing a tool you might want to check whether
the branch has an upstream configured via `git config branch.$name.remote`
and `git config branch.$name.merge` as well.


 I could try parsing a 'log' output; I have not investigated that.
 This is easy in monotone; there is a command 'mtn heads' that gives this
 result directly (it returns either one or two revs), and another command
 'mtn automate toposort' that orders revs topologically (by parent/child
 relationships).

`git log` can also tell you whether you have commits that they don't..

What does origin/master have that I don't?

git log HEAD..origin/master

What do I have that origin/master does not?

git log origin/master..HEAD

The git log output is easily controlled, though for these questions
the mere presence/absense of output tells you what you need to know.

cheers,
-- 
David
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Determining update/merge/current state of a workspace

2014-02-02 Thread brian m. carlson
On Sun, Feb 02, 2014 at 03:04:59PM -0800, David Aguilar wrote:
 I think you're looking for git merge-base.
 
 If you do `git merge-base HEAD origin/master`
 and its result is equal to `git rev-parse HEAD`
 then you know that master is an ancestor of origin/master
 and can be trivially fast-forwarded to origin/master.

In newer versions of git (1.8.0+), you can use git merge-base
--is-ancestor for this instead.  The commit message for 5907cda implies
that it is more efficient than the old way.

-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187


signature.asc
Description: Digital signature