* [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
@ 2015-11-11 2:11 Michael Rappazzo
2015-11-11 2:11 ` [PATCH 1/5] ff-refs: builtin cmd to check and fast forward local refs to their upstream Michael Rappazzo
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
This patch series is built on (based on) 'next' because it relies on
worktree.c
`ff-refs` will update local branches which can be fast-forwarded to their
upstream tracking branch. Any branch which has diverged from the upstream
will be left untouched by this command. Additionally, there are options
for '--dry-run' and to '--skip-worktrees'.
There are two primary update mechanisms for fast-forwarding a branch.
- For a checked out branch, emulate `git-merge --ff-only`
- For a non-checked out branch, emulate `git update-ref`
When run on a repo with multiple worktrees (created with git-worktree add),
git-ff-refs will take that into account when fast-forwarding. That is, it
will run in 'merge --ff-only' emulation mode when a branch is checked out
in a worktree, rather than in 'update-ref' mode.
The primary benefit of ff-refs will come for those who maintain several
local branches which track upstream remote branches that update often. The
intended usage pattern is to run `git-fetch` followed by `git-ff-refs`.
Michael Rappazzo (5):
ff-refs: builtin cmd to check and fast forward local refs to their
upstream
ff-refs: update each updatable ref
ff-refs: add --dry-run and --skip-worktree options
ff-refs: Add documentation
ff-refs: Add tests
.gitignore | 1 +
Documentation/git-ff-refs.txt | 55 +++++++++
Makefile | 1 +
builtin.h | 1 +
builtin/ff-refs.c | 272 ++++++++++++++++++++++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
t/t7900-ff-refs.sh | 164 +++++++++++++++++++++++++
8 files changed, 496 insertions(+)
create mode 100644 Documentation/git-ff-refs.txt
create mode 100644 builtin/ff-refs.c
create mode 100755 t/t7900-ff-refs.sh
--
2.6.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/5] ff-refs: builtin cmd to check and fast forward local refs to their upstream
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
@ 2015-11-11 2:11 ` Michael Rappazzo
2015-11-11 2:11 ` [PATCH 2/5] ff-refs: update each updatable ref Michael Rappazzo
` (4 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
Each local branch with an upstream remote is checked to see if it can be
fast-forwarded to its upstream. If fast-forward applies to the branch,
then this is reported to the user.
The statuses are
UP-TO-DATE - The local branch is the same or equal to the upstream
WOULD-UPDATE - The branch would be fast forwarded
REMOTE-MISSING - The branch is tracking an upstream that is not present
NON-FAST-FORWARD - The branch has diverged from the upstream
Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
.gitignore | 1 +
Makefile | 1 +
builtin.h | 1 +
builtin/ff-refs.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
6 files changed, 226 insertions(+)
create mode 100644 builtin/ff-refs.c
diff --git a/.gitignore b/.gitignore
index 1c2f832..e86a490 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,7 @@
/git-difftool--helper
/git-describe
/git-fast-export
+/git-ff-refs
/git-fast-import
/git-fetch
/git-fetch-pack
diff --git a/Makefile b/Makefile
index 43ceeb9..8e312ad 100644
--- a/Makefile
+++ b/Makefile
@@ -853,6 +853,7 @@ BUILTIN_OBJS += builtin/diff.o
BUILTIN_OBJS += builtin/fast-export.o
BUILTIN_OBJS += builtin/fetch-pack.o
BUILTIN_OBJS += builtin/fetch.o
+BUILTIN_OBJS += builtin/ff-refs.o
BUILTIN_OBJS += builtin/fmt-merge-msg.o
BUILTIN_OBJS += builtin/for-each-ref.o
BUILTIN_OBJS += builtin/fsck.o
diff --git a/builtin.h b/builtin.h
index 6b95006..5680e33 100644
--- a/builtin.h
+++ b/builtin.h
@@ -63,6 +63,7 @@ extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
extern int cmd_fast_export(int argc, const char **argv, const char *prefix);
extern int cmd_fetch(int argc, const char **argv, const char *prefix);
extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
+extern int cmd_ff_refs(int argc, const char **argv, const char *prefix);
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
diff --git a/builtin/ff-refs.c b/builtin/ff-refs.c
new file mode 100644
index 0000000..94a4649
--- /dev/null
+++ b/builtin/ff-refs.c
@@ -0,0 +1,221 @@
+#include "cache.h"
+#include "refs.h"
+#include "builtin.h"
+#include "remote.h"
+#include "run-command.h"
+#include "worktree.h"
+
+struct worktree **worktrees;
+const char *padding = ".....................................................";
+
+static const char * const builtin_ff_refs_usage[] = {
+ N_("git ff-refs [<options>]"),
+ NULL
+};
+
+enum ff_result_type {
+ UP_TO_DATE,
+ UPDATABLE,
+ REMOTE_MISSING,
+ NON_FAST_FORWARD,
+ UNABLE_TO_UPDATE
+};
+
+struct ff_ref_details {
+ struct branch *branch;
+ const char *upstream;
+ const char *shortened_upstream;
+ int names_length;
+ enum ff_result_type result_type;
+
+ struct commit *branch_commit;
+ struct commit *upstream_commit;
+ struct commit *merge_base;
+ struct worktree *wt;
+};
+
+struct ff_ref_data {
+ int max_names_length;
+
+ int detail_counter;
+ int detail_alloc;
+ struct ff_ref_details **detail_list;
+};
+
+static const char *result_type_str(enum ff_result_type result_type)
+{
+ switch (result_type) {
+ case UP_TO_DATE:
+ return _("UP-TO-DATE");
+ case UPDATABLE:
+ return _("WOULD-UPDATE");
+ case REMOTE_MISSING:
+ return _("REMOTE-MISSING");
+ case NON_FAST_FORWARD:
+ return _("NON-FAST-FORWARD");
+ default:
+ return _("UNABLE-TO-UPDATE");
+ }
+}
+
+/**
+ * return the worktree with the given refname checked out, or NULL if that
+ * ref is not checked out in any branch.
+ *
+ * This implementation assumes a small number of worktrees (since it loops
+ * through each worktree for every ref). If a repository has a large number
+ * of worktrees, then it might be beneficial to implement this as a hashmap
+ * lookup instead.
+ */
+static struct worktree *find_worktree(const char *refname)
+{
+ int i = 0;
+
+ for (i = 0; worktrees[i]; i++) {
+ if (!worktrees[i]->is_detached && !strcmp(worktrees[i]->head_ref, refname)) {
+ return worktrees[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * After all of the relevant refs have been collected, process the
+ * interesting ones
+ */
+static void process_refs(struct ff_ref_data *data)
+{
+ int i = 0;
+
+ for (i = 0; data->detail_list[i]; i++) {
+ struct ff_ref_details *details;
+ int padLen;
+
+ details = data->detail_list[i];
+ padLen = 3 + data->max_names_length - details->names_length;
+ if (padLen < 0)
+ padLen = 0;
+
+ printf(" %s -> %s%*.*s",
+ details->branch->name, details->shortened_upstream, padLen, padLen, padding);
+ printf("[%s]\n", result_type_str(details->result_type));
+ }
+}
+
+static void add_to_detail_list(struct ff_ref_data *data,
+ struct ff_ref_details *details)
+{
+ if (!data->detail_alloc) {
+ data->detail_list = xmalloc(sizeof(struct ff_ref_details *));
+ data->detail_alloc = 1;
+ } else
+ ALLOC_GROW(data->detail_list, data->detail_counter + 1, data->detail_alloc);
+
+ if (details && details->names_length > data->max_names_length)
+ data->max_names_length = details->names_length;
+
+ data->detail_list[data->detail_counter++] = details;
+}
+
+/**
+ * Look for refs which have an upstream configured. Each ref with an upstream
+ * is added to a list to later possibly make changes on. All of the necessary
+ * read-only data is gleaned here.
+ */
+static int analize_refs(const char *refname,
+ const struct object_id *oid, int flags, void *cb_data) {
+
+ struct branch *branch;
+ const char *upstream;
+ struct ff_ref_data *data = cb_data;
+
+ branch = branch_get(shorten_unambiguous_ref(refname, 0));
+ upstream = branch_get_upstream(branch, NULL);
+ if (upstream) {
+ struct ff_ref_details *details = xmalloc(sizeof(struct ff_ref_details));
+ unsigned char upstream_hash[GIT_SHA1_RAWSZ];
+
+ details->branch = branch;
+ details->upstream = upstream;
+
+ details->shortened_upstream = shorten_unambiguous_ref(upstream, 0);
+ details->branch_commit = NULL;
+ details->upstream_commit = NULL;
+ details->merge_base = NULL;
+ details->result_type = UNABLE_TO_UPDATE;
+ details->names_length = strlen(branch->name) +
+ strlen(details->shortened_upstream);
+ details->wt = find_worktree(details->branch->refname);
+
+ if (!resolve_ref_unsafe(details->upstream, RESOLVE_REF_READING,
+ upstream_hash, NULL))
+ details->result_type = REMOTE_MISSING;
+
+ else if (!hashcmp(oid->hash, upstream_hash))
+ details->result_type = UP_TO_DATE;
+ else {
+ struct commit_list *bases;
+
+ details->branch_commit = lookup_commit_reference(oid->hash);
+ details->upstream_commit = lookup_commit_reference(upstream_hash);
+ bases = get_merge_bases(details->branch_commit,
+ details->upstream_commit);
+ details->merge_base = bases->item;
+
+ if (!hashcmp(upstream_hash, details->merge_base->object.sha1))
+ details->result_type = UP_TO_DATE;
+
+ else if (!in_merge_bases(details->branch_commit, details->upstream_commit))
+ details->result_type = NON_FAST_FORWARD;
+
+ else
+ details->result_type = UPDATABLE;
+ }
+ add_to_detail_list(data, details);
+ }
+ return 0;
+}
+
+/**
+ * Free the memory allocated for all of the data
+ */
+static void free_data(struct ff_ref_data *data)
+{
+ int i = 0;
+
+ for (i = 0; data->detail_list[i]; i++)
+ free(data->detail_list[i]);
+ free(data);
+}
+
+int cmd_ff_refs(int argc, const char **argv, const char *prefix)
+{
+ int ret = 0;
+
+ struct option options[] = {
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, builtin_ff_refs_usage, 0);
+ if (argc)
+ usage_with_options(builtin_ff_refs_usage, options);
+ else {
+ struct ff_ref_data *data = NULL;
+
+ worktrees = get_worktrees();
+ data = xmalloc(sizeof(struct ff_ref_data));
+ data->detail_alloc = 0;
+ data->detail_counter = 0;
+ data->max_names_length = 0;
+
+ ret = for_each_ref(&analize_refs, data);
+ add_to_detail_list(data, NULL);
+
+ //for each detail
+ process_refs(data);
+
+ free_worktrees(worktrees);
+ free_data(data);
+ }
+ return ret;
+}
diff --git a/command-list.txt b/command-list.txt
index 2a94137..b766ea8 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -54,6 +54,7 @@ git-fast-export ancillarymanipulators
git-fast-import ancillarymanipulators
git-fetch mainporcelain remote
git-fetch-pack synchingrepositories
+git-ff-refs mainporcelain history
git-filter-branch ancillarymanipulators
git-fmt-merge-msg purehelpers
git-for-each-ref plumbinginterrogators
diff --git a/git.c b/git.c
index 6ed824c..1c75156 100644
--- a/git.c
+++ b/git.c
@@ -404,6 +404,7 @@ static struct cmd_struct commands[] = {
{ "fast-export", cmd_fast_export, RUN_SETUP },
{ "fetch", cmd_fetch, RUN_SETUP },
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
+ { "ff-refs", cmd_ff_refs, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
{ "format-patch", cmd_format_patch, RUN_SETUP },
--
2.6.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/5] ff-refs: update each updatable ref
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
2015-11-11 2:11 ` [PATCH 1/5] ff-refs: builtin cmd to check and fast forward local refs to their upstream Michael Rappazzo
@ 2015-11-11 2:11 ` Michael Rappazzo
2015-11-11 2:11 ` [PATCH 3/5] ff-refs: add --dry-run and --skip-worktree options Michael Rappazzo
` (3 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
If an updatable ref is checked out in any worktree, emulate merge
--ff-only to also update the local work tree (including executing the
post-merge hook).
If an updatable ref is not checked out in any worktree, the ref is
simply updated.
If a ref update is successful, that ref is reported as 'UPDATED'. If
it is not successful, the ref is reported as 'UNABLE-TO-UPDATE'.
Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
builtin/ff-refs.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/builtin/ff-refs.c b/builtin/ff-refs.c
index 94a4649..f14afc5 100644
--- a/builtin/ff-refs.c
+++ b/builtin/ff-refs.c
@@ -59,6 +59,43 @@ static const char *result_type_str(enum ff_result_type result_type)
}
/**
+ * Do the ref update.
+ * - If the ref is checked out in any worktree, emulate merge --ff-only to
+ * also update the local work tree (including executing the post-merge hook).
+ *
+ * - If the ref is not checked out in any worktree, update it
+ *
+ * - If any of the ref updates fails, the result_type is set to UNABLE-TO-UPDATE
+ */
+static void do_ref_update(struct ff_ref_data *data, struct ff_ref_details *details)
+{
+ const char *refname = details->branch->refname;
+
+ if (details->wt) {
+ struct strbuf path = STRBUF_INIT;
+
+ strbuf_getcwd(&path);
+ chdir(details->wt->path);
+ set_git_dir(details->wt->git_dir);
+ read_index(&the_index);
+
+ if (checkout_fast_forward(details->branch_commit->object.sha1,
+ details->upstream_commit->object.sha1, 1))
+ details->result_type = NON_FAST_FORWARD;
+ else if (update_ref("ff-refs", refname, details->upstream_commit->object.sha1,
+ details->branch_commit->object.sha1, 0, UPDATE_REFS_QUIET_ON_ERR)) {
+ details->result_type = UNABLE_TO_UPDATE;
+ run_hook_le(NULL, "post-merge", "0", NULL);
+ }
+ discard_index(&the_index);
+ chdir(path.buf);
+ strbuf_release(&path);
+ } else if (update_ref("ff-refs", refname, details->upstream_commit->object.sha1,
+ details->branch_commit->object.sha1, 0, UPDATE_REFS_QUIET_ON_ERR))
+ details->result_type = UNABLE_TO_UPDATE;
+}
+
+/**
* return the worktree with the given refname checked out, or NULL if that
* ref is not checked out in any branch.
*
@@ -98,6 +135,9 @@ static void process_refs(struct ff_ref_data *data)
printf(" %s -> %s%*.*s",
details->branch->name, details->shortened_upstream, padLen, padLen, padding);
+ if (details->result_type == UPDATABLE)
+ do_ref_update(data, details);
+
printf("[%s]\n", result_type_str(details->result_type));
}
}
--
2.6.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/5] ff-refs: add --dry-run and --skip-worktree options
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
2015-11-11 2:11 ` [PATCH 1/5] ff-refs: builtin cmd to check and fast forward local refs to their upstream Michael Rappazzo
2015-11-11 2:11 ` [PATCH 2/5] ff-refs: update each updatable ref Michael Rappazzo
@ 2015-11-11 2:11 ` Michael Rappazzo
2015-11-11 2:11 ` [PATCH 4/5] ff-refs: Add documentation Michael Rappazzo
` (2 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
'--dry-run' reports the updatable state of each ref without acutally
updating any refs. Refs which are fast-forwardable are reported as
'WOULD-UPDATE'.
'--skip-worktrees' does not update refs which are checked out in any
worktree. Branches which are fast-forwardable but checked out in a
worktree are reported as 'SKIPPED'. With `--dry-run` these are reported
'WOULD-SKIP'.
Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
builtin/ff-refs.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/builtin/ff-refs.c b/builtin/ff-refs.c
index f14afc5..ae68cfb 100644
--- a/builtin/ff-refs.c
+++ b/builtin/ff-refs.c
@@ -5,6 +5,8 @@
#include "run-command.h"
#include "worktree.h"
+int dry_run = 0;
+int no_wt = 0;
struct worktree **worktrees;
const char *padding = ".....................................................";
@@ -18,6 +20,7 @@ enum ff_result_type {
UPDATABLE,
REMOTE_MISSING,
NON_FAST_FORWARD,
+ SKIPPED,
UNABLE_TO_UPDATE
};
@@ -48,11 +51,13 @@ static const char *result_type_str(enum ff_result_type result_type)
case UP_TO_DATE:
return _("UP-TO-DATE");
case UPDATABLE:
- return _("WOULD-UPDATE");
+ return dry_run ? _("WOULD-UPDATE") : _("UPDATED");
case REMOTE_MISSING:
return _("REMOTE-MISSING");
case NON_FAST_FORWARD:
return _("NON-FAST-FORWARD");
+ case SKIPPED:
+ return dry_run ? _("WOULD-SKIP") : _("SKIPPED");
default:
return _("UNABLE-TO-UPDATE");
}
@@ -135,7 +140,7 @@ static void process_refs(struct ff_ref_data *data)
printf(" %s -> %s%*.*s",
details->branch->name, details->shortened_upstream, padLen, padLen, padding);
- if (details->result_type == UPDATABLE)
+ if (!dry_run && details->result_type == UPDATABLE)
do_ref_update(data, details);
printf("[%s]\n", result_type_str(details->result_type));
@@ -208,6 +213,9 @@ static int analize_refs(const char *refname,
else if (!in_merge_bases(details->branch_commit, details->upstream_commit))
details->result_type = NON_FAST_FORWARD;
+ else if (no_wt && details->wt)
+ details->result_type = SKIPPED;
+
else
details->result_type = UPDATABLE;
}
@@ -233,6 +241,9 @@ int cmd_ff_refs(int argc, const char **argv, const char *prefix)
int ret = 0;
struct option options[] = {
+ OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be fast-forwarded")),
+ OPT_BOOL(0, "skip-worktrees", &no_wt,
+ N_("skip refs checked out in any worktree")),
OPT_END()
};
--
2.6.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/5] ff-refs: Add documentation
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
` (2 preceding siblings ...)
2015-11-11 2:11 ` [PATCH 3/5] ff-refs: add --dry-run and --skip-worktree options Michael Rappazzo
@ 2015-11-11 2:11 ` Michael Rappazzo
2015-11-11 2:11 ` [PATCH 5/5] ff-refs: Add tests Michael Rappazzo
2015-11-11 10:41 ` [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael J Gruber
5 siblings, 0 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
Documentation/git-ff-refs.txt | 55 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 Documentation/git-ff-refs.txt
diff --git a/Documentation/git-ff-refs.txt b/Documentation/git-ff-refs.txt
new file mode 100644
index 0000000..569d1d4
--- /dev/null
+++ b/Documentation/git-ff-refs.txt
@@ -0,0 +1,55 @@
+git-ff-refs(1)
+============
+
+NAME
+----
+git-ff-refs - Fast-forward each local branch to its upstream (if possible)
+
+
+SYNOPSIS
+--------
+[verse]
+'git ff-refs' [<options>]
+
+
+DESCRIPTION
+-----------
+Update local branches to their tracked upstream if and only if the local branch
+can be fast-forwarded to the upstream ref. Local branches which have diverged
+from the upstream will not be updated.
+
+Each local branch tracking an upstream will be reported with a status based on
+whether or not it it was updated. The statuses are:
+
+ UP-TO-DATE - The local branch is the same or equal to the upstream
+ UPDATED - The branch was fast forwarded
+ WOULD-UPDATE - With `--dry-run`, the branch is fast forwardable
+ REMOTE-MISSING - The branch is tracking an upstream that is not present
+ NON-FAST-FORWARD - The branch has diverged from the upstream
+ SKIPPED - With `--skip-worktrees` the branch is fast forwardable but checked
+ out in a local worktree
+ WOULD-SKIP - With `--skip-worktrees` and `--dry-run`, the branch is fast
+ forwardable but checked out in a local worktree
+ UNABLE-TO-UPDATE - An error occurred while trying to update the branch
+
+OPTIONS
+-------
+--dry-run::
+ Report the updatable state of each branch without acutally updating anything.
+ In a dry run, fast-forwardable branches are marked 'WOULD-UPDATE' instead of
+ 'UPDATED'.
+
+--skip-worktrees::
+ Does not update branches which are checked out in any worktree. Branches
+ which are fast-forwardable that are checked out in any worktree are marked
+ 'SKIPPED'. If `--dry-run` is also set, those branches are marked 'WOULD-SKIP'.
+
+
+SEE ALSO
+--------
+linkgit:git-update-ref[1]
+linkgit:git-merge[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
--
2.6.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/5] ff-refs: Add tests
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
` (3 preceding siblings ...)
2015-11-11 2:11 ` [PATCH 4/5] ff-refs: Add documentation Michael Rappazzo
@ 2015-11-11 2:11 ` Michael Rappazzo
2015-11-11 10:41 ` [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael J Gruber
5 siblings, 0 replies; 13+ messages in thread
From: Michael Rappazzo @ 2015-11-11 2:11 UTC (permalink / raw)
To: gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine, Michael Rappazzo
Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
t/t7900-ff-refs.sh | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 164 insertions(+)
create mode 100755 t/t7900-ff-refs.sh
diff --git a/t/t7900-ff-refs.sh b/t/t7900-ff-refs.sh
new file mode 100755
index 0000000..3cfbcb8
--- /dev/null
+++ b/t/t7900-ff-refs.sh
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+# SKIPPED
+
+test_description='test ff-refs'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit init &&
+ for i in $(test_seq 1 9)
+ do
+ echo "data" >file_$i &&
+ git add file_$i &&
+ git commit -m"Commit $i" &&
+ git branch br_$i
+ done
+'
+
+test_expect_success 'UP-TO-DATE for equal branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git ff-refs >actual &&
+ grep "UP-TO-DATE" actual
+ )
+'
+
+test_expect_success 'UP-TO-DATE for ahead local branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git ff-refs >actual &&
+ echo "data" >file_new &&
+ git add file_new &&
+ git commit -m"Commit new" &&
+ grep "UP-TO-DATE" actual
+ )
+'
+
+test_expect_success 'REMOTE-MISSING by local config change' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git config --replace branch.master.merge refs/heads/nothing &&
+ git ff-refs >actual &&
+ grep "REMOTE-MISSING" actual
+ )
+'
+
+test_expect_success 'NON-FAST-FORWARD for diverged branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ echo "data" >file_new &&
+ git add file_new &&
+ git commit -m"Commit new" &&
+ git ff-refs >actual &&
+ grep "NON-FAST-FORWARD" actual
+ )
+'
+
+test_expect_success 'UPDATED for fast-forwardable branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git ff-refs >actual &&
+ grep "UPDATED" actual
+ )
+'
+
+test_expect_success 'WOULD-UPDATE for dry-run on fast-forwardable branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git ff-refs --dry-run >actual &&
+ grep "WOULD-UPDATE" actual
+ )
+'
+
+test_expect_success 'SKIPPED for skip-worktrees on fast-forwardable branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git ff-refs --skip-worktrees >actual &&
+ grep "SKIPPED" actual
+ )
+'
+
+test_expect_success 'WOULD-SKIP for dry-run, skip-worktrees on fast-forwardable branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git ff-refs --dry-run --skip-worktrees >actual &&
+ grep "WOULD-SKIP" actual
+ )
+'
+
+test_expect_success 'UPDATE for fast-forwardable, not checked-out branch' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git checkout -b other origin/br_3 &&
+ git ff-refs >actual &&
+ grep "master" actual | grep "UPDATED"
+ )
+'
+
+test_expect_success 'UPDATE for fast-forwardable, not checked-out branch using --skip-worktrees' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git checkout -b other origin/br_3 &&
+ git ff-refs --skip-worktrees >actual &&
+ grep "master" actual | grep "UPDATED"
+ )
+'
+
+test_expect_success 'UPDATE multiple' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git checkout -b other origin/br_5 &&
+ git reset --hard origin/br_3 &&
+ git ff-refs >actual &&
+ grep "master" actual | grep "UPDATED" &&
+ grep "other" actual | grep "UPDATED"
+ )
+'
+
+test_expect_success 'UPDATE one, skip worktree on another' '
+ test_when_finished "rm -rf local" &&
+ git clone . local &&
+ (
+ cd local &&
+ git reset --hard origin/br_3 &&
+ git checkout -b other origin/br_5 &&
+ git reset --hard origin/br_3 &&
+ git ff-refs --skip-worktrees >actual &&
+ grep "master" actual | grep "UPDATED" &&
+ grep "other" actual | grep "SKIPPED"
+ )
+'
+
+test_done
--
2.6.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
` (4 preceding siblings ...)
2015-11-11 2:11 ` [PATCH 5/5] ff-refs: Add tests Michael Rappazzo
@ 2015-11-11 10:41 ` Michael J Gruber
2015-11-11 12:32 ` Mike Rappazzo
5 siblings, 1 reply; 13+ messages in thread
From: Michael J Gruber @ 2015-11-11 10:41 UTC (permalink / raw)
To: Michael Rappazzo, gitster; +Cc: git, mhagger, peff, dturner, pclouds, sunshine
Michael Rappazzo venit, vidit, dixit 11.11.2015 03:11:
> This patch series is built on (based on) 'next' because it relies on
> worktree.c
>
> `ff-refs` will update local branches which can be fast-forwarded to their
> upstream tracking branch. Any branch which has diverged from the upstream
> will be left untouched by this command. Additionally, there are options
> for '--dry-run' and to '--skip-worktrees'.
>
> There are two primary update mechanisms for fast-forwarding a branch.
> - For a checked out branch, emulate `git-merge --ff-only`
> - For a non-checked out branch, emulate `git update-ref`
>
> When run on a repo with multiple worktrees (created with git-worktree add),
> git-ff-refs will take that into account when fast-forwarding. That is, it
> will run in 'merge --ff-only' emulation mode when a branch is checked out
> in a worktree, rather than in 'update-ref' mode.
>
> The primary benefit of ff-refs will come for those who maintain several
> local branches which track upstream remote branches that update often. The
> intended usage pattern is to run `git-fetch` followed by `git-ff-refs`.
I'm sorry, but I don't see why this deserves a new command. If refspec
with and without "+" are not enough then maybe "git fetch --all" or "git
remote update" should learn a new "--ff-only" option (ignoring all "+")
like merge has.
As for updating worktrees: This shouldn't be taken too lightly anyways.
But the worktree interface still has some rough edges, and I would hope
that it learns a "foreach" subcommand very much like the submodule
version. That would allow you to
git worktree foreach git merge --ff-only
with a systematic aproach that opens many other opportunities.
Michael
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-11 10:41 ` [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael J Gruber
@ 2015-11-11 12:32 ` Mike Rappazzo
[not found] ` <CANoM8SWxMeDjwy-GwVc+En8D7N8LyzzsBKtX_MbiS4Z49DjD7g@mail.gmail.com>
0 siblings, 1 reply; 13+ messages in thread
From: Mike Rappazzo @ 2015-11-11 12:32 UTC (permalink / raw)
To: Michael J Gruber
Cc: Junio C Hamano, Git List, Michael Haggerty, Jeff King,
David Turner, Nguyễn Thái Ngọc, Eric Sunshine
On Wed, Nov 11, 2015 at 5:41 AM, Michael J Gruber
<git@drmicha.warpmail.net> wrote:
> Michael Rappazzo venit, vidit, dixit 11.11.2015 03:11:
>> This patch series is built on (based on) 'next' because it relies on
>> worktree.c
>>
>> `ff-refs` will update local branches which can be fast-forwarded to their
>> upstream tracking branch. Any branch which has diverged from the upstream
>> will be left untouched by this command. Additionally, there are options
>> for '--dry-run' and to '--skip-worktrees'.
>>
>> There are two primary update mechanisms for fast-forwarding a branch.
>> - For a checked out branch, emulate `git-merge --ff-only`
>> - For a non-checked out branch, emulate `git update-ref`
>>
>> When run on a repo with multiple worktrees (created with git-worktree add),
>> git-ff-refs will take that into account when fast-forwarding. That is, it
>> will run in 'merge --ff-only' emulation mode when a branch is checked out
>> in a worktree, rather than in 'update-ref' mode.
>>
>> The primary benefit of ff-refs will come for those who maintain several
>> local branches which track upstream remote branches that update often. The
>> intended usage pattern is to run `git-fetch` followed by `git-ff-refs`.
>
> I'm sorry, but I don't see why this deserves a new command. If refspec
> with and without "+" are not enough then maybe "git fetch --all" or "git
> remote update" should learn a new "--ff-only" option (ignoring all "+")
> like merge has.
Maybe I wasn't clear in my description, or maybe I misunderstand
something. This command is about updating local refs (branches,
really), not the local copy of a remote ref. If, for example I have
local branches:
master -> origin/master
next -> origin/next
pu -> origin/pu
feature1 -> features/feature1
feature2 -> features/feature2
feature3 -> features/feature3
bug1 -> features/bugs/bug1
bug2 -> features/bugs/bug2
If I don't use multiple worktrees, I probably only have one of those
checked out at any one time. If any of the upstream branches are
updated, then when I fetch those branches will be behind. If I wanted
to make sure that the branches I am not touching are updated, I would
have to do it individually (AFAIK). And why not update my local
worktree if it is a fast-forward?. This command aims to put that
local branch update into a single command.
> git fetch --all
fetching origin...
abc1234..abc1235 next -> origin/next
abd1234..abd1235 pu -> origin/pu
fetching features...
123abcd..123abce feature1 -> features/feature1
+ 124abcd...124abce feature2 -> features/feature2
125abcd..125abce feature3 -> features/feature3
> git ff-refs
master -> origin/master.........[UP-TO-DATE]
next -> origin/next.............[UPDATED]
pu -> origin/pu.................[UPDATED]
feature1 -> features/feature1...[UPDATED]
feature2 -> features/feature2...[NON-FAST-FORWARD]
feature3 -> features/feature3...[UPDATED]
bug1 -> features/bugs/bug1......[UP-TO-DATE]
bug2 -> features/bugs/bug2......[UP-TO-DATE]
For reference, I have been using a scripted version of this command
[1]. Assuming that I change your mind on this command, I will add
this example to the help doc.
>
> As for updating worktrees: This shouldn't be taken too lightly anyways.
> But the worktree interface still has some rough edges, and I would hope
> that it learns a "foreach" subcommand very much like the submodule
> version. That would allow you to
>
> git worktree foreach git merge --ff-only
>
> with a systematic aproach that opens many other opportunities.
>
> Michael
I am aware of the current status of the worktrees command (I worked on
the 'list' command). If a user only wants to update unchecked out
branches, there is a command line option provided, '--skip-worktrees'.
The foreach command sounds like a good idea, but I don't know that it
would help here, as ff-refs is looping through all of the refs already
(ala for-each-ref). If you are proposing foreach-worktree as an
alternative, that is good for half of the command, but I would still
want to update the unchecked out refs.
_Mike
[1] https://github.com/rappazzo/dotfiles/blob/ff-refs/bin/git-ff-refs
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
[not found] ` <CANoM8SWxMeDjwy-GwVc+En8D7N8LyzzsBKtX_MbiS4Z49DjD7g@mail.gmail.com>
@ 2015-11-17 15:28 ` Michael J Gruber
2015-11-17 15:36 ` Mike Rappazzo
0 siblings, 1 reply; 13+ messages in thread
From: Michael J Gruber @ 2015-11-17 15:28 UTC (permalink / raw)
To: Mike Rappazzo; +Cc: Git Mailing List
Mike Rappazzo venit, vidit, dixit 17.11.2015 14:58:
> (This message is off list)
[cut the message part, though no big secrets there]
Hi Mike,
I don't think there's a point in discussing this off-list.
Your intentions are clearer now, yes, or else I would have asked more.
I still don't like the idea of having a new command just for the purpose
of fast-forwarding local branches from specified upstreams.
What's wrong with "git merge --ff-only" once you check them out? We have
all the gory messages when you checkout a branch or use the git prompt
or "branch -vv". And if you don't - how is forgetting to "ff-refs"
better than forgetting to "merge --ff-only"?
In short, I don't see a problem that this is solving, but maybe it's
because we use local branches differently, I dunno.
If other people were interested they should or would have come up with
comments, I think (as a general rule).
Cheers,
Michael
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-17 15:28 ` Michael J Gruber
@ 2015-11-17 15:36 ` Mike Rappazzo
2015-11-18 9:56 ` Johannes Schindelin
0 siblings, 1 reply; 13+ messages in thread
From: Mike Rappazzo @ 2015-11-17 15:36 UTC (permalink / raw)
To: Michael J Gruber; +Cc: Git Mailing List
On Tue, Nov 17, 2015 at 10:28 AM, Michael J Gruber
<git@drmicha.warpmail.net> wrote:
> Mike Rappazzo venit, vidit, dixit 17.11.2015 14:58:
>
> I still don't like the idea of having a new command just for the purpose
> of fast-forwarding local branches from specified upstreams.
>
> What's wrong with "git merge --ff-only" once you check them out? We have
> all the gory messages when you checkout a branch or use the git prompt
> or "branch -vv". And if you don't - how is forgetting to "ff-refs"
> better than forgetting to "merge --ff-only"?
>
> In short, I don't see a problem that this is solving, but maybe it's
> because we use local branches differently, I dunno.
For me I use this command more as a post-fetch:
git fetch --all --prune && git-ff-refs
I imagine that the big difference is in the number of branches that I
maintain, and perhaps in the way that I use gitk to visualize them. I
would be happy to add another option to git-fetch for --ff-refs as an
alternative if that would feel better than a full-on builtin.
>
> If other people were interested they should or would have come up with
> comments, I think (as a general rule).
>
> Cheers,
> Michael
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-17 15:36 ` Mike Rappazzo
@ 2015-11-18 9:56 ` Johannes Schindelin
2015-11-24 22:39 ` Jeff King
0 siblings, 1 reply; 13+ messages in thread
From: Johannes Schindelin @ 2015-11-18 9:56 UTC (permalink / raw)
To: Mike Rappazzo; +Cc: Michael J Gruber, Git Mailing List
Hi Mike,
On Tue, 17 Nov 2015, Mike Rappazzo wrote:
> On Tue, Nov 17, 2015 at 10:28 AM, Michael J Gruber
> <git@drmicha.warpmail.net> wrote:
> > Mike Rappazzo venit, vidit, dixit 17.11.2015 14:58:
> >
> > I still don't like the idea of having a new command just for the purpose
> > of fast-forwarding local branches from specified upstreams.
> >
> > What's wrong with "git merge --ff-only" once you check them out? We have
> > all the gory messages when you checkout a branch or use the git prompt
> > or "branch -vv". And if you don't - how is forgetting to "ff-refs"
> > better than forgetting to "merge --ff-only"?
> >
> > In short, I don't see a problem that this is solving, but maybe it's
> > because we use local branches differently, I dunno.
>
> For me I use this command more as a post-fetch:
>
> git fetch --all --prune && git-ff-refs
>
> I imagine that the big difference is in the number of branches that I
> maintain, and perhaps in the way that I use gitk to visualize them. I
> would be happy to add another option to git-fetch for --ff-refs as an
> alternative if that would feel better than a full-on builtin.
I would much prefer, say, `git fetch --all --prune
--fast-forward-tracking-branches` (with maybe `-T` as short option for
`--fast-forward-tracking-branches` and/or a shorter `--ff-tracking`) to a
new builtin.
But yeah, I can see how it is convenient when you have to work with N
tracking branches where N > 2.
Thanks,
Dscho
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-18 9:56 ` Johannes Schindelin
@ 2015-11-24 22:39 ` Jeff King
2015-12-01 0:24 ` Junio C Hamano
0 siblings, 1 reply; 13+ messages in thread
From: Jeff King @ 2015-11-24 22:39 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Mike Rappazzo, Michael J Gruber, Git Mailing List
On Wed, Nov 18, 2015 at 10:56:02AM +0100, Johannes Schindelin wrote:
> > For me I use this command more as a post-fetch:
> >
> > git fetch --all --prune && git-ff-refs
> >
> > I imagine that the big difference is in the number of branches that I
> > maintain, and perhaps in the way that I use gitk to visualize them. I
> > would be happy to add another option to git-fetch for --ff-refs as an
> > alternative if that would feel better than a full-on builtin.
>
> I would much prefer, say, `git fetch --all --prune
> --fast-forward-tracking-branches` (with maybe `-T` as short option for
> `--fast-forward-tracking-branches` and/or a shorter `--ff-tracking`) to a
> new builtin.
FWIW, that makes a lot more sense to me, as it would presumably touch
only branches which track whatever we just updated, and not other random
refs.
I have to admit that I'm a little wary of something like ff-refs meeting
all needs, though. I have custom scripts that match my workflow and tell
me when a branch could be updated. I could replace part of them with
"ff-refs --dry-run", but that is really not much code. Basically:
git for-each-ref --format='%(refname) %(upstream)' refs/heads |
while read ref upstream; do
git merge-base --is-ancestor $ref $upstream &&
echo "$ref can fast-forward"
done
-Peff
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/5] ff-refs: builtin command to fast-forward local refs
2015-11-24 22:39 ` Jeff King
@ 2015-12-01 0:24 ` Junio C Hamano
0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2015-12-01 0:24 UTC (permalink / raw)
To: Jeff King
Cc: Johannes Schindelin, Mike Rappazzo, Michael J Gruber,
Git Mailing List
Jeff King <peff@peff.net> writes:
> On Wed, Nov 18, 2015 at 10:56:02AM +0100, Johannes Schindelin wrote:
>
>> > For me I use this command more as a post-fetch:
>> >
>> > git fetch --all --prune && git-ff-refs
>> >
>> > I imagine that the big difference is in the number of branches that I
>> > maintain, and perhaps in the way that I use gitk to visualize them. I
>> > would be happy to add another option to git-fetch for --ff-refs as an
>> > alternative if that would feel better than a full-on builtin.
>>
>> I would much prefer, say, `git fetch --all --prune
>> --fast-forward-tracking-branches` (with maybe `-T` as short option for
>> `--fast-forward-tracking-branches` and/or a shorter `--ff-tracking`) to a
>> new builtin.
Hmph, I am not sure it is a good idea to allow "git fetch" affect
refs that it was not told to "fetch", but that is why you give a new
option from the command line to update refs that are not involved in
the fetch based on what was fetched, so it might be OK.
But the above is *NOT* fast-forwarding "tracking" branch. It is
doing something else: fast-forwarding the local branch that is based
on a remote-tracking branch.
They have refs/heads/master, and they call it their 'master'
branch.
You have refs/remotes/origin/master, and that is the
remote-tracking branch for their 'master'.
You may have prepared your 'master' to build on their 'master'
branch. That is not a 'tracking branch' for anything.
So --ff-tracking and the other name above need to be rethought.
> FWIW, that makes a lot more sense to me, as it would presumably touch
> only branches which track whatever we just updated, and not other random
> refs.
>
This ff-refs series breaks build for me by introducing calls to chdir()
whose return values are not checked -Werror=unused-result, by the way.
> I have to admit that I'm a little wary of something like ff-refs meeting
> all needs, though. I have custom scripts that match my workflow and tell
> me when a branch could be updated. I could replace part of them with
> "ff-refs --dry-run", but that is really not much code. Basically:
>
> git for-each-ref --format='%(refname) %(upstream)' refs/heads |
> while read ref upstream; do
> git merge-base --is-ancestor $ref $upstream &&
> echo "$ref can fast-forward"
> done
Yup. I like that one.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2015-12-01 0:24 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-11 2:11 [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael Rappazzo
2015-11-11 2:11 ` [PATCH 1/5] ff-refs: builtin cmd to check and fast forward local refs to their upstream Michael Rappazzo
2015-11-11 2:11 ` [PATCH 2/5] ff-refs: update each updatable ref Michael Rappazzo
2015-11-11 2:11 ` [PATCH 3/5] ff-refs: add --dry-run and --skip-worktree options Michael Rappazzo
2015-11-11 2:11 ` [PATCH 4/5] ff-refs: Add documentation Michael Rappazzo
2015-11-11 2:11 ` [PATCH 5/5] ff-refs: Add tests Michael Rappazzo
2015-11-11 10:41 ` [PATCH 0/5] ff-refs: builtin command to fast-forward local refs Michael J Gruber
2015-11-11 12:32 ` Mike Rappazzo
[not found] ` <CANoM8SWxMeDjwy-GwVc+En8D7N8LyzzsBKtX_MbiS4Z49DjD7g@mail.gmail.com>
2015-11-17 15:28 ` Michael J Gruber
2015-11-17 15:36 ` Mike Rappazzo
2015-11-18 9:56 ` Johannes Schindelin
2015-11-24 22:39 ` Jeff King
2015-12-01 0:24 ` Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).